Showing preview only (942K chars total). Download the full file or copy to clipboard to get everything.
Repository: etkecc/baibot
Branch: main
Commit: 20cb33bc66ed
Files: 221
Total size: 877.6 KB
Directory structure:
gitextract_wac8c_3x/
├── .dockerignore
├── .editorconfig
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── publish.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CHANGELOG.md
├── Cargo.toml
├── Dockerfile
├── Dockerfile.ci
├── LICENSE
├── README.md
├── docs/
│ ├── README.md
│ ├── access.md
│ ├── agents.md
│ ├── configuration/
│ │ ├── README.md
│ │ ├── authentication.md
│ │ ├── handlers.md
│ │ ├── image-generation.md
│ │ ├── speech-to-text.md
│ │ ├── text-generation.md
│ │ └── text-to-speech.md
│ ├── development.md
│ ├── features.md
│ ├── installation.md
│ ├── providers.md
│ ├── sample-provider-configs/
│ │ ├── anthropic.yml
│ │ ├── groq.yml
│ │ ├── localai.yml
│ │ ├── mistral.yml
│ │ ├── ollama.yml
│ │ ├── openai-compatible.yml
│ │ ├── openai.yml
│ │ ├── openrouter.yml
│ │ └── together-ai.yml
│ └── usage.md
├── etc/
│ ├── app/
│ │ └── config.yml.dist
│ ├── assets/
│ │ └── baibot.xcf
│ └── services/
│ ├── continuwuity/
│ │ ├── compose.yml
│ │ ├── config/
│ │ │ └── continuwuity.toml
│ │ └── register-user.sh
│ ├── element-web/
│ │ ├── compose.yml
│ │ └── config.json.dist
│ ├── env.dist
│ ├── localai/
│ │ └── compose.yml
│ ├── ollama/
│ │ └── compose.yml
│ └── synapse/
│ ├── compose.yml
│ └── config/
│ ├── homeserver.yaml
│ ├── synapse.127.0.0.1.nip.io.log.config
│ └── synapse.127.0.0.1.nip.io.signing.key
├── justfile
├── mise.toml
├── renovate.json
├── rust-toolchain.toml
└── src/
├── agent/
│ ├── definition.rs
│ ├── identifier.rs
│ ├── instantiation.rs
│ ├── manager.rs
│ ├── mod.rs
│ ├── provider/
│ │ ├── anthropic/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── config.rs
│ │ ├── controller.rs
│ │ ├── entity/
│ │ │ ├── agent_provider.rs
│ │ │ ├── image.rs
│ │ │ ├── mod.rs
│ │ │ ├── ping.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation/
│ │ │ │ ├── mod.rs
│ │ │ │ └── prompt_variables.rs
│ │ │ └── text_to_speech.rs
│ │ ├── groq/
│ │ │ └── mod.rs
│ │ ├── localai/
│ │ │ └── mod.rs
│ │ ├── mistral/
│ │ │ └── mod.rs
│ │ ├── mod.rs
│ │ ├── ollama/
│ │ │ └── mod.rs
│ │ ├── openai/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── openai_compat/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── openrouter/
│ │ │ └── mod.rs
│ │ └── togetherai/
│ │ └── mod.rs
│ ├── purpose.rs
│ └── utils.rs
├── bot/
│ ├── implementation.rs
│ ├── load_config.rs
│ ├── messaging.rs
│ ├── mod.rs
│ ├── reacting.rs
│ └── rooms.rs
├── controller/
│ ├── access/
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── dispatching.rs
│ │ ├── help.rs
│ │ ├── mod.rs
│ │ ├── room_local_agent_managers.rs
│ │ └── users.rs
│ ├── agent/
│ │ ├── create/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── delete/
│ │ │ └── mod.rs
│ │ ├── details/
│ │ │ └── mod.rs
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── help/
│ │ │ └── mod.rs
│ │ ├── list/
│ │ │ └── mod.rs
│ │ └── mod.rs
│ ├── cfg/
│ │ ├── common/
│ │ │ ├── generic_setting.rs
│ │ │ └── mod.rs
│ │ ├── controller_type.rs
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text/
│ │ │ │ ├── mod.rs
│ │ │ │ └── tests.rs
│ │ │ ├── tests.rs
│ │ │ ├── text_generation/
│ │ │ │ ├── mod.rs
│ │ │ │ └── tests.rs
│ │ │ └── text_to_speech/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── dispatching/
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation.rs
│ │ │ └── text_to_speech.rs
│ │ ├── global_config/
│ │ │ ├── generic_setting.rs
│ │ │ ├── handler.rs
│ │ │ └── mod.rs
│ │ ├── help.rs
│ │ ├── mod.rs
│ │ ├── room_config/
│ │ │ ├── generic_setting.rs
│ │ │ ├── handler.rs
│ │ │ └── mod.rs
│ │ └── status.rs
│ ├── chat_completion/
│ │ └── mod.rs
│ ├── controller_type.rs
│ ├── determination/
│ │ ├── mod.rs
│ │ └── tests.rs
│ ├── dispatching.rs
│ ├── help/
│ │ └── mod.rs
│ ├── image/
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── edit.rs
│ │ ├── generation.rs
│ │ ├── mod.rs
│ │ └── prompt.rs
│ ├── join/
│ │ └── mod.rs
│ ├── mod.rs
│ ├── provider/
│ │ └── mod.rs
│ ├── reaction/
│ │ ├── mod.rs
│ │ └── text_to_speech.rs
│ ├── usage/
│ │ └── mod.rs
│ └── utils/
│ ├── agent.rs
│ ├── mod.rs
│ └── text_to_speech.rs
├── conversation/
│ ├── llm/
│ │ ├── entity.rs
│ │ ├── mod.rs
│ │ ├── tests.rs
│ │ ├── tokenization.rs
│ │ └── utils.rs
│ ├── matrix/
│ │ ├── entity.rs
│ │ ├── mod.rs
│ │ ├── room_display_name_fetcher.rs
│ │ ├── room_event_fetcher.rs
│ │ └── utils/
│ │ ├── mod.rs
│ │ └── tests.rs
│ ├── matrix_llm_bridge.rs
│ └── mod.rs
├── entity/
│ ├── catch_up_marker/
│ │ ├── delayed_catch_up_marker_manager.rs
│ │ ├── entity.rs
│ │ └── mod.rs
│ ├── cfg/
│ │ ├── config.rs
│ │ ├── config_tests.rs
│ │ ├── defaults.rs
│ │ ├── env.rs
│ │ └── mod.rs
│ ├── globalconfig/
│ │ ├── entity.rs
│ │ └── mod.rs
│ ├── interaction_context.rs
│ ├── message_context.rs
│ ├── message_payload.rs
│ ├── mod.rs
│ ├── room_config_context.rs
│ ├── roomconfig/
│ │ ├── defaults.rs
│ │ ├── entity/
│ │ │ ├── handler.rs
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation.rs
│ │ │ └── text_to_speech.rs
│ │ └── mod.rs
│ └── trigger_event_info.rs
├── lib.rs
├── main.rs
├── strings/
│ ├── access.rs
│ ├── agent.rs
│ ├── cfg.rs
│ ├── error.rs
│ ├── global_config.rs
│ ├── help/
│ │ ├── access.rs
│ │ ├── agent.rs
│ │ ├── cfg.rs
│ │ ├── mod.rs
│ │ ├── provider.rs
│ │ └── usage.rs
│ ├── image_edit.rs
│ ├── image_generation.rs
│ ├── introduction.rs
│ ├── mod.rs
│ ├── provider.rs
│ ├── room_config.rs
│ ├── speech_to_text.rs
│ ├── text_to_speech.rs
│ └── usage.rs
└── utils/
├── base64.rs
├── mime.rs
├── mod.rs
├── status.rs
├── text.rs
└── text_to_speech.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
/target
/var
================================================
FILE: .editorconfig
================================================
# This file is the top-most EditorConfig file
root = true
# All Files
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
#########################
# File Extension Settings
#########################
[*.{yml,yaml,yml.dist}]
indent_style = space
indent_size = 2
[*.rs]
indent_style = space
indent_size = 4
# Markdown Files
#
# Two spaces at the end of a line in Markdown mean "new line",
# so trimming trailing whitespace for such files can cause breakage.
[*.md]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
workflow_dispatch:
pull_request:
branches: [ "main" ]
push:
branches:
- "**"
tags: [ "v*" ]
permissions:
contents: read
pull-requests: read
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test-and-clippy:
name: Unit testing and linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@1.93.0
- name: Install SQLite3
run: sudo apt-get update && sudo apt-get install -y libsqlite3-dev
- run: cargo test --all-features
- run: cargo clippy
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish
on:
workflow_run:
workflows: [ "CI" ]
types: [ "completed" ]
permissions:
contents: read
concurrency:
group: publish-${{ github.event.workflow_run.id || github.ref }}
cancel-in-progress: false
jobs:
docker-clean-metadata:
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
(
github.event.workflow_run.head_branch == 'main' ||
startsWith(github.event.workflow_run.head_branch || '', 'v')
)
runs-on: ubuntu-latest
outputs:
json: ${{ steps.meta.outputs.json }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: |
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest,enable=${{ github.event.workflow_run.head_branch == 'main' }}
type=semver,pattern={{raw}},value=${{ github.event.workflow_run.head_branch }},enable=${{ startsWith(github.event.workflow_run.head_branch || '', 'v') }}
docker-build:
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
(
github.event.workflow_run.head_branch == 'main' ||
startsWith(github.event.workflow_run.head_branch || '', 'v')
)
permissions:
contents: read
packages: write
attestations: write
id-token: write
strategy:
matrix:
include:
- os: self-hosted
arch: amd64
- os: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- name: Log in to the GitHub Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
tags: |
type=raw,value=latest,enable=${{ github.event.workflow_run.head_branch == 'main' }}
type=semver,pattern={{raw}},value=${{ github.event.workflow_run.head_branch }},enable=${{ startsWith(github.event.workflow_run.head_branch || '', 'v') }}
flavor: |
latest=auto
suffix=-${{ matrix.arch }},onlatest=true
images: |
ghcr.io/${{ github.repository }}
- name: Build and push Docker images
uses: docker/build-push-action@v7
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-manifest:
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
(
github.event.workflow_run.head_branch == 'main' ||
startsWith(github.event.workflow_run.head_branch || '', 'v')
)
permissions:
contents: read
packages: write
needs:
- docker-build
- docker-clean-metadata
runs-on: ubuntu-latest
strategy:
matrix:
image: ${{ fromJson(needs.docker-clean-metadata.outputs.json).tags }}
steps:
- name: Log in to the GitHub Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest
run: |
docker buildx imagetools create -t ${{ matrix.image }} ${{ matrix.image }}-amd64 ${{ matrix.image }}-arm64
================================================
FILE: .gitignore
================================================
/target
/var
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
# Fast built-in hooks (Rust-native, no dependencies)
- repo: builtin
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-merge-conflict
- id: check-added-large-files
args: ['--maxkb=1024']
# Local hooks that run project-specific tools
- repo: local
hooks:
- id: cargo-fmt-check
name: Cargo Format Check
entry: cargo fmt --all -- --check
language: system
files: '\.rs$'
pass_filenames: false
- id: cargo-clippy
name: Cargo Clippy
entry: cargo clippy -- -D warnings
language: system
files: '\.rs$'
pass_filenames: false
priority: 100
- id: test-unit
name: Unit Tests
entry: just test
language: system
files: '\.rs$'
pass_filenames: false
priority: 100
================================================
FILE: CHANGELOG.md
================================================
# (2026-05-21) Version 1.19.2
- (**Internal Improvement**) Update [async-openai](https://crates.io/crates/async-openai) to 0.40.0.
- (**Internal Improvement**) Dependency updates.
# (2026-05-09) Version 1.19.1
- (**Internal Improvement**) Update [async-openai](https://crates.io/crates/async-openai) to 0.38.0.
- (**Internal Improvement**) Dependency updates.
# (2026-05-09) Version 1.19.0
- (**Internal Improvement**) Update [matrix-sdk](https://crates.io/crates/matrix-sdk) from 0.16 to 0.17 and [mxlink](https://crates.io/crates/mxlink) to 1.14.0. matrix-sdk 0.17 dropped its `native-tls` feature and now uses [rustls](https://github.com/rustls/rustls) exclusively as its TLS backend.
- (**Internal Improvement**) Bump the pinned Rust toolchain from 1.93.0 to 1.95.0 (in `rust-toolchain.toml` and the Docker build images).
- (**Internal Improvement**) Dependency updates.
# (2026-04-11) Version 1.18.0
- (**Bugfix**) Fix the bot not sending a welcome message when joining a room on homeservers (like [Continuwuity](https://continuwuity.org/)) that place the join membership event in the sync response's `state` block rather than the `timeline` block, via [mxlink](https://crates.io/crates/mxlink) 1.13.1
- (**Improvement**) Update [tiktoken-rs](https://crates.io/crates/tiktoken-rs) to 0.11, adding tokenization support for newer GPT models (gpt-5.x, codex, etc.) and fixing context sizes for o1-mini/chatgpt-4o/gpt-4.5
- (**Internal Improvement**) Dependency updates
# (2026-03-25) Version 1.17.0
- (**Feature**) Add `text-generation sender-context-mode` for attaching sender metadata to conversation messages. See the [💬 Text Generation](./docs/configuration/text-generation.md#-sender-context-mode) documentation for details. Thanks to [kschwank](https://github.com/kschwank) for the contribution in [#104](https://github.com/etkecc/baibot/pull/104)!
# (2026-03-24) Version 1.16.1
- (**Bugfix**) Fix compatibility with [async-openai](https://crates.io/crates/async-openai) 0.34.0 by populating the new `phase` field required for OpenAI Responses API message inputs. baibot does not currently distinguish between assistant `commentary` and `final_answer` turns, so using `None` preserves the previous behavior while remaining compatible with the updated crate.
- (**Internal Improvement**) Dependency updates.
# (2026-03-20) Version 1.16.0
- (**Feature**) Add support for file attachments (`m.file` Matrix messages) in conversations. Files like PDFs, text documents, spreadsheets, code files, etc. are now downloaded and forwarded to the LLM alongside the conversation context, similar to how images (`m.image`) are already handled. See the [💬 Text Generation](./docs/features.md#-text-generation) documentation for details and known limitations.
- (**Improvement**) Use the [mime_guess](https://crates.io/crates/mime_guess) crate for MIME type detection from file extensions, replacing a hand-maintained mapping. This covers hundreds of file extensions out of the box.
# (2026-03-07) Version 1.15.0
- (**Feature**) Add support for authentication via access tokens (for [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service)/OIDC-enabled homeservers) as an alternative to password authentication. See [🔐 Authentication](./docs/configuration/authentication.md) for setup details. Thanks to [Taylor Southwick](https://github.com/twsouthwick) for the contribution in [#83](https://github.com/etkecc/baibot/pull/83)!
- (**Internal Improvement**) Pin the Rust toolchain to `1.93.0` in both CI and local development to avoid `matrix-sdk` build failures on newer stable toolchains.
- (**Internal Improvement**) Documentation updates.
- (**Internal Improvement**) Dependency updates.
# (2026-02-18) Version 1.14.3
- (**Internal Improvement**) Add [Renovate](https://docs.renovatebot.com/) configuration for automated dependency updates
- (**Internal Improvement**) Dependency updates
# (2026-02-18) Version 1.14.2
- (**Internal Improvement**) Dependency updates
- (**Internal Improvement**) Reorganize the development environment to support [Continuwuity](https://continuwuity.org/) as a homeserver choice (in addition to [Synapse](https://github.com/element-hq/synapse)). Continuwuity is now the default for its lighter footprint (no external database required). See [development docs](./docs/development.md) for details.
# (2026-02-10) Version 1.14.1
- (**Security**) Dependency updates to fix security vulnerabilities ([time](https://crates.io/crates/time) stack exhaustion DoS, [bytes](https://crates.io/crates/bytes) integer overflow), via [mxlink](https://crates.io/crates/mxlink) 1.12.0
- (**Internal Improvement**) Switch from deprecated [serde_yaml](https://crates.io/crates/serde_yaml) to its maintained fork [serde_yaml_ng](https://crates.io/crates/serde_yaml_ng)
- (**Internal Improvement**) Add [prek](https://github.com/nicholasgasior/prek) pre-commit hooks via [mise](https://mise.jdx.dev/) for automated code quality checks (formatting, clippy, tests)
- (**Internal Improvement**) Fix clippy warnings and formatting issues
# (2026-02-04) Version 1.14.0
- (**Feature**) The `openai` provider now uses OpenAI's [Responses API](https://platform.openai.com/docs/api-reference/responses) (instead of the older Chat Completions API), adding support for [🛠️ built-in tools](./docs/features.md#️-built-in-tools-openai-only) (`web_search` and `code_interpreter`). These tools are **disabled by default** and can be enabled via the `text_generation.tools` configuration (see the [sample configuration](https://github.com/etkecc/baibot/blob/c70387b0c38d8d0f30bba2179a2a21a3710dbeaf/docs/sample-provider-configs/openai.yml#L12-L15)). To enable tools on an existing agent, you need to [update the agent](./docs/agents.md#updating-agents) to re-create it with the `text_generation.tools` section added and enable the tools you need. Thanks to [Layla Manley](https://github.com/yeslayla) for the contribution in [#62](https://github.com/etkecc/baibot/pull/62)!
- (**Bugfix**) Fix sticker generation for newer GPT image models (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`) which don't support the previously hardcoded `256x256` size (minimum is `1024x1024`)
- (**Internal Improvement**) Dependency updates
# (2026-01-23) Version 1.13.0
- (**Improvement**) Extend auto-switching to support cheaper models (`gpt-image-1-mini`) for `gpt-image-1` and `gpt-image-1.5` when generating stickers ([e0b4a40](https://github.com/etkecc/baibot/commit/e0b4a40))
- (**Internal Improvement**) Upgrade Rust compiler (1.92.0 -> 1.93.0) ([691aeeb](https://github.com/etkecc/baibot/commit/691aeeb))
- (**Internal Improvement**) Dependency updates
# (2025-12-21) Version 1.12.0
- (**Improvement**) Upgrade [async-openai](https://crates.io/crates/async-openai) (0.31.1 -> 0.32.2) and add support for OpenAI's `gpt-image-1.5` model ([08c689a](https://github.com/etkecc/baibot/commit/08c689a), [f7bf3d7](https://github.com/etkecc/baibot/commit/f7bf3d7))
- (**Internal Improvement**) Dependency updates
# (2025-12-15) Version 1.11.0
- (**Feature**) Add support for custom avatars via file path and for keeping the already-set avatar (for those who wish to manage it by themselves via other means). See the [sample config](./etc/app/config.yml.dist) for details. ([062fbbb](https://github.com/etkecc/baibot/commit/062fbbb8ef9ad600db483a431c5c782402191023))
- (**Internal Improvement**) Dependency updates ([99bde53](https://github.com/etkecc/baibot/commit/99bde53ef648a5a9086a96778fde4a9dbc1ede58))
- (**Internal Improvement**) Documentation updates ([b3fd8e5](https://github.com/etkecc/baibot/commit/b3fd8e548f83fe46398ced4760d7e2bb7588c24d))
- (**Internal Improvement**) Upgrade Rust compiler (1.91.1 -> 1.92.0) ([22906aa](https://github.com/etkecc/baibot/commit/22906aa2d3cae51815fad2560a545eaa69c247b6))
# (2025-12-06) Version 1.10.0
- (**Internal Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.11.0 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.16.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.16.0).
# (2025-11-30) Version 1.9.0
- (**Internal Improvement**) Upgrade [async-openai](https://crates.io/crates/async-openai) from our own etkecc fork (0.28.1-patched) to the official upstream version 0.31.1. This upgrade required some code adaptations to the new module structure, etc. While tested, regressions are possible.
# (2025-11-28) Version 1.8.3
- (**Improvement**) Add support for the `BAIBOT_PERSISTENCE_SESSION_ENCRYPTION_KEY` environment variable for configuring `persistence.session_encryption_key`
- (**Improvement**) Add support for the `BAIBOT_USER_ENCRYPTION_RECOVERY_RESET_ALLOWED` environment variable for configuring `user.encryption.recovery_reset_allowed`
- (**Internal Improvement**) Dependency updates.
# (2025-11-20) Version 1.8.2
- (**Internal Improvement**) Dependency and compiler updates (Rust 1.89.0 -> 1.91.1).
# (2025-09-12) Version 1.8.1
- (**Internal Improvement**) Dependency updates.
# (2025-09-08) Version 1.8.0
- (**Internal Improvement**) Upgrade [mxlink](https://crates.io/crates/mxlink) (1.9.0 -> 1.10.0) and [matrix-sdk](https://crates.io/crates/matrix-sdk) (0.13.0 -> 0.14.0)
- (**Internal Improvement**) Upgrade [Rust](https://www.rust-lang.org/) (1.88.0 -> 1.89.0)
- (**Internal Improvement**) Upgrade Debian base for container images (12/bookworm -> 13/trixie)
# (2025-07-11) Version 1.7.6
- (**Internal Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.9.0 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.13.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.13.0), which contains fixes for some security vulnerabilities)
# (2025-06-10) Version 1.7.5
- (**Internal Improvement**) Dependency and compiler updates (Rust 1.86 -> 1.86).
# (2025-06-10) Version 1.7.4
- (**Internal Improvement**) Dependency updates.
# (2025-06-10) Version 1.7.3
- (**Internal Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.8.0 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.12.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.12.0), which contains fixes for important security vulnerabilities)
# (2025-05-11) Version 1.7.2
- (**Bugfix**) Allow `image_generation.size` configuration value for OpenAI to be `null` to allow the model to choose the size automatically and default to that
# (2025-05-11) Version 1.7.1
- (**Bugfix**) Fix lack of documentation for the new [image-editing](./docs/features.md#-image-editing) feature in the `!bai usage` command's output
# (2025-05-10) Version 1.7.0
- (**Feature**) Add vision support to the OpenAI and Anthropic providers. You can now mix text and images in your conversations - fixes [issue #5](https://github.com/etkecc/baibot/issues/5)
- (**Feature**) Add [image-editing](./docs/features.md#-image-editing) support to the OpenAI provider
- (**Improvement**) Add compatibility with OpenAI's `gpt-image-1` model - fixes [issue #40](https://github.com/etkecc/baibot/issues/40)
- (**Change**) Rework [image-creation](./docs/features.md#-image-creation) to avoid command conflicts with [image-editing](./docs/features.md#-image-editing). The image-creation command syntax is now `!bai image create <prompt>` (previously: `!bai image <prompt>`).
- (**Internal Improvement**) Dependency and compiler updates
> [!WARNING]
> Unlike other releases, this release is not published to [crates.io](https://crates.io), because it relies on multiple library forks (`async-openai` and `anthropic-rs`) sourced from Github.
# (2025-04-12) Version 1.6.0
- (**Internal Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.7.0 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.11.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.11.0))
# (2025-03-31) Version 1.5.1
- (**Internal Improvement**) Dependency updates
# (2025-02-27) Version 1.5.0
- (**Feature**) Add support for sending Speech-to-Text replies for [Transcribe-only mode](./docs/features.md#transcribe-only-mode) as regular text messages instead of notices and doing it so by default ([a1bd292752](https://github.com/etkecc/baibot/commit/a1bd292752bdd37a196788c73d00b5619e843a78)) - improvement for [issue #14](https://github.com/etkecc/baibot/issues/14). See [🦻 Speech-to-Text / 🪄 Message Type for non-threaded only-transcribed messages](./docs/configuration/speech-to-text.md#-message-type-for-non-threaded-only-transcribed-messages) for details.
- (**Feature**) Add config setting controlling if a self-introduction message is posted after joining a room ([c051da2f4a](https://github.com/etkecc/baibot/commit/c051da2f4a161de0974ebb917f7a52d01f5a001f)) - fixes [issue #32](https://github.com/etkecc/baibot/issues/32). You may wish to add a `room.post_join_self_introduction_enabled` property to your configuration. See the [sample config](./etc/app/config.yml.dist) for details. If unspecified, it defaults to `true` anyway which preserves the old behavior.
- (**Feature**) Add support for configuring `max_completion_tokens` for OpenAI ([47d8edea70](https://github.com/etkecc/baibot/commit/47d8edea705a44aa25a9bfaec4888c0f9ea8700e))
- (**Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.6.1 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.10.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.10.0))
- (**Improvement**) Populate image/audio attachment `body` with a filename, not with text to avoid incorrect rendering in Element Web, etc. ([ec1879d212](https://github.com/etkecc/baibot/commit/ec1879d212fa8d6e5f8590486e94c72abfcb75a5))
- (**Improvement**) Replace Anthropic library ([anthropic-rs](https://crates.io/crates/anthropic-rs) -> [anthropic](https://crates.io/crates/anthropic)) and switch default recommended model (`claude-3-5-sonnet-20240620` -> `claude-3-7-sonnet-20250219`) ([692d61b239](https://github.com/etkecc/baibot/commit/692d61b2398f073b81d32d4cbe8145ab3929e48c)) - fixes [issue #22](https://github.com/etkecc/baibot/issues/22)
- (**Internal Improvement**) Switch to native building of `arm64` container images to decrease total build times from ~40 minutes to ~8 minutes ([6719538530b](https://github.com/etkecc/baibot/commit/6719538530bf76b3ff2d24077b2a7fa868276b79))
- (**Internal Improvement**) Various other internal changes, including upgrading [Rust from 1.82 to 1.85 and switching to Rust edition 2024](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
# (2024-12-12) Version 1.4.1
- (**Bugfix**) Fix detection for whether the bot is the last member in a room, to avoid incorrectly leaving multi-user rooms that have had at least one person `leave` ([3c47d40781](https://github.com/etkecc/baibot/commit/3c47d407819aa9c0121117a411858238724f06da))
# (2024-11-19) Version 1.4.0
- (**Improvement**) Dependency updates. This version is based on [mxlink](https://crates.io/crates/mxlink)@1.4.0 (which is based on the newly released [matrix-sdk](https://crates.io/crates/matrix-sdk)@[0.8.0](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-0.8.0)). Once you run this version at least once and your matrix-sdk datastore gets upgraded to the new schema, **you will not be able to downgrade to older baibot versions** (based on the older matrix-sdk), unless you start with an empty datastore.
- (**Bugfix**) Add missing typing notices sending functionality while generating images ([9d166e35ba](https://github.com/etkecc/baibot/commit/9d166e35ba6fc0daaf69318870e92436f3302056))
- (**Feature**) Support for [Matrix authenticated media](https://matrix.org/docs/spec-guides/authed-media-servers/), thanks to upgrading [mxlink](https://crates.io/crates/mxlink) / [matrix-sdk](https://crates.io/crates/matrix-sdk) - fixes [issue #12](https://github.com/etkecc/baibot/issues/12)
# (2024-11-12) Version 1.3.2
Dependency updates.
# (2024-10-03) Version 1.3.1
- (**Improvement**) Improves fallback user mentions support for old clients (like Element iOS) which use the bot's display name (not its full Matrix User ID). ([d9a045a5e4](https://github.com/etkecc/baibot/commit/d9a045a5e41d2b99694f92ec9e90f47529546d89))
# (2024-10-03) Version 1.3.0
**TLDR**: you can now use OpenAI's [o1](https://platform.openai.com/docs/models/o1) models, benefit from [prompt caching](https://platform.openai.com/docs/guides/prompt-caching) and mention the bot again from old clients lacking proper [user mentions support](https://spec.matrix.org/latest/client-server-api/#user-and-room-mentions) (like Element iOS).
- (**Feature**) Introduces a new `baibot_conversation_start_time_utc` [prompt variable](./docs/configuration/text-generation.md#️-prompt-override) which is not a moving target (like the `baibot_now_utc` variable) and allows [prompt caching](https://platform.openai.com/docs/guides/prompt-caching) to work. All default/sample configs have been adjusted to make use of this new variable, but users need to adjust your existing dynamically-created agents to start using it. ([85e66406dc](https://github.com/etkecc/baibot/commit/85e66406dc6f430741c7819f420e2df4ae6e8d3b))
- (**Improvement**) Allows for the `max_response_tokens` configuration value for the [OpenAI provider](./docs/providers.md#openai) to be set to `null` to allow [o1](https://platform.openai.com/docs/models/o1) models (which do not support `max_response_tokens`) to be used. See the new o1 sample config [here](./docs/sample-provider-configs/openai-o1.yml). ([db9422740c](https://github.com/etkecc/baibot/commit/db9422740ceca32956d9628b6326b8be206344e2))
- (**Improvement**) Switches the sample configs for the [OpenAI provider](./docs/providers.md#openai) to point to the `gpt-4o` model, which since 2024-10-02 is the same as the `gpt-4o-2024-08-06` model. We previously explicitly pointed the bot to the `gpt-4o-2024-08-06` model, because it was much better (longer context window). Now that `gpt-4o` points to the same powerful model, we don't need to pin its version anymore. Existing users may wish to adjust their configuration to match. ([90fbad5b64](https://github.com/etkecc/baibot/commit/90fbad5b643cd06c23179f055a309ec6a7cba161))
- (**Bugfix**) Restores fallback user mentions support (via regular text, not via the [user mentions spec](https://spec.matrix.org/latest/client-server-api/#user-and-room-mentions)) to allow certain old clients (like Element iOS) to be able to mention the bot again. Support for this was intentionally removed recently (in [v1.2.0](#2024-10-01-version-120)), but it turned out to be too early to do this. ([b40226826f](https://github.com/etkecc/baibot/commit/b40226826fe914d0d5d265230ebc5bac8058b6f7))
# (2024-10-01) Version 1.2.0
- (**Feature**) Adds support for [on-demand involvement](./docs/features.md#on-demand-involvement) of the bot (via mention) in arbitrary threads and reply chains ([9908512968](https://github.com/etkecc/baibot/commit/990851296828168c2106eb3f4668833e9e5a7463)) - fixes [issue #15](https://github.com/etkecc/baibot/issues/15)
- (**Improvement**) Simplifies [Transcribe-only mode](./docs/features.md#transcribe-only-mode) reply format (removing `> 🦻` prefixing) to allow easier forwarding, etc. ([e6aa956423](https://github.com/etkecc/baibot/commit/e6aa95642376ee7d87932d0e66dcfedf261b188b)) - fixes [issue #14](https://github.com/etkecc/baibot/issues/14)
- (**Bugfix**) Fixes speech-to-text replies rendering incorrectly in certain clients, due to them confusing our old reply format with [fallback for rich replies](https://spec.matrix.org/v1.11/client-server-api/#fallbacks-for-rich-replies) ([e6aa956423](https://github.com/etkecc/baibot/commit/e6aa95642376ee7d87932d0e66dcfedf261b188b)) - fixes [issue #17](https://github.com/etkecc/baibot/issues/17)
# (2024-09-22) Version 1.1.1
- (**Bugfix**) Fix thread messages being lost due to lack of pagination support ([d4ddd29660](https://github.com/etkecc/baibot/commit/d4ddd29660d9f51d248119dd6032e68ab29e7d35)) - fixes [issue #13](https://github.com/etkecc/baibot/issues/13)
- (**Bugfix**) Fix Anthropic conversations getting stuck when being impatient and sending multiple consecutive messages ([8b12bdf2b3](https://github.com/etkecc/baibot/commit/8b12bdf2b3196abea0e8db33d7c50fff48341cb9)) - fixes [issue #13](https://github.com/etkecc/baibot/issues/13)
# (2024-09-21) Version 1.1.0
- (**Feature**) Adds support for [prompt variables](./docs/configuration/text-generation.md#️-prompt-override) (date/time, bot name, model id) ([2a5a2d6a4d](https://github.com/etkecc/baibot/commit/2a5a2d6a4dbf5fd7cb504ac07d4187fdc32ae395)) - fixes [issue #10](https://github.com/etkecc/baibot/issues/10)
- (**Improvement**) [Dockerfile](./Dockerfile) changes to produce ~20MB smaller container images ([354063abb7](https://github.com/etkecc/baibot/commit/354063abb79035069bd3b26c53214874e9cdd95d))
- (**Improvement**) [Dockerfile](./Dockerfile) changes to optimize local (debug) runs in a container ([c8c5e0e540](https://github.com/etkecc/baibot/commit/c8c5e0e540ab981e849452eb3ddb0378105e1fc6))
- (**Improvement**) CI changes to try and work around multi-arch image issues like [this one](https://github.com/etkecc/baibot/issues/2) ([5de7559ed6](https://github.com/etkecc/baibot/commit/5de7559ed685a41c22dfc12283681f02f4c2ee00))
# (2024-09-19) Version 1.0.6
Improvements to:
- messages sent by the bot - better onboarding flow, especially when no agents have been created yet
- documentation pages
# (2024-09-14) Version 1.0.5
Further [improves](https://github.com/etkecc/baibot/commit/3b25b92a81a05ebaf1c6dbabf675fbfbe6c9f418) the typing notification logic, so that it tolerates edge cases better.
# (2024-09-14) Version 1.0.4
[Improves](https://github.com/etkecc/baibot/commit/dd1dd78312e3db7f92b37fb3b4750fbe35de7115) the typing notification logic.
# (2024-09-13) Version 1.0.3
Contains [fixes](https://github.com/etkecc/rust-mxlink/commit/f339fc85e69aa7f614394ad303d1614cd307319c) for [some](https://github.com/etkecc/baibot/issues/1) startup failures caused by partial initialization (errors during startup).
# (2024-09-12) Version 1.0.0
Initial release. 🎉
================================================
FILE: Cargo.toml
================================================
[package]
name = "baibot"
description = "A Matrix bot for using diffent capabilities (text-generation, text-to-speech, speech-to-text, image-generation, etc.) of AI / Large Language Models"
authors = ["Slavi Pantaleev <slavi@devture.com>"]
repository = "https://github.com/etkecc/baibot"
license = "AGPL-3.0-or-later"
readme = "README.md"
keywords = ["matrix", "chat", "bot", "AI", "LLM"]
include = ["/etc/assets/baibot-torso-768.png", "/src", "/README.md", "/CHANGELOG.md", "/LICENSE"]
version = "1.19.2"
edition = "2024"
[lib]
name = "baibot"
path = "src/lib.rs"
[dependencies]
anthropic = { git = "https://github.com/etkecc/anthropic-rs.git", branch = "fix-content-block-image" }
anyhow = "1.0.*"
async-openai = { version = "0.40.0", features = ["audio", "chat-completion", "image", "responses"] }
base64 = "0.22.*"
chrono = { version = "0.4.*", default-features = false, features = ["std", "now"] }
# We'd rather not depend on this, but we cannot use the ruma-events EventContent macro without it.
matrix-sdk = { version = "0.17.0", default-features = false }
mime_guess = "2.0.*"
mxidwc = "1.0.*"
mxlink = ">=1.14.0"
etke_openai_api_rust = "0.1.*"
quick_cache = "0.6.*"
regex = "1.12.*"
serde = { version = "1.0.*", features = ["derive"], default-features = false }
serde_json = "1.0.*"
serde_yaml_ng = "0.10.*"
tempfile = "3.27.*"
tiktoken-rs = { version = "0.11.*", default-features = false }
tokio = { version = "1.52.*", features = ["rt", "rt-multi-thread", "macros"] }
tracing = "0.1.*"
tracing-subscriber = { version = "0.3.*", features = ["env-filter"] }
url = "2.5.*"
[profile.release]
strip = true
opt-level = "z"
lto = "thin"
================================================
FILE: Dockerfile
================================================
#######################################
# #
# Stage 1: building #
# #
#######################################
FROM docker.io/rust:1.95.0-slim-trixie AS build
RUN apt-get update && apt-get install -y build-essential pkg-config libssl-dev libsqlite3-dev
ENV CARGO_HOME=/cargo
ENV CARGO_TARGET_DIR=/target
WORKDIR /app
COPY . /app
ARG RELEASE_BUILD=true
RUN --mount=type=cache,target=/cargo,sharing=locked \
--mount=type=cache,target=/target,sharing=locked \
if [ "$RELEASE_BUILD" = "true" ]; then \
cargo build --release; \
else \
cargo build; \
fi
# Move it out of the mounted cache, so we can copy it in the next stage.
RUN --mount=type=cache,target=/target,sharing=locked \
if [ "$RELEASE_BUILD" = "true" ]; then \
cp /target/release/baibot /baibot; \
else \
cp /target/debug/baibot /baibot; \
fi
#######################################
# #
# Stage 2: packaging #
# #
#######################################
FROM docker.io/debian:trixie-slim
RUN apt-get update && apt-get install -y ca-certificates sqlite3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /baibot .
ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/app/baibot"]
================================================
FILE: Dockerfile.ci
================================================
#######################################
# #
# Stage 1: building #
# #
#######################################
FROM docker.io/rust:1.95.0-slim-trixie AS build
RUN apt-get update && apt-get install -y build-essential pkg-config libssl-dev libsqlite3-dev
WORKDIR /app
COPY . /app
RUN cargo build --release
#######################################
# #
# Stage 2: packaging #
# #
#######################################
FROM docker.io/debian:trixie-slim
RUN apt-get update && apt-get install -y ca-certificates sqlite3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/target/release/baibot .
ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/app/baibot"]
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
================================================
FILE: README.md
================================================
<p align="center">
<img src="./etc/assets/baibot.svg" alt="baibot logo" width="150" />
<h1 align="center">baibot</h1>
</p>
🤖 baibot is an [AI](https://en.wikipedia.org/wiki/Artificial_intelligence) ([Large Language Model](https://en.wikipedia.org/wiki/Large_language_model)) bot for [Matrix](https://matrix.org/) built by [etke.cc](https://etke.cc/) (managed Matrix servers).
The name is pronounced 'bye'-bot and is a play on [AI](https://en.wikipedia.org/wiki/Artificial_intelligence), referencing the fictional character [🇧🇬 Bai Ganyo](https://en.wikipedia.org/wiki/Bay_Ganyo).
It's designed as a more private and [featureful](#-features) alternative to [matrix-chatgpt-bot](https://github.com/matrixgpt/matrix-chatgpt-bot).
It's influenced by [chaz](https://github.com/arcuru/chaz), but does **not** use the [AIChat](https://github.com/sigoden/aichat) CLI tool and instead does everything in-process, without forking.
## 🌟 Features
- 🎨 Encourages **[provider](./docs/providers.md) choice** ([Anthropic](./docs/providers.md#anthropic), [Groq](./docs/providers.md#groq), [LocalAI](./docs/providers.md#localai), [OpenAI](./docs/providers.md#openai) and [☁️ many more](./docs/providers.md#️-providers)) as well as **[mixing & matching models](./docs/features.md#-mixing--matching-models)**:
- Supports **different use purposes** (depending on the [☁️ provider](./docs/providers.md) & model):
- [💬 text-generation](./docs/features.md#-text-generation): communicating with you via text (though certain models may "see" images as well). The [OpenAI provider](./docs/providers.md#openai) also supports [🛠️ built-in tools](./docs/features.md#️-built-in-tools-openai-only) (web search, code interpreter)
- [🦻 speech-to-text](./docs/features.md#-speech-to-text): turning your voice messages into text
- [🗣️ text-to-speech](./docs/features.md#%EF%B8%8F-text-to-speech): turning bot or users text messages into voice messages
- [🖌️ image-generation](./docs/features.md#image-generation): creating and editing images based on instructions
- 🪄 Supports [seamless voice interaction](./docs/features.md#seamless-voice-interaction) (turning user voice messages into text, answering in text, then turning that text back into voice)
- 🦻 Supports [transcribe-only mode](./docs/features.md#transcribe-only-mode) (turning user voice messages into text, without doing text-generation)
- 🗣️ Supports [text-to-speech-only mode](./docs/features.md#text-to-speech-only-mode) (turning user text messages into voice, without doing text-generation)
- 🔒 Supports [encryption](./docs/features.md#-encryption) for Matrix communication and Account-Data-stored configuration
- ♻️ Supports [context-management](./docs/configuration/text-generation.md#️-context-management) handling on some models (automatically adjusting the message history length, etc.)
- 🛠️ Allows **customizing much of the bot's [configuration](./docs/configuration/README.md)** at runtime (using commands sent via chat)
- 👥 **Actively maintained** by the team at [etke.cc](https://etke.cc/)
## 🖼️ Screenshots

You can find more screenshots on the [🌟 Features](./docs/features.md) and other [📚 Documentation](./docs/README.md) pages, as well as in the [docs/screenshots](./docs/screenshots) directory.
## 🚀 Getting Started
🗲 For a quick experiment, you can refer to the [🧑💻 development documentation](./docs/development.md) which contains information on how to build and run the bot (and its various dependency services) locally.
For a real installation, see the [🚀 Installation](./docs/installation.md) documentation which contains information on [🐋 Running in a container](./docs/installation.md#-running-in-a-container) and [🖥️️️️️ Running a binary](./docs/installation.md#-running-a-binary).
## 📚 Documentation
See the bot's [📚 documentation](./docs/README.md) for more information on how to use and configure the bot.
## 💻 Development
See the bot's [🧑💻 development documentation](./docs/development.md) for more information on how to develop on the bot.
## 📜 Changes
This bot evolves over time, sometimes with backward-incompatible changes.
When updating the bot, refer to [the changelog](CHANGELOG.md) to catch up with what's new.
## 🆘 Support
- Matrix room: [#baibot:etke.cc](https://matrix.to/#/#baibot:etke.cc)
- GitHub issues: [etkecc/baibot/issues](https://github.com/etkecc/baibot/issues)
- (for [etke.cc](https://etke.cc/) customers): etke.cc [support](https://etke.cc/contacts/)
================================================
FILE: docs/README.md
================================================
# Table of Contents
- [🔒 Access](./access.md)
- [🤖 Agents](./agents.md)
- [🛠️ Configuration](./configuration/README.md)
- [🌟 Features](./features.md)
- [🤝 Handlers](./configuration/handlers.md)
- [☁️ Providers](./providers.md)
- [📖 Usage](./usage.md)
- [🚀 Installation](./installation.md)
- [💻 Development](./development.md)
================================================
FILE: docs/access.md
================================================
## 🔒 Access
This bot employs access control to decide who can use its services and manage its configuration.
### 👋 Joining rooms
The bot automatically joins rooms only when invited by someone considered a bot [👥 user](#-users).
### 👥 Users
The bot can be used by users that match some [dynamically](./configuration/README.md#dynamic-configuration) configured [Matrix user id](https://spec.matrix.org/v1.11/#users) patterns.
Users:
- ✅ can **invite the bot to rooms**
- ✅ can **use all the bot's [features](./features.md)** ([💬 Text Generation](./features.md#-text-generation), [🦻 Speech-to-Text](./features.md#-speech-to-text), etc.) by sending room messages
- ✅ can **mention the bot** in threads and reply chains to provoke it to respond to non-user messages (see [🌟 Features / 💬 Text Generation / On-demand involvement](./features.md#on-demand-involvement))
- ✅ can **change the bot's configuration in a room** (e.g. `!bai config room ...` commands)
- ❌ cannot **change the bot's global configuration** (e.g. `!bai config global ...` commands)
- ❌ cannot **create new [🤖 Agents](./agents.md)** (neither in rooms, nor globally). See [💼 Room-local agent managers](#-room-local-agent-managers) for controlling which users can create agents.
The following commands are available:
- **Show** the currently allowed users: `!bai access users`
- **Set** the list of allowed users: `!bai access set-users SPACE_SEPARATED_PATTERNS`
Example patterns: `@*:example.com @*:another.com @someone:company.org`
### 👮♂️ Administrators
Administrators can **manage the bot's configuration and access control**.
Administrators are [👥 Users](#-users) and [💼 Room-local agent managers](#-room-local-agent-managers) implicitly, so they inherit all their permissions.
The bot can be administrated by users that match some [statically](./configuration/README.md#static-configuration) configured [Matrix user id](https://spec.matrix.org/v1.11/#users) patterns.
Administrators cannot be changed without adjusting the bot's configuration on the server.
### 💼 Room-local agent managers
Room-local agent managers are users privileged to **create their own [agents](./agents.md)** (see `!bai agent`) in rooms.
> [!WARNING]
> Letting regular users create agents which contact arbitrary network services **may be a security issue**.
The following commands are available:
- **Show** the currently allowed users: `!bai access room-local-agent-managers`
- **Set** the list of allowed users: `!bai access set-room-local-agent-managers SPACE_SEPARATED_PATTERNS`
Example patterns: `@*:example.com @*:another.com @someone:company.org`
================================================
FILE: docs/agents.md
================================================
## 🤖 Agents
An agent is an instantiation and configuration of some [☁️ provider](./providers.md).
It can support different capabilities (text-generation, speech-to-text, etc.) depending on the provider used and on the configuration of the agent.
Agents can be set as **[🤝 handlers](./configuration/handlers.md) for various purposes** (text-generation, speech-to-text, etc.) globally or in specific rooms. Send a `!bai config status` command to see the current configuration.
Agents can be **defined [statically](./configuration/README.md#static-configuration)** (in the server configuration) **or dynamically** (via commands sent to the bot).
When [creating agents](#creating-agents) dynamically, you can do it **per-room or globally**.
Globally-defined agents can be used by any authorized bot user in any room, while room-local agents can only be used in the room where they were defined.
Agent configuration (like all other configuration) is stored in the Matrix Account Data of the bot user and is **potentially encrypted** (if enabled in the configuration), so that your configuration data is safe even on untrusted homeservers.
### Listing agents
To **list** all available agents: `!bai agent list`
#### Creating agents
See a [🖼️ Screenshot of the agent creation process](./screenshots/agent-creation.webp).
To **create** a new agent, you need to specify the [provider](./providers.md) and an agent id of your choosing.
- **Create** a new agent:
- (Accessible in **this room only**) `!bai agent create-room-local PROVIDER_ID AGENT_ID`
- (Accessible in **all rooms**) `!bai agent create-global PROVIDER AGENT_ID`
- Example: `!bai agent create-room-local openai my-openai-agent`
The `AGENT_ID` is a unique identifier for the agent. It can be any string which **doesn't contain spaces and `/`**.
Depending on where the agent is defined (within a room, globally, or [statically](./configuration/README.md#static-configuration)), this id will get a prefix (e.g. `room-local/`, `global/` or `static/`). The combined id (prefix + agent id) makes the **full agent identifier** (refered to as `FULL_AGENT_IDENTIFIER` in commands below).
When creating an agent, you will be given some sample [YAML](https://en.wikipedia.org/wiki/YAML) configuration which you can use to customize the agent's behavior.
This configuration varies depending on the [☁️ provider](./providers.md) used and the capabilities of the agent. Based on the configuration keys you pass, certain features will be enabled or disabled. For example, if you skip the `image_generation` key for an [OpenAI](./providers.md#openai) agent, it won't be able to generate images (see [🖌️ Image Creation](./features.md#-image-creation), [🎨 Image Editing](./features.md#-image-editing), [🫵 Sticker Creation](./features.md#-sticker-creation)).
After making your modifications to the sample YAML, you submit it back to the bot and the new agent will be created.
**To make use of the agent**, you need to [🤝 configure it as a handler for a given purpose](./configuration/handlers.md).
### Showing agent details
To **show** full details for a given agent: `!bai agent details FULL_AGENT_IDENTIFIER`
This command requires a full agent identifier (e.g. `room-local/agent-id`).
### Deleting agents
To **delete** an agent: `!bai agent delete FULL_AGENT_IDENTIFIER`
This command requires a full agent identifier (e.g. `room-local/agent-id`).
### Updating agents
To **update** a given agent's configuration: show the agent's [details](#showing-agent-details) (current configuration), then [delete](#deleting-agents) it and finally [re-create](#creating-agents) it.
================================================
FILE: docs/configuration/README.md
================================================
## 🛠️ Configuration
The bot's behavior is controlled by a combination of [static](#static-configuration) and [dynamic](#dynamic-configuration) configuration.
### Static configuration
The bot can be configured using a [YAML](https://en.wikipedia.org/wiki/YAML) configuration file as well as [environment variables](https://en.wikipedia.org/wiki/Environment_variable).
When running the bot locally (during [🧑💻 development](../development.md)), the bot's configuration is read from the `var/app/config.yml` file.
This file is created from the template found in [etc/app/config.yml.dist](../../etc/app/config.yml.dist).
Certain keys can be left unset, in which case [📝 hardcoded defaults](../../src/entity/cfg/defaults.rs) would be used.
Some configuration keys found in the YAML configuration can be overridden by setting an environment variable (dots should be replaced with `_`). Example:
- to override `command_prefix`, set an environment variable `BAIBOT_COMMAND_PREFIX`
- to override `homeserver.server_name`, set an environment variable `BAIBOT_HOMESERVER_SERVER_NAME`
You can see the list of supported environment variables in the [🦀 src/entity/cfg/env.rs](../../src/entity/cfg/env.rs) file.
> [!WARNING]
> The static configuration contains an `initial_global_config` key, which is used to populate the bot's global configuration (stored as [dynamic configuration](#dynamic-configuration)) the first time the bot starts. Modifying this subsequently will not have any effect. After initial global configuration creation, it's expected to be managed dynamically via chat commands.
For Matrix-account authentication setup, see [🔐 Authentication](./authentication.md).
### Dynamic configuration
Besides the bot's [static configuration](#static-configuration), **the bot can also be configured dynamically at runtime (via chat messages)**.
This includes changes to [🔒 Access](../access.md), [🤖 Agents](../agents.md) and [🛠️ Room Settings](#room-settings).
#### Room Settings
Room Settings come from 3 different levels with priority in the following order (higher to lower):
- 📍 per-room (`!bai config room ..` commands)
- 🌐 globally (`!bai config global ..` commands)
- 📝 as [hardcoded defaults](../../src/entity/cfg/defaults.rs)
You can adjust the following settings per room and/or globally:
- [💬 Text Generation](text-generation.md)
- [🦻 Speech-to-Text](speech-to-text.md)
- [🗣️ Text-to-Speech](text-to-speech.md)
- [🖌️ Image Creation](image-generation.md)
- [🤝 Handlers](handlers.md)
Refer to the bot's help messages (as a response to a `!bai config` help command) for the most up-to-date information on what Room Settings can be configured.
You can **get an overview of the configuration affecting the current room** (a mix of hardcoded defaults, agent defaults, global and room-level settings) by sending a `!bai config status` command to the room.
================================================
FILE: docs/configuration/authentication.md
================================================
## 🔐 Authentication
baibot supports 2 authentication modes for the Matrix account (`user.*` keys in config).
Set **exactly one** mode. If both are set (or neither is set), startup validation fails.
### Password authentication
- Config key: `user.password`
- Environment variable: `BAIBOT_USER_PASSWORD`
### Access token authentication
- Config keys: `user.access_token` + `user.device_id`
- Environment variables: `BAIBOT_USER_ACCESS_TOKEN` + `BAIBOT_USER_DEVICE_ID`
Access-token authentication is useful for OIDC-enabled homeservers (e.g. those using [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service)).
Example token-generation command:
```sh
mas-cli manage issue-compatibility-token <username> [device_id]
```
================================================
FILE: docs/configuration/handlers.md
================================================
## 🤝 Handlers
### Introduction
You can use **different models in different rooms** (e.g. [OpenAI](../providers.md#openai) GPT-4o alongside [Llama](https://en.wikipedia.org/wiki/Llama_(language_model)) running on [Groq](../providers.md#groq), etc.)
You can also use **different models within the same room** (e.g. [💬 text-generation](#-text-generation) handled by one [agent](./agents.md), [🦻 speech-to-text](#-speech-to-text) handled by another, [🗣️ text-to-speech](#️-text-to-speech) by a 3rd, etc.)
The bot supports the following use-purposes:
- [💬 text-generation](../features.md#-text-generation): communicating with you via text (though certain models may also process images and files)
- [🦻 speech-to-text](../features.md#-speech-to-text): turning your voice messages into text
- [🗣️ text-to-speech](../features.md#️-text-to-speech): turning bot or users text messages into voice messages
- [🖌️ image-generation](../features.md#image-generation): generating images based on instructions
In a given room, each different purpose can be served by a different [provider](../providers.md) and model. This combination of provider and model configuration is called an [🤖 agent](../agents.md). Each purpose can be served by a different **handler** agent.
See a [🖼️ Screenshot of an example room configuration](./screenshots/config-status-handlers.webp).
### Configuring
Handlers can be configured [dynamically](./README.md#dynamic-configuration):
- either per-room (e.g. `!bai config room set-handler text-generation room-local/openai-gpt-4o`)
- or globally (e.g. `!bai config global set-handler text-generation global/openai-gpt-4o`)
The per-room configuration takes priority over the global configuration.
There's also a `catch-all` purpose that can be used as a fallback handler for messages that don't match any other handler.
💡 It's a good idea to globally-configure a powerful agent as a catch-all handler, so that the bot can always handle messages of any kind. You can then override individual handlers per room or globally.
================================================
FILE: docs/configuration/image-generation.md
================================================
## Image Generation
The Image Creation and Image Editing features are not configurable at this moment.
You may also wish to see:
- [🌟 Features / Image Generation / 🖌️ Image Creation](../features.md#-image-creation) for a higher-level introduction to the Image Creation features
- [🌟 Features / Image Generation / 🎨 Image Editing](../features.md#-image-editing) for a higher-level introduction to the Image Editing features
- [📖 Usage / Image Generation / 🖌️ Creating Images](../usage.md#-creating-images) section for more details on how to use the bot for Image Creation in a room
- [📖 Usage / Image Generation / 🎨 Editing images](../usage.md#-editing-images) section for more details on how to use the bot for Image Editing in a room
================================================
FILE: docs/configuration/speech-to-text.md
================================================
## 🦻 Speech-to-Text
Below are some configuration settings related to Speech-to-Text.
You may also wish to see:
- [🌟 Features / 🦻 Speech-to-Text](../features.md#-speech-to-text) for a higher-level introduction to the Speech-to-Text features
- [📖 Usage / 🦻 Speech-to-Text](../usage.md#-speech-to-text) section for more details on how to use the bot for Speech-to-Text in a room
### 🪄 Flow Type
Controls how voice messages sent by [👥 user](../access.md#-users) are handled.
The following configuration values are recognized:
- (default) `transcribe_and_generate_text`: the bot will turn [👥 user](../access.md#-users) voice messages into text and then generate text messages via [💬 Text Generation](../features.md#-text-generation). This is the default setting to allow for [Seamless voice interaction](../features.md#seamless-voice-interaction).
- `ignore`: the bot will ignore all audio messages
- `only_transcribe`: the bot will turn [👥 user](../access.md#-users) voice messages into text, but will **not** proceed with [💬 Text Generation](../features.md#-text-generation). Switching to this may be useful in some cases, as in [Transcribe-only mode](../features.md#transcribe-only-mode).
Example: `!bai config room speech-to-text set-flow-type ignore` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### 🪄 Message Type for non-threaded only-transcribed messages
Controls how the transcribed text of voice messages is sent to the chat when Flow Type = `only_transcribe`.
The following configuration values are recognized:
- (default) `text`: the transcribed text is sent as a regular message. This is more convenient if you'd like to forward the transcribed message to other rooms.
- `notice`: the transcribed text is sent as a notice message. This provides better compatibility with other bots in the room, as they are less likely to interact with messages of type notice.
Example: `!bai config room speech-to-text set-msg-type-for-non-threaded-only-transcribed-messages notice` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### 🔤 Language
Lets you specify the language of the input voice messages, to avoid using auto-detection.
Supplying the input language using a 2-letter code (e.g. `ja`) as per [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) may improve accuracy & latency.

In the above example screenshot, even without a language specified, the voice was understood correctly as [Bulgarian](https://en.wikipedia.org/wiki/Bulgarian_language), but was produced in latin, not [Cyrillic](https://en.wikipedia.org/wiki/Cyrillic_script), which is wrong.
If different [👥 user](../access.md#-users) are using different languages, do not specify a language.
💡 Certain models (like [OpenAI](../providers.md#openai)'s Whisper) may perform auto-translation if you specify a language, but you're speaking another one. You may abuse this side-effect for performing voice-to-text translation, but be aware that not all models behave this way.
Example (setting it to Japanese): `!bai config room speech-to-text set-language ja` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
================================================
FILE: docs/configuration/text-generation.md
================================================
## 💬 Text Generation
Below are some [🛠️ dynamic configuration settings](./README.md#dynamic-configuration) related to Text Generation.
You may also wish to see:
- [🌟 Features / 💬 Text Generation](../features.md#-text-generation) for a higher-level introduction to the Text Generation features
- [📖 Usage / 💬 Text Generation](../usage.md#-text-generation) section for more details on how to use the bot for Text Generation in a room
### 🗟 Prefix Requirement Type
In Direct Message rooms with the bot (1:1 rooms), it most usually makes sense for the bot to respond to **all** of your messages, as shown on this [🖼️ screenshot](../screenshots/text-generation.webp).
In group rooms (with multiple users), it may be more appropriate for the bot to only respond to messages that are **prefixed** with the command prefix (e.g. `!bai`) or which are [mentioning](https://spec.matrix.org/latest/client-server-api/#user-and-room-mentions) the bot (e.g. `@baibot`), so that other chat exchange in the room will not trigger it. Such a setup is shown on the [🖼️ On-demand involvement in the room](../screenshots/text-generation-prefix-requirement.webp) screenshot.
There are exceptions to these rules, and you can configure the bot to respond only to prefixed messages in a 1:1 room, or to respond to all messages even in a multi-user group room.
To support such use-cases, the bot has a `text-generation prefix-requirement-type` setting, which can be set to:
- (default) `no`: indicates that the bot would not require a prefix and would respond to all messages
- `command_prefix`: indicates that the bot would require that messages be prefixed with the command prefix (e.g. `!bai`) and would ignore all messages that are not prefixed
By default, the bot is **auto-configured (upon joining a new room)** to use the `no` setting in rooms that only include 2 users (you and the bot), and `command_prefix` in rooms with more than 2 users. To prevent surprises, the bot will **not** adjust this setting subsequently. You can manually adjust it via `!bai config room text-generation set-prefix-requirement-type VALUE`.
Example: `!bai config room text-generation set-prefix-requirement-type command_prefix` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
Regardless of this configuration, **the bot will also respond to messages by allowed [👥 Users](../access.md#-users) which directly [mention](https://spec.matrix.org/latest/client-server-api/#user-and-room-mentions) the bot** (e.g. `@baibot`), even if they are not prefixed. An example of this can be seen on these screenshots:
- [🖼️ On-demand involvement in a thread](../screenshots/text-generation-on-demand-thread-involvement.webp)
- [🖼️ On-demand involvement in a reply chain](../screenshots/text-generation-on-demand-reply-involvement.webp)
### 🪄 Auto Usage
Text generation is enabled by default (the `text-generation auto-usage` setting being set to `always`), but can be set to:
- (default) `always`: generate text for all messages (also see [🗟 Prefix Requirement Type](#-prefix-requirement-type))
- `never`: never generate text for messages
- `only_for_voice`: only generate text when the original user message was a voice message, later transcribed via [🦻 Speech-to-Text](../features.md#-speech-to-text)
- `only_for_text`: only generate text when original user message was a text message
Example: `!bai config room text-generation set-auto-usage only_for_voice` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### ♻️ Context Management
The bot also supports ♻️ **context management**, which automatically adjusts the message history length, etc.
This feature relies on [tokenization](https://en.wikipedia.org/wiki/Large_language_model#Tokenization) performed by the [tiktoken-rs](https://github.com/zurawiki/tiktoken-rs) library which is [poorly well-maintained](https://github.com/zurawiki/tiktoken-rs/issues/50) and only works well for [OpenAI](../providers.md#openai) models.
This setting is **disabled by default**, but can be enabled via `!bai config room text-generation set-context-management-enabled true` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings)).
### 👤 Sender Context Mode
In multi-user rooms, it may be useful for the model to know which participant sent each message in the conversation context.
To support this, the bot has a `text-generation sender-context-mode` setting, which can be set to:
- (default) `disabled`: do not attach sender metadata to messages before sending them to the model
- `matrix_user_id`: prefix text messages with the sender's Matrix user ID, for example: `[sender=@alice:example.com] Hello bot`
- `matrix_user_id_and_timestamp`: prefix text messages with the sender's Matrix user ID and the message timestamp, for example: `[sender=@alice:example.com sent_at=2026-03-23T14:30:00Z] Hello bot`
This sender metadata is attached to conversation messages before they are sent to the model provider. It applies to user and assistant text messages, but not to system prompts or non-text content.
⚠️ Enabling this sends Matrix user IDs, and optionally timestamps, to the model provider.
Example: `!bai config room text-generation set-sender-context-mode matrix_user_id` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### ⌨️ Prompt Override
You can override the [system prompt](https://huggingface.co/docs/transformers/en/tasks/prompting) configured at the [🤖 agent](../agents.md) level.
Example (multi-line is supported):
```
!bai config room text-generation set-prompt-override You're a UI/UX expert. Everything you say needs to consider design and usability.
Where appropriate, you'll mention best practices and common pitfalls.
```
A prompt override can also be set globally, see [🛠️ Room Settings](./README.md#room-settings).
Prompts may contain the following **placeholder variables** which will be replaced *every time* the bot is interacted with:
| Placeholder | Description | Example |
|---------------------------|-------------|---------|
| `{{ baibot_name }}` | Name of the bot as configured in the `user.name` field in the [Static configuration](./README.md#static-configuration) | `Baibot` |
| `{{ baibot_model_id }}` | Text-Generation model ID as configured in the [🤖 agent](../agents.md)'s configuration | `gpt-4o` |
| `{{ baibot_now_utc }}` | Current date and time in UTC (⚠️ usage may break prompt caching - see below) | `2024-09-20 (Friday), 14:26:42 UTC` |
| `{{ baibot_conversation_start_time_utc }}` | The date and time in UTC that the conversation started | `2024-09-20 (Friday), 14:26:42 UTC` |
💡 `{{ baibot_now_utc }}` changes as time goes on, which prevents [prompt caching](https://platform.openai.com/docs/guides/prompt-caching) from working. It's better to use `{{ baibot_conversation_start_time_utc }}` in prompts, as its value doesn't change yet still orients the bot to the current date/time.
Here's a prompt that combines some of the above variables:
> You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
### 🌡️ Temperature Override
You can override the [temperature](https://blogs.novita.ai/what-are-large-language-model-settings-temperature-top-p-and-max-tokens/#what-is-llm-temperature) (randomness / creativity) parameter configured at the [🤖 agent](../agents.md) level.
Example: `!bai config room text-generation set-temperature-override 3.5` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
================================================
FILE: docs/configuration/text-to-speech.md
================================================
## 🗣️ Text-to-Speech
Below are some configuration settings related to Text-to-Speech.
You may also wish to see:
- [🌟 Features / 🗣️ Text-to-Speech](../features.md#-text-generation) for a higher-level introduction to the Text-to-Speech features
- [📖 Usage / 🗣️ Text-to-Speech](../usage.md#-text-generation) section for more details on how to use the bot for Text-to-Speech in a room
### 🪄 Bot Messages Flow Type
Controls how automatic text-to-speech functions for **messages sent by the bot**.
The following configuration values are recognized:
- (default) `on_demand_for_voice`: the bot will turn its own text messages into audio (voice) messages only after an allowed [👥 user](../access.md#-users) **reacts** to a bot's message with 🗣️. To make it easier for users to react without having to hunt for this emoji, the bot will automatically add a 🗣️ reaction to its own messages which are in response to a user audio (voice) message.
- `on_demand_always`: the bot will turn its own text messages into audio (voice) messages only after an allowed [👥 user](../access.md#-users) **reacts** to a bot's message with 🗣️. To make it easier for users to react without having to hunt for this emoji, the bot will automatically add a 🗣️ reaction to **all of its own messages**.
- `only_for_voice`: the bot will turn its own text messages into audio (voice) messages only if the original user message was a voice message. This is to allow for [Seamless voice interaction](../features.md#seamless-voice-interaction), where you can speak to the bot and then hear its responses
- `never`: the bot will never turn its own text messags into audio (voice) messages
- `always`: the bot will turn all its text messages into audio (voice) messages. This also allows for [Seamless voice interaction](../features.md#seamless-voice-interaction).
Example: `!bai config room text-to-speech set-bot-msgs-flow-type never` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### 🪄 User Messages Flow Type
Controls how automatic text-to-speech functions for **messages sent by [👥 users](../access.md#-users)**.
**Only works when automatic text-generation is disabled** (see [💬 Text Generation / 🪄 Auto Usage](./text-generation.md#-auto-usage)).
The following configuration values are recognized:
- (default) `never`: the bot will never turn [👥 user](../access.md#-users) text messages into audio (voice) messages
- `on_demand`: the bot will turn [👥 user](../access.md#-users) text messages into audio (voice) messages if the text message receives a 🗣️ reaction
- `always`: the bot will turn all [👥 user](../access.md#-users) text messages into audio (voice) messages. This is to allow for [Text-to-Speech-only mode](../features.md/#text-to-speech-only-mode).
Example: `!bai config room text-to-speech set-user-msgs-flow-type always` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### 🗲 Speed override
The speed override setting lets you speed up/down speech relative to the default speed configured at the [🤖 agent](../agents.md) level (usually `1.0`).
Values typically range from `0.25` to `4.0`, but may vary depending on the selected model.
Example: `!bai config room text-to-speech set-speed-override 1.5` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
### 👫 Voice override
The voice override setting lets you change the voice being used by the text-to-speech model configured at the [🤖 agent](../agents.md) level (usually `onyx` when using [OpenAI](../providers.md#openai)).
Possible values (e.g. `onyx`) depend on the model you're using. For example, for [OpenAI](../providers.md#openai)'s Whisper model, [these voices](https://platform.openai.com/docs/guides/text-to-speech/voice-options) are available.
Example: `!bai config room text-to-speech set-voice-override nova` (this can also be set globally, see [🛠️ Room Settings](./README.md#room-settings))
================================================
FILE: docs/development.md
================================================
## 🧑💻 Development
This documentation page contains information about **running the bot locally for development purposes**.
This can also **helpful for quickly testing the bot in a containerized environment, with all dependency services included**.
For running the bot against your Matrix server, see the [🚀 Installation](./installation.md) documentation.
This bot is built in [🦀 Rust](https://www.rust-lang.org/) and uses the [mxlink](https://github.com/etkecc/rust-mxlink) library (built on top of [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk)).
For local development, we run all dependency services in [🐋 Docker](https://www.docker.com/) containers via [docker-compose](https://docs.docker.com/compose/).
### Prerequisites
- [🐋 Docker](https://www.docker.com/) and [docker-compose](https://docs.docker.com/compose/)
- [Just](https://github.com/casey/just)
- (Optional) [🦀 Rust](https://www.rust-lang.org/) - for compiling and running outside of a container
- (Optional) an API key for some Large Language Model [☁️ provider](./providers.md) (e.g. [OpenAI](./providers.md#openai)), though we recommend using [LocalAI](#localai) or [Ollama](#ollama) for local development
### Choosing a homeserver
The development environment supports two homeserver implementations:
- **[Continuwuity](https://continuwuity.org/)** (default) — lightweight, no external database required. Good for most development needs.
- **[Synapse](https://github.com/element-hq/synapse)** — the reference implementation, bundled with Postgres. Use this if you need Synapse-specific behavior.
To choose a homeserver (optional — defaults to Continuwuity if skipped):
```sh
just homeserver-init continuwuity # or: just homeserver-init synapse
```
The choice is stored in `var/homeserver` and affects all subsequent commands.
> **Note:** If you switch homeservers after initial setup, you will need to:
> - Delete `var/app/local/` and/or `var/app/container/` (app config and data)
> - Delete `var/services/element-web/` (to regenerate its config)
> - Re-run the prepare and user registration steps
### Getting started guide
Developing [locally](#running-locally) is possible, but requires a [Rust](https://www.rust-lang.org/) toolchain.
If this dependency is problematic for you, consider [🐋 running in a container](#running-in-a-container).
In any case, you will need [🐋 Docker](https://www.docker.com/) as [dependency services](../etc/services/) run there.
#### Running locally
1. (Optional) Choose a homeserver: `just homeserver-init continuwuity` (or `synapse`). Default is `continuwuity`.
2. Start the homeserver and Element Web: `just services-start`
3. (Only the first time around) Prepare initial app configuration in `var/app/local/config.yml`: `just app-local-prepare`
4. (Only the first time around) [Prepare your configuration file](#prepare-your-configuration-file)
5. (Only the first time around) Prepare initial default Matrix user accounts (`admin` and `baibot`): `just users-prepare`
6. (Optional) Start additional services depending on which [agent provider you've chosen](#choosing-an-agent-provider):
- for [LocalAI](#localai):
- Start services: `just localai-start`
- Wait a while for LocalAI to start up. It has a lot of models to download. Monitor progress using `just localai-tail-logs`
- When ready, you'll be able to reach LocalAI's web interface at http://localai.127.0.0.1.nip.io:42027/ (not that you really need it)
- for [Ollama](#ollama):
- Start services: `just ollama-start`
- (Only the first time around) Pull the model configured in `agents.static_definitions` in the configuration file: `just ollama-pull-model gemma2:2b`
7. Start the bot: `just run-locally`
8. Go to http://element.127.0.0.1.nip.io:42025/ and login with `admin` / `admin`
9. Create a new room and invite `@baibot:continuwuity.127.0.0.1.nip.io` (or `@baibot:synapse.127.0.0.1.nip.io` if using Synapse)
10. When done, stop the bot (`Ctrl` + `C`)
11. Stop the services: `just services-stop`
12. (Optional) Stop additional services:
- for [LocalAI](#localai): `just localai-stop`
- for [Ollama](#ollama): `just ollama-stop`
#### Running in a container
You can avoid having a [Rust](https://www.rust-lang.org/) toolchain installed locally and build/run this in a container.
1. (Optional) Choose a homeserver: `just homeserver-init continuwuity` (or `synapse`). Default is `continuwuity`.
2. Start the homeserver and Element Web: `just services-start`
3. (Only the first time around) Prepare initial app configuration in `var/app/container/config.yml`: `just app-container-prepare`
4. (Only the first time around) [Prepare your configuration file](#prepare-your-configuration-file)
5. (Only the first time around) Prepare initial default Matrix user accounts (`admin` and `baibot`): `just users-prepare`
6. (Optional) Start additional services depending on which [agent provider you've chosen](#choosing-an-agent-provider):
- for [LocalAI](#localai):
- Start services: `just localai-start`
- Wait a while for LocalAI to start up. It has a lot of models to download. Monitor progress using `just localai-tail-logs`
- When ready, you'll be able to reach LocalAI's web interface at http://localai.127.0.0.1.nip.io:42027/ (not that you really need it)
- for [Ollama](#ollama):
- Start services: `just ollama-start`
- (Only the first time around) Pull the model configured in `agents.static_definitions` in the configuration file: `just ollama-pull-model gemma2:2b`
7. Start the bot: `just run-in-container`
8. Go to http://element.127.0.0.1.nip.io:42025/ and login with `admin` / `admin`
9. Create a new room and invite `@baibot:continuwuity.127.0.0.1.nip.io` (or `@baibot:synapse.127.0.0.1.nip.io` if using Synapse)
10. When done, stop the bot (`Ctrl` + `C`)
11. Stop the services: `just services-stop`
12. (Optional) Stop additional services:
- for [LocalAI](#localai): `just localai-stop`
- for [Ollama](#ollama): `just ollama-stop`
#### Prepare your configuration file
This is about editing your configuration. The initial configuration is created based on `etc/app/config.yml.dist` when you run `just app-local-prepare` or `just app-container-prepare`.
Depending on whether you run locally or in a container, your configuration lives in a different file (`var/app/local/config.yml` and `var/app/container/config.yml`, respectively).
Before starting the bot, you may wish to adjust this configuration.
##### Choosing an agent provider
You can create [🤖 agents](./agents.md) either [statically](./configuration/README.md#static-configuration) or [dynamically](./configuration/README.md#dynamic-configuration) using any of the supported [☁️ providers](./providers.md).
For getting started most quickly (and locally), we recommend using [LocalAI](#localai) or [Ollama](#ollama). These services are already configured to run as [local services via docker-compose](../etc/services/).
**Ollama is most lightweight** (~2GB for the container image + ~1.6GB for the model), but supports only [💬 text-generation](./features.md#-text-generation).
**LocalAI requires 4x more disk space** (~6GB for the container image + ~12GB for the models), but supports [💬 text-generation](./features.md#-text-generation), [🗣️ text-to-speech](./features.md#️-text-to-speech), [🦻 speech-to-text](./features.md#-speech-to-text) and [🖼️ image-generation](./features.md#️-image-creation).
**OpenAI supports all of these capabilities** as well and does not require powerful hardware or lots of disk space. However, it requires signup and an API key.
For local testing, **we recommend LocalAI**, because it runs fully locally and supports more features than Ollama.
###### LocalAI
[LocalAI](./providers.md#localai) supports all [🌟 features](./features.md) of the bot.
If you decided to go with [LocalAI](./providers.md#localai):
- enable the `localai` entry in the `agents.static_definitions` list in the configuration file
- adjust the `initial_global_config.handler.catch_all` setting in the configuration file (`null` -> `static/localai`)
By default, we configure LocalAI to use the [All-In-One images](https://localai.io/basics/container/#all-in-one-images) running on the CPU.
Performance is not great, but it should work reasonably well on good hardware.
If you'd like to use GPU acceleration, you may adjust the `SERVICE_LOCALAI_IMAGE_NAME` variable in [var/services/env](../var/services/env) (this file is automatically prepared for you based on [etc/services/env.dist](../etc/services/env.dist)) to use [other available LocalAI All-In-One images](https://localai.io/basics/container/#available-aio-images).
###### Ollama
[Ollama](./providers.md#ollama) only supports [💬 text-generation](./features.md#-text-generation).
If you decided to go with [Ollama](./providers.md#ollama):
- enable the `ollama` entry in the `agents.static_definitions` list in the configuration file
- adjust the `initial_global_config.handler.catch_all` setting in the configuration file (`null` -> `static/ollama`)
The [gemma2:2b](https://ollama.com/library/gemma2:2b) model was chosen as a default, because it's smallest/lightest and should run well under [Ollama](./providers.md#ollama) on most machines.
###### OpenAI
[OpenAI](./providers.md#openai) supports all [🌟 features](./features.md) of the bot.
If you decided to go with [OpenAI](./providers.md#openai):
- enable the `openai` entry in the `agents.static_definitions` list in the configuration file
- adjust the `initial_global_config.handler.catch_all` setting in the configuration file (`null` -> `static/openai`)
================================================
FILE: docs/features.md
================================================
## 🌟 Features
### 🎨 Mixing & matching models
You can use **different models in different rooms** (e.g. [OpenAI](./providers.md#openai) GPT-4o alongside [Llama](https://en.wikipedia.org/wiki/Llama_(language_model)) running on [Groq](./providers.md#groq), etc.)
You can also use **different models within the same room** (e.g. [💬 text-generation](#-text-generation) handled by one [🤖 agent](./agents.md), [🦻 speech-to-text](#-speech-to-text) handled by another, [🗣️ text-to-speech](#️-text-to-speech) by a 3rd, etc.)
The bot supports the following use-purposes:
- [💬 text-generation](#-text-generation): communicating with you via text (though certain models may also process images and files)
- [🦻 speech-to-text](#-speech-to-text): turning your voice messages into text
- [🗣️ text-to-speech](#%EF%B8%8F-text-to-speech): turning bot or users text messages into voice messages
- [🖌️ image-generation](#%EF%B8%8F-image-generation): generating images based on instructions
In a given room, each different purpose can be served by a different [☁️ provider](./providers.md) and model. This combination of provider and model configuration is called an [🤖 agent](./agents.md). Each purpose can be served by a different **handler** agent.
See a [🖼️ Screenshot of an example room configuration](./screenshots/config-status-handlers.webp).
For more information about configuring handlers, see the [🤝 Handlers / Configuring](./configuration/handlers.md#configuring) documentation section.
### 💬 Text Generation
Text Generation is the bot's ability to **respond to users' messages with text**.

Some models also support vision and document understanding, so you may be able to mix text, images, and files (PDFs, text documents, etc.) in the same conversation. Note that certain providers may not support all file types or may have issues with specific files (e.g. scanned/image-based PDFs). If a file is rejected by the provider, the conversation thread may become unusable — start a new thread to work around this.
In multi-user (group) rooms, to avoid disturbing the normal conversation between people, the bot is auto-configured to only respond to messages starting with the command prefix (`!bai`) or direct mentions via the [💬 Text Generation / 🗟 Prefix Requirement Type](./configuration/text-generation.md#-prefix-requirement-type) setting.
Normally, the bot only responds to allowed [👥 Users](./access.md#-users). In certain cases, it's useful for an allowed user to provoke the bot to respond even in foreign threads or reply chains. You can learn more about this feature in the [On-demand involvement](./features.md#on-demand-involvement) section below.
If needed, the bot can also attach sender metadata to conversation messages before sending them to the model, which can help the model distinguish between participants in multi-user rooms. See [🛠️ Configuration / 💬 Text Generation / 👤 Sender Context Mode](./configuration/text-generation.md#-sender-context-mode).
A few other features (like [🗣️ Text-to-Speech](#️-text-to-speech) and [🦻 Speech-to-Text](#-speech-to-text)) combine well with Text Generation, so you **don't necessarily need to communicate with the bot via text** (with [Seamless voice interaction](#seamless-voice-interaction), you can communicate only with voice).
You may also wish to see:
- [🛠️ Configuration / 💬 Text Generation](./configuration/text-generation.md) for configuration options related to Text Generation
- [📖 Usage / 💬 Text Generation](./usage.md#-text-generation) section for more details on how to use the bot for Text Generation in a room
#### 🛠️ Built-in Tools (OpenAI only)
The [OpenAI provider](./providers.md#openai) supports built-in tools that extend the model's capabilities:
- [🔍 Web Search](https://platform.openai.com/docs/guides/tools-web-search) (`web_search`): allows the model to search the web for up-to-date information. [🖼️ Screenshot](./screenshots/text-generation-tools-web-search.webp)
- [💻 Code Interpreter](https://platform.openai.com/docs/guides/tools-code-interpreter) (`code_interpreter`): allows the model to write and execute Python code in a sandbox
These tools are **disabled by default** and need to be explicitly enabled in the agent's `text_generation.tools` configuration. See the [OpenAI sample configuration](https://github.com/etkecc/baibot/blob/c70387b0c38d8d0f30bba2179a2a21a3710dbeaf/docs/sample-provider-configs/openai.yml#L12-L15) for reference.
To enable tools on an existing dynamically-created agent, you need to [update the agent](./agents.md#updating-agents) to re-create it with the `text_generation.tools` section added and enable the tools you need
💡 **Note**: These tools run on OpenAI's infrastructure and may incur additional costs. Web search results include citations that are incorporated into the response.
#### On-demand involvement
In the following 2 cases, it's useful to involve the bot in conversations on-demand:
1. In multi-user rooms (with the [🗟 Prefix Requirement](./configuration/text-generation.md#-prefix-requirement-type) setting set to "required")
2. In rooms with foreign users (users that are not authorized bot [👥 users](./access.md#-users))
In these instances, an allowed [👥 user](./access.md#-users) can also provoke the bot to respond to **any** thread or reply chain by [mentioning](https://spec.matrix.org/latest/client-server-api/#user-and-room-mentions) the bot (e.g. `@baibot Hello!`). The following screenshots demonstrate this behavior:
- [🖼️ On-demand involvement in the room](./screenshots/text-generation-prefix-requirement.webp)
- [🖼️ On-demand involvement in a thread](./screenshots/text-generation-on-demand-thread-involvement.webp) (the Alice user in this example is not an allowed user, yet her messages are still considered as part of the conversation context)
- [🖼️ On-demand involvement in a reply chain](./screenshots/text-generation-on-demand-reply-involvement.webp) (the Alice user in this example is not an allowed user, yet her messages are still considered as part of the conversation context)
💡 **NOTE**: Normally, the bot **only considers messages from allowed [👥 Users](./access.md#-users)** and ignores all other messages when responding. However, **when the bot is explicitly invoked (via mention)** in a thread or reply chain, **it will consider all messages** in the thread and reply chain (even those from foreign users) as part of the conversation context.
### 🗣️ Text-to-Speech
Text-to-Speech is the bot's ability to **turn text messages into voice messages**.
It can be performed **on the bot's own text messages** (responses to yours due to [💬 Text Generation](#-text-generation)) and/or **on your own text messages**.
Text-to-Speech can be enabled to be done automatically or on-demand (only after reacting to a message with 🗣️), and is configurable for different message types ([🪄 Bot Messages Flow Type](./configuration/README.md#-bot-messages-flow-type) vs [🪄 User Messages Flow Type](./configuration/README.md#-user-messages-flow-type)).
By default, the bot **doesn't** perform text-to-speech. It can be configured for [Seamless voice interaction](#seamless-voice-interaction), where you can **speak to the bot** (instead of typing) and then **hear its responses**.
Another use-case is to have the bot operate in [Text-to-Speech-only mode](#text-to-speech-only-mode).
You may also wish to see:
- [🛠️ Configuration / 🗣️ Text-to-Speech](./configuration/text-to-speech.md) for configuration options related to Text-to-Speech
- [📖 Usage / 🗣️ Text-to-Speech](./usage.md#-text-to-speech) section for more details on how to use the bot for Text-to-Speech in a room
#### Text-to-Speech-only mode
You may wish to have the bot **automatically turn your text messages into voice messages**, but **without** doing [💬 Text Generation](#-text-generation).

This could be useful in a room with others, where you'd like to post text messages and have people in the room consume them more easily (by listening to audio).
To allow for this use-case, you can:
- disable [💬 Text Generation](#-text-generation) (via [💬 Text Generation / 🪄 Auto Usage](./configuration/text-generation.md#-auto-usage) setting): `!bai config room text-generation set-auto-usage never`
- enable [🗣️ Text-to-Speech](#️-text-to-speech) for user messages (via [🗣️ Text-to-Speech / 🪄 User Messages Flow Type](./configuration/text-to-speech.md#-user-messages-flow-type)): `!bai config room text-to-speech set-user-msgs-flow-type always` (or `on_demand`)
### 🦻 Speech-to-Text
Speech-to-Text is the bot's ability to **turn voice messages into text**.

The default flow is shown in the screenshot above: your voice messages are transcribed to text and [💬 Text Generation](#-text-generation) is performed. By default, the bot offers [🗣️ Text-to-Speech](#️-text-to-speech) for its answers via a 🗣️ emoji. You can click it to trigger text-to-speech on-demand.
You may also configure the bot for [Seamless voice interaction](#seamless-voice-interaction) or [Transcribe-only mode](#transcribe-only-mode), etc.
You may also wish to see:
- [🛠️ Configuration / 🦻 Speech-to-Text](./configuration/speech-to-text.md) for configuration options related to Speech-to-Text
- [📖 Usage / 🦻 Speech-to-Text](./usage.md#-speech-to-text) section for more details on how to use the bot for Speech-to-Text in a room
#### Seamless voice interaction
The bot can perform seamless voice interaction (🗣️-to-🗣️), allowing you to **speak to the bot** (instead of typing) and then **hear its responses**.

The flow is like this:
1. 👤 You sending a voice message
2. 🤖 The bot:
- (default) first turning your **voice message into text** ([🦻 Speech-to-Text](#-speech-to-text)) and posting it as a reply. This lets you you see what the bot heard.
- (default) then **answering in text** ([💬 Text Generation](#-text-generation)). This lets you read/skim text, if you so prefer.
- (can be enabled) finally **turning the answer's text into a voice message** ([🗣️ Text-to-Speech](#️-text-to-speech))
3. 👤 You continuing the conversation via text or voice messages
⚠️ Certain clients (like [Element](https://element.io/)) only support sending voice messages as top-level room messages, not as thread replies. Until this client limitation is fixed, Element users can only send the 1st message as a voice message - subsequent replies in the same conversation thread will need to be sent as text messages.
By default, the last part of the aforementioned flow is **not enabled**, because we assume **a saner default is to reply with text and merely *offer* text-to-speech to those who want it**. Offering is done by the bot reacting to its own message with 🗣️, and letting you click this emoji to trigger text-to-speech on-demand.
To enable automatic text-to-speech for the bot's messages, set the [🗣️ Text-to-Speech / 🪄 Bot Messages Flow Type](./configuration/text-to-speech.md#-bot-messages-flow-type) setting to `only_for_voice` or `always` (e.g. `!bai config room text-to-speech set-bot-msgs-flow-type only_for_voice`).
#### Transcribe-only mode
If you'd like to have the bot **only turn voice messages into text** (without generating text messages or voice messages), you can configure the bot for that.

To operate in this mode, you can:
- disable [💬 Text Generation](#-text-generation) (via [💬 Text Generation / 🪄 Auto Usage](./configuration/text-generation.md#-auto-usage) setting): `!bai config room text-generation set-auto-usage never`
- adjust the [🦻 Speech-to-Text / 🪄 Flow Type](./configuration/speech-to-text.md#-flow-type) setting to make the bot only transcribe (without doing [💬 Text Generation](#-text-generation)): `!bai config room speech-to-text set-flow-type only_transcribe`
- optionally adjust [🦻 Speech-to-Text / 🪄 Message Type for non-threaded only-transcribed messages](./configuration/speech-to-text.md#-message-type-for-non-threaded-only-transcribed-messages), if you'd like to bot to send messages of type `notice` (for better compatibility with other bots in the room) instead of sending regular `text` messages (default)
### Image Generation
#### 🖌️ Image Creation
Image creation is the bot's ability to **create images** based on text prompts.
See a [🖼️ Screenshot of the Image Creation feature](./screenshots/image-creation.webp).
You may also wish to see:
- [🛠️ Configuration / 🖌️ Image Generation](./configuration/image-generation.md) for configuration options related to Image Generation
- [📖 Usage / Image Generation / 🖌️ Creating Images](./usage.md#-creating-images) section for more details on how to use the bot for Image Creation in a room
- [🖌️ Image Editing](#️-image-editing) - another image generation feature
- [🫵 Sticker Creation](#-sticker-creation) - a special case of Image Creation
#### 🎨 Image Editing
Image editing is the bot's ability to **edit images** based on a prompt and one or more existing images.
See a [🖼️ Screenshot of the Image Editing feature (manipulating a single image)](./screenshots/image-editing-single-image.webp) and a [🖼️ Screenshot of the Image Editing feature (manipulating multiple images)](./screenshots/image-editing-multiple-images.webp).
You may also wish to see:
- [🛠️ Configuration / 🖌️ Image Generation](./configuration/image-generation.md) for configuration options related to Image Generation
- [📖 Usage / Image Generation / 🎨 Editing images](./usage.md#-editing-images) section for more details on how to use the bot for Image Editing in a room
- [🖌️ Image Creation](#️-image-creation) - another image generation feature
#### 🫵 Sticker Creation
Sticker generation is the bot's ability to **generate sticker** images based on text prompts. It's a special case of [🖌️ Image Creation](#️-image-creation).
See a [🖼️ Screenshot of the Sticker Creation feature](./screenshots/sticker-generation.webp).
See [📖 Usage / Image Generation / 🫵 Creating Stickers](./usage.md#-creating-stickers) for details.
### 🔒 Encryption
#### Message exchange
The bot works in both **unencrypted and encrypted Matrix rooms**.
If configured, the bot can make use of **Matrix's Secure Storage (Recovery) feature**, so that it can restore its encryption keys even its local database gets lost.
#### Configuration
The bot also stores its [🛠️ configuration](./configuration/README.md) (both 📍 per-room and 🌐globally) in Matrix Account Data, which is **generally stored as plain-text in the server**.
To overcome this Matrix limitation, the bot can **optionally encrypt the configuration data** before storing it in Account Data. This allows for the bot to be used securely even against untrusted servers, without leaking sensitive configuration data to them.
================================================
FILE: docs/installation.md
================================================
## 🚀 Installation
☁️ The easiest way to use the bot is to **get a managed Matrix server from [etke.cc](https://etke.cc/)** and order baibot via the [order form](https://etke.cc/order/). Existing customers can request the inclusion of this additional service by [contacting support](https://etke.cc/contacts/).
💻 If you're managing your Matrix server with the help of the [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy) Ansible playbook, you can easily **install the bot via the Ansible playbook**. See the playbook's [Setting up baibot](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-bot-baibot.md) documentation page.
🐋 In other cases, we **recommend using our [prebuilt container images](https://github.com/etkecc/baibot/pkgs/container/baibot) and [running in a container](#-running-in-a-container)**. You can also [build a container image](#building-a-container-image) yourself.
🔨 If containers are not your thing, you can [build a binary](#-building-a-binary) yourself and [run it](#-running-a-binary).
🗲 For a quick experiment, you can refer to the [🧑💻 development documentation](./development.md) which contains information on how to build and run the bot (and its various dependency services) locally.
### 🐋 Building a container image
We provide prebuilt container images for the `amd64` and `arm64` architectures, so **you don't necessarily need to build images yourself** and can jump to [Running in a container](#-running-in-a-container).
If you nevertheless wish to build a container image yourself, you can do so by running:
- (recommended) `just build-container-image-release` to build a release version of the container image
- or `just build-container-image-debug` to build a debug version of the container image
Debug images are faster to build but are larger in size.
Release images are ~5x smaller in size, but are slower to build.
Both of these commands will build and tag your container image as `localhost/baibot:latest`.
### 🐋 Running in a container
We recommend using a **tagged-release** (e.g. `v1.0.0`, not `latest`) of our [prebuilt container images](https://github.com/etkecc/baibot/pkgs/container/baibot), but you can also [build a container image](#-building-a-container-image) yourself.
You should:
- [🛠️ prepare a configuration file](#-preparing-a-configuration-file) (e.g. `cp etc/app/config.yml.dist /path/to/config.yml` & edit it)
- prepare a data directory (`mkdir /path/to/data`)
The example below uses [🐋 Docker](https://www.docker.com/) to run the container, but other container runtimes like [Podman](https://podman.io/) should work as well.
```sh
# Adjust the version tag to point to the latest available tagged version.
# If building your own container image name, adjust to something like `localhost/baibot:latest`.
CONTAINER_IMAGE_NAME=ghcr.io/etkecc/baibot:v1.0.0
/usr/bin/env docker run \
-it \
--rm \
--name=baibot \
--user=$(id -u):$(id -g) \
--cap-drop=ALL \
--read-only \
--env BAIBOT_PERSISTENCE_DATA_DIR_PATH=/data \
--mount type=bind,src=/path/to/config.yml,dst=/app/config.yml,ro \
--mount type=bind,src=/path/to/data,dst=/data \
--tmpfs=/tmp:rw,noexec,nosuid,size=1024m \
$CONTAINER_IMAGE_NAME
```
💡 If you've defined the `persistence.data_dir_path` setting in the `config.yml` file, you can skip the `BAIBOT_PERSISTENCE_DATA_DIR_PATH` environment variable.
### 🔨 Building a binary
To build a binary, you need a [🦀 Rust](https://www.rust-lang.org/) toolchain.
Consult the [Dockerfile](../Dockerfile) file to learn what some of the build dependencies are (e.g. `libssl-dev`, `libsqlite3-dev`, etc., on Debian-based distros).
You can build a binary from the current project's source code:
- in `debug` mode via: `just build-debug`, yielding a binary in `target/debug/baibot`
- (recommended) in `release` mode via: `just build-release`, yielding a binary in `target/release/baibot`
💡 Unless you're [🧑💻 developing](./development.md), you probably wish to build in release mode, as that provides a much smaller and more optimized binary.
📦 You can also install from the [baibot](https://crates.io/crates/baibot) crate published to [crates.io](https://crates.io) with the help of the [cargo](https://doc.rust-lang.org/cargo/) package manager by running: `cargo install baibot`.
### 🖥️ Running a binary
Once you've [🔨 built a binary](#-building-a-binary) and [🛠️ prepared a configuration file](#-preparing-a-configuration-file), you can run it.
Consult the [Dockerfile](../Dockerfile) file to learn what some of the runtime dependencies are (e.g. `ca-certificates`, `sqlite3`, etc., on Debian-based distros).
You can run the binary like this:
```sh
BAIBOT_CONFIG_FILE_PATH=/path/to/config.yml \
BAIBOT_PERSISTENCE_DATA_DIR_PATH=/path/to/data \
./target/release/baibot
```
💡 If you've defined the `persistence.data_dir_path` setting in the `config.yml` file, you can skip the `BAIBOT_PERSISTENCE_DATA_DIR_PATH` environment variable.
💡 If your `config.yml` file is in your working directory (which may be different than the directory the binary lives in), you can skip the `BAIBOT_CONFIG_FILE_PATH` environment variable.
### 🛠️ Preparing a configuration file
For an introduction to the configuration file, see the [🛠️ Configuration](./configuration/README.md) page.
Generally, you need to copy the configuration file template ([etc/app/config.yml.dist](../etc/app/config.yml.dist)) and make modifications as needed.
================================================
FILE: docs/providers.md
================================================
## ☁️ Providers
[🤖 Agents](./agents.md) are powered by a provider. The provider could be a **local service** or a **cloud service**.
The list of supported providers is below.
### Table of contents
- [How to choose a provider](#how-to-choose-a-provider)
- [How to use a provider](#how-to-use-a-provider)
- [Supported providers](#supported-providers)
- [Anthropic](#anthropic)
- [Groq](#groq)
- [LocalAI](#localai)
- [Mistral](#mistral)
- [Ollama](#ollama)
- [OpenAI](#openai)
- [OpenAI Compatible](#openai-compatible)
- [OpenRouter](#openrouter)
- [Together AI](#together-ai)
### How to choose a provider
If you're not sure which provider to start with, **we recommend [OpenAI](#openai)** as it's the most popular and has the **widest range of capabilities**: [💬 text-generation](./features.md#-text-generation) (incl. vision, incl. [🛠️ tools](./features.md#️-built-in-tools-openai-only)), [🖌️ image-generation](./features.md#️image-generation), [🦻 speech-to-text](./features.md#-speech-to-text), [🗣️ text-to-speech](./features.md#️-text-to-speech).
You don't need to choose just one though. The bot supports [mixing & matching models](./features.md#-mixing--matching-models), so you can use multiple providers at the same time.
### How to use a provider
1. 📝 **Sign up for it**
2. 🔑 **Obtain an API key**
3. 🤖 **Create one or more agents** in a given room or globally. Next to each provider in the [list below](#supported-providers) you'll see **🗲 Quick start** commands, but you may also refer to the [agent creation guide](./agents.md#creating-agents).
4. 🤝 **Set the new agent as a handler** for a given use-purpose like text-generation, image-generation, etc. The agent creation wizard will tell you how, but you may also refer to the [🤝 Handlers](./configuration/handlers.md) guide.
### Supported providers
### Anthropic
[Anthropic](https://www.anthropic.com/) is an American AI company founded by former OpenAI engineers and providing powerful language models.
- 🆔 Identifier: `anthropic`
- 🔗 Links: [🏠 Home page](https://www.anthropic.com/), [🌐 Wiki](https://en.wikipedia.org/wiki/Anthropic), [👤 Sign up](https://console.anthropic.com/), [📋 Models list](https://docs.anthropic.com/en/docs/about-claude/models)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (incl. vision, no tools)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local anthropic my-anthropic-agent`
- create a global agent: `!bai agent create-global anthropic my-anthropic-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/anthropic.yml).
### Groq
[Groq](https://groq.com/) is an American company developing optimized Language Processing Units (LPU) and offering cloud service which runs various models (built by others) with very high performance.
- 🆔 Identifier: `groq`
- 🔗 Links: [🏠 Home page](https://groq.com/), [🌐 Wiki](https://en.wikipedia.org/wiki/Groq), [👤 Sign up](https://console.groq.com/login), [📋 Models list](https://console.groq.com/docs/models)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools), [🦻 speech-to-text](./features.md#-speech-to-text)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local groq my-groq-agent`
- create a global agent: `!bai agent create-global groq my-groq-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/groq.yml).
### LocalAI
[LocalAI](https://localai.io/) is the free, Open Source OpenAI alternative. LocalAI act as a drop-in replacement REST API that’s compatible with OpenAI API specifications for local inferencing. It allows you to run LLMs, generate images, audio (and not only) locally or on-prem with consumer grade hardware, supporting multiple model families and architectures.
- 🆔 Identifier: `localai`
- 🔗 Links: [🏠 Home page](https://localai.io/), [📋 Models list](https://localai.io/gallery.html)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools), [🗣️ text-to-speech](./features.md#️-text-to-speech), [🦻 speech-to-text](./features.md#-speech-to-text)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local localai my-localai-agent`
- create a global agent: `!bai agent create-global localai my-localai-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/localai.yml).
### Mistral
[Mistral AI](https://mistral.ai/) is a research lab based in Europe (France) which produces their own language models.
- 🆔 Identifier: `mistral`
- 🔗 Links: [🏠 Home page](https://mistral.ai/), [🌐 Wiki](https://en.wikipedia.org/wiki/Mistral_AI), [👤 Sign up](https://auth.mistral.ai/ui/registration), [📋 Models list](https://docs.mistral.ai/getting-started/models/)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local mistral my-mistral-agent`
- create a global agent: `!bai agent create-global mistral my-mistral-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/mistral.yml).
### Ollama
[Ollama](https://ollama.com/) lets you run various models in a [self-hosted](https://github.com/ollama/ollama?tab=readme-ov-file#ollama) way. This is more advanced and requires powerful hardware for running some of the better models, but ensures your data stays with you.
- 🆔 Identifier: `ollama`
- 🔗 Links: [🏠 Home page](https://ollama.com/), [📋 Models list](https://ollama.com/library)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local ollama my-ollama-agent`
- create a global agent: `!bai agent create-global ollama my-ollama-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/ollama.yml).
### OpenAI
[OpenAI](https://openai.com/) is an American AI company providing powerful language models.
Use this provider either with the OpenAI API or with other OpenAI-compatible API services which **fully** adhere to the [OpenAI API spec](https://github.com/openai/openai-openapi/).
For services which are not fully compatible with the OpenAI API, consider using the [OpenAI Compatible](#openai-compatible) provider.
- 🆔 Identifier: `openai`
- 🔗 Links: [🏠 Home page](https://openai.com/), [🌐 Wiki](https://en.wikipedia.org/wiki/OpenAI), [👤 Sign up](https://platform.openai.com/signup), [📋 Models list](https://platform.openai.com/docs/models)
- 🌟 Capabilities: [🖌️ image-generation](./features.md#️-image-creation), [💬 text-generation](./features.md#-text-generation) (incl. vision, incl. [🛠️ tools](./features.md#️-built-in-tools-openai-only)), [🗣️ text-to-speech](./features.md#️-text-to-speech), [🦻 speech-to-text](./features.md#-speech-to-text)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local openai my-openai-agent`
- create a global agent: `!bai agent create-global openai my-openai-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/openai.yml).
### OpenAI Compatible
This provider allows you to use OpenAI-compatible API services like [OpenRouter](https://openrouter.ai/), [Together AI](https://www.together.ai/), etc.
Some of these popular services already have **shortcut** providers (leading to this one behind the scenes) - this make it easier to get started.
This provider is just as featureful as the [OpenAI](#openai) provider, but is more compatible with services which do not fully adhere to the [OpenAI API spec](https://github.com/openai/openai-openapi/).
- 🆔 Identifier: `openai-compatible`
- 🌟 Capabilities: [🖌️ image-generation](./features.md#️-image-creation), [💬 text-generation](./features.md#-text-generation) (no vision, no tools), [🗣️ text-to-speech](./features.md#️-text-to-speech), [🦻 speech-to-text](./features.md#-speech-to-text)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local openai-compatible my-openai-compatible-agent`
- create a global agent: `!bai agent create-global openai-compatible my-openai-compatible-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/openai-compatible.yml).
### OpenRouter
[OpenRouter](https://openrouter.ai/) is a unified interface for LLMs. The platform scouts for the lowest prices and best latencies/throughputs across dozens of providers, and lets you choose how to [prioritize](https://openrouter.ai/docs/provider-routing) them.
- 🆔 Identifier: `openrouter`
- 🔗 Links: [🏠 Home page](https://openrouter.ai/), [👤 Sign up](https://openrouter.ai/), [📋 Models list](https://openrouter.ai/models)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local openrouter my-openrouter-agent`
- create a global agent: `!bai agent create-global openrouter my-openrouter-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/openrouter.yml).
### Together AI
[Together AI](https://www.together.ai/) makes it easy to run or [fine-tune](https://docs.together.ai/docs/fine-tuning-overview) leading open source models with only a few lines of code.
- 🆔 Identifier: `together-ai`
- 🔗 Links: [🏠 Home page](https://www.together.ai/), [👤 Sign up](https://api.together.ai/signup), [📋 Models list](https://api.together.xyz/models)
- 🌟 Capabilities: [💬 text-generation](./features.md#-text-generation) (no vision, no tools)
- 🗲 Quick start:
- create a room-local agent: `!bai agent create-room-local together-ai my-together-ai-agent`
- create a global agent: `!bai agent create-global together-ai my-together-ai-agent`
💡 When creating an agent, the bot will show you an up-to-date sample configuration for this provider which looks [like this](./sample-provider-configs/together-ai.yml).
================================================
FILE: docs/sample-provider-configs/anthropic.yml
================================================
base_url: https://api.anthropic.com/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: claude-3-7-sonnet-20250219
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 8192
max_context_tokens: 204800
================================================
FILE: docs/sample-provider-configs/groq.yml
================================================
base_url: https://api.groq.com/openai/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: llama3-70b-8192
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 4096
max_context_tokens: 131072
speech_to_text:
model_id: whisper-large-v3
================================================
FILE: docs/sample-provider-configs/localai.yml
================================================
base_url: http://my-localai-self-hosted-service:8080/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: gpt-4
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 4096
max_context_tokens: 128000
speech_to_text:
model_id: whisper-1
text_to_speech:
model_id: tts-1
voice: onyx
speed: 1.0
response_format: opus
image_generation:
model_id: stablediffusion
style: vivid
size: 1024x1024
quality: standard
================================================
FILE: docs/sample-provider-configs/mistral.yml
================================================
base_url: https://api.mistral.ai/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: mistral-large-latest
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 4096
max_context_tokens: 128000
================================================
FILE: docs/sample-provider-configs/ollama.yml
================================================
base_url: http://my-ollama-self-hosted-service:11434/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: gemma2:2b
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 4096
max_context_tokens: 128000
================================================
FILE: docs/sample-provider-configs/openai-compatible.yml
================================================
base_url: ''
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: some-model
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 4096
max_context_tokens: 128000
speech_to_text:
model_id: whisper-1
================================================
FILE: docs/sample-provider-configs/openai.yml
================================================
base_url: https://api.openai.com/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: gpt-5.4
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
# Reasoning models need to use `max_completion_tokens` instead of `max_response_tokens`.
# If you're dealing with a non-reasoning model, specify `max_response_tokens` and unset `max_completion_tokens`.
max_response_tokens: null
max_completion_tokens: 128000
max_context_tokens: 400000
# Built-in tools
tools:
web_search: false
code_interpreter: false
speech_to_text:
model_id: whisper-1
text_to_speech:
model_id: tts-1-hd
voice: onyx
speed: 1.0
response_format: opus
image_generation:
model_id: gpt-image-1.5
style: null
size: null
quality: null
================================================
FILE: docs/sample-provider-configs/openrouter.yml
================================================
base_url: https://openrouter.ai/api/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: mattshumer/reflection-70b:free
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 2048
max_context_tokens: 8192
================================================
FILE: docs/sample-provider-configs/together-ai.yml
================================================
base_url: https://api.together.xyz/v1
api_key: YOUR_API_KEY_HERE
text_generation:
model_id: meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo
prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
temperature: 1.0
max_response_tokens: 2048
max_context_tokens: 8192
================================================
FILE: docs/usage.md
================================================
## 📖 Usage
This document covers how to use the bot in a room.
The [🌟 Features](./features.md) page also includes details about how each feature works and can be configured.
### 💬 Text Generation
This is related to the [💬 Text Generation](./features.md#-text-generation) feature.
If there's a text-generation handler agent configured, the bot **may** respond to messages sent in the room.
Some models also support vision and document understanding, so you may be able to mix text, images, and files (PDFs, text documents, etc.) in the same conversation.
See screenshots of:
- 🖼️ [the default Text Generation flow](./screenshots/text-generation.webp) in 1:1 rooms
- 🖼️ [the Text Generation flow in multi-user rooms](./screenshots/text-generation-prefix-requirement.webp) (where the [🗟 Prefix Requirement](./configuration/text-generation.md#-prefix-requirement-type) setting is auto-configured to "required")
- the [on-demand involvement](./features.md#on-demand-involvement) feature
Whether the bot responds depends on:
- ([🔒 access](./access.md)) whether you're a whitelisted bot [👥 user](./access.md#-users)
- [🛠️ configuration](./configuration/README.md) whether there's a configured `text-generation` handler agent (or a `catch-all` handler agent). See [Mixing & matching models](./features.md#-mixing--matching-models)
- (🎨 agent capabilities) whether the configured `text-generation` (or `catch-all`) handler agent actually supports text-generation. The provider may lack support for this feature or it may be disabled in the [🤖 agents](./agents.md) configuration
- (the [🗟 Prefix Requirement](./configuration/text-generation.md#-prefix-requirement-type) setting) whether a prefix (e.g. `!bai`) or user mention (e.g. `@baibot`) is required for messages sent to the room. For multi-user rooms, this setting defaults to "required". See [🌟 Features / 💬 Text Generation / On-demand involvement](./features.md#on-demand-involvement) for details.
Room messages start a threaded conversation where you can continue back-and-forth communication with the bot. Using [on-demand involvement](./features.md#on-demand-involvement), you can can also mention the bot to provoke it to get involved in any conversation thread or reply chain.
Unless you've enabled the [♻️ Context Management](./features.md#️-context-management) feature, all messages will be sent to the agent's API each time. If the context management feature is enabled, older messages may be dropped.
### 🗣️ Text-to-Speech
This is related to the [🗣️ Text-to-Speech](./features.md#️-text-to-speech) feature.
If there's a text-to-speech handler agent configured, the bot **may** convert text messages sent to the room to audio (voice).
See:
- a [🖼️ screenshot](./screenshots/text-to-speech-only-mode.webp) of the bot's [Text-to-Speech-only](./features.md#text-to-speech-only-mode) mode
- a [🖼️ screenshot](./screenshots/text-to-speech-seamless-voice-interaction.webp) of the bot's [Seamless voice interaction](./features.md#seamless-voice-interaction) mode
By default, the bot:
- will offer tex-to-speech for its own messages which are a response to voice message from your, as part of the [Seamless voice interaction](./features.md#seamless-voice-interaction) feature. This can be adjusted via the [🗣️ Text-to-Speech / 🪄 Bot Messages Flow Type](./configuration/text-to-speech.md#-bot-messages-flow-type) setting.
- does not turn your own text messages to audio (voice). If you'd like for the bot to operate in such a mode, use the [🗣️ Text-to-Speech / 🪄 User Messages Flow Type](./configuration/text-to-speech.md#-user-messages-flow-type) setting (see [Text-to-Speech-only mode](./features.md#text-to-speech-only-mode)).
### 🦻 Speech-to-Text
This is related to the [🦻 Speech-to-Text](./features.md#-speech-to-text) feature.
If there's a speech-to-text handler agent configured, the bot **may** transcribe voice messages sent to the room to text.
See a [🖼️ Screenshot of the default flow for Speech-to-Text and Text-Generation](./screenshots/speech-to-text-default-flow.webp).
The speech-to-text feature triggers automatically by default, but can be adjusted via the [🦻 Speech-to-Text / 🪄 Flow Type](./features.md#-speech-to-text-flow-type) setting.
If all your messages are in the same language, you can improve accuracy & latency by configuring the language (see [🦻 Speech-to-Text / 🔤 Language](./configuration/speech-to-text.md#-language)).
### Image Generation
This feature is not configurable at the moment. The configuration (size, quality, style) specified at the [🤖 agent](./agents.md) level will be used.
Capabilities depend on the [☁️ provider](./providers.md) and model used.
#### 🖌️ Creating images
Simply send a command like `!bai image create A beautiful sunset over the ocean` and the bot will start a threaded conversation and post an image based on your prompt.
See a [🖼️ Screenshot of the Image Creation feature](./screenshots/image-creation.webp).
You can then respond in the same message thread with:
- more messages, to add more criteria to your prompt.
- a message saying `again`, to generate one more image with the current prompt.
#### 🎨 Editing images
Simply send a command like `!bai image edit Turn the following image into an anime-style drawing` and the bot will start a threaded conversation asking for more details.
See a [🖼️ Screenshot of the Image Editing feature (manipulating a single image)](./screenshots/image-editing-single-image.webp) and a [🖼️ Screenshot of the Image Editing feature (manipulating multiple images)](./screenshots/image-editing-multiple-images.webp).
You can then respond in the same message thread with:
- more messages, to add more criteria to your prompt.
- one or more images, to provide the images that the bot will operate on.
- a message saying `go`, to start the image generation process.
- a message saying `again`, to prompt the bot to generate one more image edit with the current prompt.
#### 🫵 Creating stickers
A variation of [creating images](#creating-images) is creating "sticker images".
See a [🖼️ Screenshot of the Sticker Creation feature](./screenshots/sticker-generation.webp).
To create a sticker, send a command like `!bai sticker A huge ramen bowl with lots of chashu and a mountain of beansprouts on top`.
The difference from [creating images](#creating-images) is that the bot will:
- generate a smaller-resolution image (currently hardcoded to `256x256`) - smaller/quicker, but still good enough for a sticker
- potentially switch to a different (cheaper or otherwise more suitable) model, if available
- post the image directly to the room (as a reply to your message), without starting a threaded conversation
Some models (like [OpenAI](./providers.md#openai)'s [Dall-E-3](https://openai.com/index/dall-e-3/)) can only generate larger images (`1024x1024`, etc., for a higher charge), so we switching to a smaller/cheaper model (like [Dall-E-2](https://openai.com/index/dall-e-2/)) is a way to generate a sticker cheaply.
================================================
FILE: etc/app/config.yml.dist
================================================
homeserver:
# The canonical homeserver domain name
server_name: __HOMESERVER_SERVER_NAME__
url: __HOMESERVER_URL__
user:
mxid_localpart: baibot
# Authentication: set EITHER password OR access_token + device_id.
#
# Password-based login (traditional homeservers):
password: baibot
# Access token login (for Matrix Authentication Service/OIDC-enabled homeservers):
# Generate a token via: mas-cli manage issue-compatibility-token <username> [device_id]
# access_token: null
# device_id: null
# The name the bot uses as a display name and when it refers to itself.
# Leave empty to use the default (baibot).
name: baibot
# An optional path to an image file to be used as a custom avatar image.
# - null or empty string: use the default avatar
# - "keep": don't touch the avatar, keep whatever is already set
# - any other value: path to a custom avatar image file
avatar: null
encryption:
# An optional passphrase to use for backing up and recovering the bot's encryption keys.
# You can use any string here.
#
# If set to null, the recovery module will not be used and losing your session/database (see persistence)
# will mean you lose access to old messages in encrypted room.
#
# Changing this subsequently will also cause you to lose access to old messages in encrypted rooms.
# If you really need to change this:
# - Set `encryption_recovery_reset_allowed` to `true` and adjust the passphrase
# - Remove your session file and database (see persistence)
# - Restart the bot
# - Then restore `encryption_recovery_reset_allowed` to `false` to prevent accidental resets in the future
recovery_passphrase: long-and-secure-passphrase-here
# An optional flag to reset the encryption recovery passphrase.
recovery_reset_allowed: false
# Command prefix. Leave empty to use the default (!bai).
command_prefix: "!bai"
room:
# Whether the bot should send an introduction message after joining a room.
post_join_self_introduction_enabled: true
access:
# Space-separated list of MXID patterns which specify who is an admin.
admin_patterns:
- "@admin:__HOMESERVER_SERVER_NAME__"
persistence:
# This is unset here, because we expect the configuration to come from an environment variable (BAIBOT_PERSISTENCE_DATA_DIR_PATH).
# In your setup, you may wish to set this to a directory path.
data_dir_path: null
# An optional secret for encrypting the bot's session data (stored in data_dir_path).
# This must be 32-bytes (64 characters when HEX-encoded).
# Generate it with: `openssl rand -hex 32`
# Leave null or empty to avoid using encryption.
# Changing this subsequently requires that you also throw away all data stored in data_dir_path.
session_encryption_key: 9701cd109ed56770687dd8410f7d7371a4390dd3feb8ed721f189a0756c40098
# An optional secret for encrypting bot configuration stored in Matrix's account data.
# This must be 32-bytes (64 characters when HEX-encoded).
# Generate it with: `openssl rand -hex 32`
# Leave null or empty to avoid using encryption.
# Changing this subsequently will make you lose your configuration.
config_encryption_key: a9f1df98d288802ead20a8be2c701a627eabd31cf3d9e2aea28867ccd7a4ded7
agents:
# A list of statically-defined agents.
#
# Below are a few common choices on popular providers, preconfigured for development purposes (see docs/development.md).
# You may enable some of the ones you see below or define others.
# You can also leave this list empty and only define agents dynamically (via chat).
#
# Uncomment one or more of these and potentially adjust their configuration (API key, etc).
# Consider setting `initial_global_config.handler.*` to an agent that you enable here.
static_definitions:
# - id: openai
# provider: openai
# config:
# base_url: https://api.openai.com/v1
# api_key: ""
# text_generation:
# model_id: gpt-5.4
# prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
# temperature: 1.0
# # Reasoning models need to use `max_completion_tokens` instead of `max_response_tokens`.
# # If you're dealing with a non-reasoning model, specify `max_response_tokens` and unset `max_completion_tokens`.
# max_response_tokens: null
# max_completion_tokens: 128000
# max_context_tokens: 400000
# # Built-in tools
# tools:
# web_search: false
# code_interpreter: false
# speech_to_text:
# model_id: whisper-1
# text_to_speech:
# model_id: tts-1-hd
# voice: onyx
# speed: 1.0
# response_format: opus
# image_generation:
# model_id: gpt-image-1.5
# style: null
# size: null
# quality: null
#
# - id: localai
# provider: localai
# config:
# base_url: http://127.0.0.1:42027/v1
# api_key: null
# text_generation:
# model_id: gpt-4
# prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
# temperature: 1.0
# max_response_tokens: 16384
# max_context_tokens: 128000
# speech_to_text:
# model_id: whisper-1
# text_to_speech:
# model_id: tts-1
# voice: onyx
# speed: 1.0
# response_format: opus
# image_generation:
# model_id: stablediffusion
# style: vivid
# # Intentionally defaults to a small value to improve performance
# size: 256x256
# quality: standard
#
# - id: ollama
# provider: ollama
# config:
# base_url: "http://127.0.0.1:42026/v1"
# api_key: null
# text_generation:
# model_id: "gemma2:2b"
# prompt: "You are a brief, but helpful bot called {{ baibot_name }} powered by the {{ baibot_model_id }} model. The date/time of this conversation's start is: {{ baibot_conversation_start_time_utc }}."
# temperature: 1.0
# max_response_tokens: 4096
# max_context_tokens: 128000
# Initial global configuration. This only affects the first run of the bot.
# Configuration is later managed at runtime.
initial_global_config:
handler:
catch_all: null
text_generation: null
text_to_speech: null
speech_to_text: null
image_generation: null
# Space-separated list of MXID patterns which specify who can use the bot.
# By default, we let anyone on the homeserver use the bot.
user_patterns:
- "@*:__HOMESERVER_SERVER_NAME__"
# Controls logging.
#
# Sets all tracing targets (external crates) to warn, and our own logs to debug.
# For even more verbose logging, one may also use trace.
#
# matrix_sdk_crypto may be chatty and could be added with an error level.
#
# Learn more here: https://stackoverflow.com/a/73735203
logging: warn,mxlink=debug,baibot=debug
================================================
FILE: etc/services/continuwuity/compose.yml
================================================
services:
continuwuity:
image: forgejo.ellis.link/continuwuation/continuwuity:v0.5.9
user: "${UID}:${GID}"
restart: unless-stopped
cap_drop:
- ALL
read_only: true
environment:
CONDUWUIT_CONFIG: /etc/continuwuity/continuwuity.toml
CONDUWUIT_DATABASE_PATH: /var/lib/continuwuity
ports:
- "${SERVICE_CONTINUWUITY_BIND_PORT_CLIENT_API}:6167"
volumes:
- ../../etc/services/continuwuity/config:/etc/continuwuity:ro
- ./continuwuity/data:/var/lib/continuwuity
tmpfs:
- /tmp:rw,noexec,nosuid,size=500m
networks:
default:
name: ${NETWORK_NAME}
external: true
================================================
FILE: etc/services/continuwuity/config/continuwuity.toml
================================================
[global]
server_name = "continuwuity.127.0.0.1.nip.io"
address = "0.0.0.0"
port = 6167
database_path = "/var/lib/continuwuity"
allow_registration = true
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true
new_user_displayname_suffix = ""
max_request_size = 20_000_000
allow_federation = false
trusted_servers = ["matrix.org"]
log = "info,state_res=warn,rocket=off,_=off,sled=off"
================================================
FILE: etc/services/continuwuity/register-user.sh
================================================
#!/bin/sh
set -eu
if [ $# -ne 3 ]; then
echo "Usage: $0 <env-file> <username> <password>"
exit 1
fi
ENV_FILE="$1"
USERNAME="$2"
PASSWORD="$3"
SERVER="http://$(grep '^SERVICE_CONTINUWUITY_BIND_PORT_CLIENT_API=' "${ENV_FILE}" | cut -d= -f2)"
REGISTER_URL="${SERVER}/_matrix/client/v3/register"
echo "Registering user '${USERNAME}' on ${SERVER}..."
SESSION_RESPONSE=$(curl -s -X POST "${REGISTER_URL}" \
-H 'Content-Type: application/json' \
-d "{\"username\": \"${USERNAME}\", \"password\": \"${PASSWORD}\"}")
SESSION_ID=$(echo "${SESSION_RESPONSE}" | grep -o '"session":"[^"]*"' | head -1 | cut -d'"' -f4)
if [ -z "${SESSION_ID}" ]; then
echo "Error: Could not get session ID. Response: ${SESSION_RESPONSE}"
exit 1
fi
# Determine the required auth flow from the server response.
# The first user requires m.login.registration_token (bootstrap token from logs).
# Subsequent users use m.login.dummy (open registration).
if echo "${SESSION_RESPONSE}" | grep -q 'm.login.registration_token'; then
CONTAINER_ID=$(docker ps -q --filter name=baibot-continuwuity-continuwuity)
REG_TOKEN=$(docker logs "${CONTAINER_ID}" 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep 'using the registration token' | grep -oP 'registration token \K[A-Za-z0-9]+' | head -1)
AUTH_BODY="{\"type\": \"m.login.registration_token\", \"token\": \"${REG_TOKEN}\", \"session\": \"${SESSION_ID}\"}"
else
AUTH_BODY="{\"type\": \"m.login.dummy\", \"session\": \"${SESSION_ID}\"}"
fi
RESULT=$(curl -s -X POST "${REGISTER_URL}" \
-H 'Content-Type: application/json' \
-d "{\"username\": \"${USERNAME}\", \"password\": \"${PASSWORD}\", \"auth\": ${AUTH_BODY}}")
if echo "${RESULT}" | grep -q '"user_id"'; then
echo "Successfully registered user: $(echo "${RESULT}" | grep -o '"user_id":"[^"]*"' | cut -d'"' -f4)"
else
echo "Registration failed. Response: ${RESULT}"
exit 1
fi
================================================
FILE: etc/services/element-web/compose.yml
================================================
services:
element-web:
image: ghcr.io/element-hq/element-web:v1.12.18
user: "${UID}:${GID}"
restart: unless-stopped
environment:
ELEMENT_WEB_PORT: 8080
ports:
- "${SERVICE_ELEMENT_WEB_BIND_PORT_HTTP}:8080"
volumes:
- ./element-web/config.json:/app/config.json:ro
tmpfs:
- /var/cache/nginx:rw,mode=777
- /var/run:rw,mode=777
- /tmp/element-web-config:rw,mode=777
- /etc/nginx/conf.d:rw,mode=777
networks:
default:
name: ${NETWORK_NAME}
external: true
================================================
FILE: etc/services/element-web/config.json.dist
================================================
{
"default_hs_url": "__HOMESERVER_CLIENT_URL__",
"default_is_url": "https://vector.im",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"enableLabs": true,
"roomDirectory": {
"servers": [
"matrix.org"
]
}
}
================================================
FILE: etc/services/env.dist
================================================
SERVICE_SYNAPSE_BIND_PORT_CLIENT_API=127.0.0.1:42020
SERVICE_SYNAPSE_BIND_PORT_FEDERATION_API=127.0.0.1:42028
SERVICE_ELEMENT_WEB_BIND_PORT_HTTP=127.0.0.1:42025
SERVICE_CONTINUWUITY_BIND_PORT_CLIENT_API=127.0.0.1:42030
SERVICE_OLLAMA_BIND_PORT_HTTP=127.0.0.1:42026
# See https://localai.io/basics/container/#all-in-one-images for the list of available images
SERVICE_LOCALAI_IMAGE_NAME=docker.io/localai/localai:latest-aio-cpu
SERVICE_LOCALAI_BIND_PORT_HTTP=127.0.0.1:42027
# Variables below are added later on, dynamically
================================================
FILE: etc/services/localai/compose.yml
================================================
services:
localai:
image: ${SERVICE_LOCALAI_IMAGE_NAME}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/readyz"]
interval: 1m
timeout: 20m
retries: 5
ports:
- ${SERVICE_LOCALAI_BIND_PORT_HTTP}:8080
environment:
- DEBUG=true
volumes:
- ./localai/models:/build/models:cached
networks:
default:
name: ${NETWORK_NAME}
external: true
================================================
FILE: etc/services/ollama/compose.yml
================================================
services:
ollama:
image: docker.io/ollama/ollama:0.24.0
restart: unless-stopped
ports:
- "${SERVICE_OLLAMA_BIND_PORT_HTTP}:11434"
volumes:
- ./ollama:/root/.ollama
networks:
default:
name: ${NETWORK_NAME}
external: true
================================================
FILE: etc/services/synapse/compose.yml
================================================
services:
postgres:
image: docker.io/postgres:18.4-alpine
user: ${UID}:${GID}
restart: unless-stopped
environment:
POSTGRES_USER: synapse
POSTGRES_PASSWORD: synapse-password
POSTGRES_DB: homeserver
POSTGRES_INITDB_ARGS: --lc-collate C --lc-ctype C --encoding UTF8
PGDATA: /data
volumes:
- ./postgres:/data
- /etc/passwd:/etc/passwd:ro
synapse:
image: ghcr.io/element-hq/synapse:v1.153.0
user: "${UID}:${GID}"
restart: unless-stopped
entrypoint: python
command: "-m synapse.app.homeserver -c /config/homeserver.yaml"
ports:
- "${SERVICE_SYNAPSE_BIND_PORT_CLIENT_API}:8008"
- "${SERVICE_SYNAPSE_BIND_PORT_FEDERATION_API}:8008"
volumes:
- ../../etc/services/synapse/config:/config:ro
- ./synapse/media-store:/media-store
networks:
default:
name: ${NETWORK_NAME}
external: true
================================================
FILE: etc/services/synapse/config/homeserver.yaml
================================================
#jinja2: lstrip_blocks: "True"
# Configuration file for Synapse.
#
# This is a YAML file: see [1] for a quick introduction. Note in particular
# that *indentation is important*: all the elements of a list or dictionary
# should have the same indentation.
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
## Modules ##
# Server admins can expand Synapse's functionality with external modules.
#
# See https://matrix-org.github.io/synapse/latest/modules/index.html for more
# documentation on how to configure or create custom modules for Synapse.
#
#modules:
#- module: my_super_module.MySuperClass
# config:
# do_thing: true
#- module: my_other_super_module.SomeClass
# config: {}
modules: []
## Server ##
# The domain name of the server, with optional explicit port.
# This is used by remote servers to connect to this server,
# e.g. matrix.org, localhost:8080, etc.
# This is also the last part of your UserID.
#
server_name: "synapse.127.0.0.1.nip.io"
# When running as a daemon, the file to store the pid in
#
pid_file: /homeserver.pid
# The path to the web client which will be served at /_matrix/client/
# if 'webclient' is configured under the 'listeners' configuration.
#
#web_client_location: "/path/to/web/root"
# The public-facing base URL that clients use to access this HS
# (not including _matrix/...). This is the same URL a user would
# enter into the 'custom HS URL' field on their client. If you
# use synapse with a reverse proxy, this should be the URL to reach
# synapse via the proxy.
#
#public_baseurl: https://example.com/
# Set the soft limit on the number of file descriptors synapse can use
# Zero is used to indicate synapse should set the soft limit to the
# hard limit.
#
#soft_file_limit: 0
# Set to false to disable presence tracking on this homeserver.
#
#use_presence: false
# Whether to require authentication to retrieve profile data (avatars,
# display names) of other users through the client API. Defaults to
# 'false'. Note that profile data is also available via the federation
# API, so this setting is of limited value if federation is enabled on
# the server.
#
#require_auth_for_profile_requests: true
# If set to 'false', requires authentication to access the server's public rooms
# directory through the client API. Defaults to 'true'.
#
#allow_public_rooms_without_auth: false
# If set to 'false', forbids any other homeserver to fetch the server's public
# rooms directory via federation. Defaults to 'true'.
#
#allow_public_rooms_over_federation: false
# The default room version for newly created rooms.
#
# Known room versions are listed here:
# https://matrix.org/docs/spec/#complete-list-of-room-versions
#
# For example, for room version 1, default_room_version should be set
# to "1".
#
#default_room_version: "4"
# The GC threshold parameters to pass to `gc.set_threshold`, if defined
#
#gc_thresholds: [700, 10, 10]
# Set the limit on the returned events in the timeline in the get
# and sync operations. The default value is -1, means no upper limit.
#
#filter_timeline_limit: 5000
# Whether room invites to users on this server should be blocked
# (except those sent by local server admins). The default is False.
#
#block_non_admin_invites: True
# Room searching
#
# If disabled, new messages will not be indexed for searching and users
# will receive errors when searching for messages. Defaults to enabled.
#
#enable_search: false
# Restrict federation to the following whitelist of domains.
# N.B. we recommend also firewalling your federation listener to limit
# inbound federation traffic as early as possible, rather than relying
# purely on this application-layer restriction. If not specified, the
# default is to whitelist everything.
#
#federation_domain_whitelist:
# - lon.example.com
# - nyc.example.com
# - syd.example.com
# Prevent federation requests from being sent to the following
# blacklist IP address CIDR ranges. If this option is not specified, or
# specified with an empty list, no ip range blacklist will be enforced.
#
# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
# listed here, since they correspond to unroutable addresses.)
#
federation_ip_range_blacklist:
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '169.254.0.0/16'
- '::1/128'
- 'fe80::/64'
- 'fc00::/7'
# List of ports that Synapse should listen on, their purpose and their
# configuration.
#
# Options for each listener include:
#
# port: the TCP port to bind to
#
# bind_addresses: a list of local addresses to listen on. The default is
# 'all local interfaces'.
#
# type: the type of listener. Normally 'http', but other valid options are:
# 'manhole' (see docs/manhole.md),
# 'metrics' (see docs/metrics-howto.rst),
# 'replication' (see docs/workers.rst).
#
# tls: set to true to enable TLS for this listener. Will use the TLS
# key/cert specified in tls_private_key_path / tls_certificate_path.
#
# x_forwarded: Only valid for an 'http' listener. Set to true to use the
# X-Forwarded-For header as the client IP. Useful when Synapse is
# behind a reverse-proxy.
#
# resources: Only valid for an 'http' listener. A list of resources to host
# on this port. Options for each resource are:
#
# names: a list of names of HTTP resources. See below for a list of
# valid resource names.
#
# compress: set to true to enable HTTP comression for this resource.
#
# additional_resources: Only valid for an 'http' listener. A map of
# additional endpoints which should be loaded via dynamic modules.
#
# Valid resource names are:
#
# client: the client-server API (/_matrix/client), and the synapse admin
# API (/_synapse/admin). Also implies 'media' and 'static'.
#
# consent: user consent forms (/_matrix/consent). See
# docs/consent_tracking.md.
#
# federation: the server-server API (/_matrix/federation). Also implies
# 'media', 'keys', 'openid'
#
# keys: the key discovery API (/_matrix/keys).
#
# media: the media API (/_matrix/media).
#
# metrics: the metrics interface. See docs/metrics-howto.rst.
#
# openid: OpenID authentication.
#
# replication: the HTTP replication API (/_synapse/replication). See
# docs/workers.rst.
#
# static: static resources under synapse/static (/_matrix/static). (Mostly
# useful for 'fallback authentication'.)
#
# webclient: A web client. Requires web_client_location to be set.
#
listeners:
# TLS-enabled listener: for when matrix traffic is sent directly to synapse.
#
# Disabled by default. To enable it, uncomment the following. (Note that you
# will also need to give Synapse a TLS key and certificate: see the TLS section
# below.)
#
#- port: 8448
# type: http
# tls: true
# resources:
# - names: [client, federation]
# Unsecure HTTP listener: for when matrix traffic passes through a reverse proxy
# that unwraps TLS.
#
# If you plan to use a reverse proxy, please see
# https://github.com/matrix-org/synapse/blob/master/docs/reverse_proxy.rst.
#
- port: 8008
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
# example additional_resources:
#
#additional_resources:
# "/_matrix/my/custom/endpoint":
# module: my_module.CustomRequestHandler
# config: {}
# Turn on the twisted ssh manhole service on localhost on the given
# port.
#
#- port: 9000
# bind_addresses: ['::1', '127.0.0.1']
# type: manhole
## Homeserver blocking ##
# How to reach the server admin, used in ResourceLimitError
#
#admin_contact: 'mailto:admin@server.com'
# Global blocking
#
#hs_disabled: False
#hs_disabled_message: 'Human readable reason for why the HS is blocked'
#hs_disabled_limit_type: 'error code(str), to help clients decode reason'
# Monthly Active User Blocking
#
# Used in cases where the admin or server owner wants to limit to the
# number of monthly active users.
#
# 'limit_usage_by_mau' disables/enables monthly active user blocking. When
# anabled and a limit is reached the server returns a 'ResourceLimitError'
# with error type Codes.RESOURCE_LIMIT_EXCEEDED
#
# 'max_mau_value' is the hard limit of monthly active users above which
# the server will start blocking user actions.
#
# 'mau_trial_days' is a means to add a grace period for active users. It
# means that users must be active for this number of days before they
# can be considered active and guards against the case where lots of users
# sign up in a short space of time never to return after their initial
# session.
#
#limit_usage_by_mau: False
#max_mau_value: 50
#mau_trial_days: 2
# If enabled, the metrics for the number of monthly active users will
# be populated, however no one will be limited. If limit_usage_by_mau
# is true, this is implied to be true.
#
#mau_stats_only: False
# Sometimes the server admin will want to ensure certain accounts are
# never blocked by mau checking. These accounts are specified here.
#
#mau_limit_reserved_threepids:
# - medium: 'email'
# address: 'reserved_user@example.com'
# Used by phonehome stats to group together related servers.
#server_context: context
# Whether to require a user to be in the room to add an alias to it.
# Defaults to 'true'.
#
#require_membership_for_aliases: false
# Whether to allow per-room membership profiles through the send of membership
# events with profile information that differ from the target's global profile.
# Defaults to 'true'.
#
#allow_per_room_profiles: false
## TLS ##
# PEM-encoded X509 certificate for TLS.
# This certificate, as of Synapse 1.0, will need to be a valid and verifiable
# certificate, signed by a recognised Certificate Authority.
#
# See 'ACME support' below to enable auto-provisioning this certificate via
# Let's Encrypt.
#
# If supplying your own, be sure to use a `.pem` file that includes the
# full certificate chain including any intermediate certificates (for
# instance, if using certbot, use `fullchain.pem` as your certificate,
# not `cert.pem`).
#
#tls_certificate_path: "/data/synapse.127.0.0.1.nip.io.tls.crt"
# PEM-encoded private key for TLS
#
#tls_private_key_path: "/data/synapse.127.0.0.1.nip.io.tls.key"
# Whether to verify TLS server certificates for outbound federation requests.
#
# Defaults to `true`. To disable certificate verification, uncomment the
# following line.
#
#federation_verify_certificates: false
# The minimum TLS version that will be used for outbound federation requests.
#
# Defaults to `1`. Configurable to `1`, `1.1`, `1.2`, or `1.3`. Note
# that setting this value higher than `1.2` will prevent federation to most
# of the public Matrix network: only configure it to `1.3` if you have an
# entirely private federation setup and you can ensure TLS 1.3 support.
#
#federation_client_minimum_tls_version: 1.2
# Skip federation certificate verification on the following whitelist
# of domains.
#
# This setting should only be used in very specific cases, such as
# federation over Tor hidden services and similar. For private networks
# of homeservers, you likely want to use a private CA instead.
#
# Only effective if federation_verify_certicates is `true`.
#
#federation_certificate_verification_whitelist:
# - lon.example.com
# - *.domain.com
# - *.onion
# List of custom certificate authorities for federation traffic.
#
# This setting should only normally be used within a private network of
# homeservers.
#
# Note that this list will replace those that are provided by your
# operating environment. Certificates must be in PEM format.
#
#federation_custom_ca_list:
# - myCA1.pem
# - myCA2.pem
# - myCA3.pem
# ACME support: This will configure Synapse to request a valid TLS certificate
# for your configured `server_name` via Let's Encrypt.
#
# Note that provisioning a certificate in this way requires port 80 to be
# routed to Synapse so that it can complete the http-01 ACME challenge.
# By default, if you enable ACME support, Synapse will attempt to listen on
# port 80 for incoming http-01 challenges - however, this will likely fail
# with 'Permission denied' or a similar error.
#
# There are a couple of potential solutions to this:
#
# * If you already have an Apache, Nginx, or similar listening on port 80,
# you can configure Synapse to use an alternate port, and have your web
# server forward the requests. For example, assuming you set 'port: 8009'
# below, on Apache, you would write:
#
# ProxyPass /.well-known/acme-challenge http://localhost:8009/.well-known/acme-challenge
#
# * Alternatively, you can use something like `authbind` to give Synapse
# permission to listen on port 80.
#
acme:
# ACME support is disabled by default. Uncomment the following line
# (and tls_certificate_path and tls_private_key_path above) to enable it.
#
#enabled: true
# Endpoint to use to request certificates. If you only want to test,
# use Let's Encrypt's staging url:
# https://acme-staging.api.letsencrypt.org/directory
#
#url: https://acme-v01.api.letsencrypt.org/directory
# Port number to listen on for the HTTP-01 challenge. Change this if
# you are forwarding connections through Apache/Nginx/etc.
#
#port: 80
# Local addresses to listen on for incoming connections.
# Again, you may want to change this if you are forwarding connections
# through Apache/Nginx/etc.
#
#bind_addresses: ['::', '0.0.0.0']
# How many days remaining on a certificate before it is renewed.
#
#reprovision_threshold: 30
# The domain that the certificate should be for. Normally this
# should be the same as your Matrix domain (i.e., 'server_name'), but,
# by putting a file at 'https://<server_name>/.well-known/matrix/server',
# you can delegate incoming traffic to another server. If you do that,
# you should give the target of the delegation here.
#
# For example: if your 'server_name' is 'example.com', but
# 'https://example.com/.well-known/matrix/server' delegates to
# 'matrix.example.com', you should put 'matrix.example.com' here.
#
# If not set, defaults to your 'server_name'.
#
#domain: matrix.example.com
# file to use for the account key. This will be generated if it doesn't
# exist.
#
# If unspecified, we will use CONFDIR/client.key.
#
account_key_file: /data/acme_account.key
# List of allowed TLS fingerprints for this server to publish along
# with the signing keys for this server. Other matrix servers that
# make HTTPS requests to this server will check that the TLS
# certificates returned by this server match one of the fingerprints.
#
# Synapse automatically adds the fingerprint of its own certificate
# to the list. So if federation traffic is handled directly by synapse
# then no modification to the list is required.
#
# If synapse is run behind a load balancer that handles the TLS then it
# will be necessary to add the fingerprints of the certificates used by
# the loadbalancers to this list if they are different to the one
# synapse is using.
#
# Homeservers are permitted to cache the list of TLS fingerprints
# returned in the key responses up to the "valid_until_ts" returned in
# key. It may be necessary to publish the fingerprints of a new
# certificate and wait until the "valid_until_ts" of the previous key
# responses have passed before deploying it.
#
# You can calculate a fingerprint from a given TLS listener via:
# openssl s_client -connect $host:$port < /dev/null 2> /dev/null |
# openssl x509 -outform DER | openssl sha256 -binary | base64 | tr -d '='
# or by checking matrix.org/federationtester/api/report?server_name=$host
#
#tls_fingerprints: [{"sha256": "<base64_encoded_sha256_fingerprint>"}]
## Database ##
database:
# The database engine name
name: "psycopg2"
args:
user: "synapse"
password: "synapse-password"
database: "homeserver"
host: "postgres"
cp_min: 5
cp_max: 10
# Number of events to cache in memory.
#
#event_cache_size: 10K
## Logging ##
# A yaml python logging config file
#
log_config: "/config/synapse.127.0.0.1.nip.io.log.config"
## Ratelimiting ##
# Ratelimiting settings for client actions (registration, login, messaging).
#
# Each ratelimiting configuration is made of two parameters:
# - per_second: number of requests a client can send per second.
# - burst_count: number of requests a client can send before being throttled.
#
# Synapse currently uses the following configurations:
# - one for messages that ratelimits sending based on the account the client
# is using
# - one for registration that ratelimits registration requests based on the
# client's IP address.
# - one for login that ratelimits login requests based on the client's IP
# address.
# - one for login that ratelimits login requests based on the account the
# client is attempting to log into.
# - one for login that ratelimits login requests based on the account the
# client is attempting to log into, based on the amount of failed login
# attempts for this account.
#
# The defaults are as shown below.
#
#rc_message:
# per_second: 0.2
# burst_count: 10
#
#rc_registration:
# per_second: 0.17
# burst_count: 3
#
#rc_login:
# address:
# per_second: 0.17
# burst_count: 3
# account:
# per_second: 0.17
# burst_count: 3
# failed_attempts:
# per_second: 0.17
# burst_count: 3
rc_message:
per_second: 100
burst_count: 1000
rc_registration:
per_second: 100
burst_count: 1000
rc_login:
address:
per_second: 100
burst_count: 1000
account:
per_second: 100
burst_count: 1000
failed_attempts:
per_second: 100
burst_count: 1000
# Ratelimiting settings for incoming federation
#
# The rc_federation configuration is made up of the following settings:
# - window_size: window size in milliseconds
# - sleep_limit: number of federation requests from a single server in
# a window before the server will delay processing the request.
# - sleep_delay: duration in milliseconds to delay processing events
# from remote servers by if they go over the sleep limit.
# - reject_limit: maximum number of concurrent federation requests
# allowed from a single server
# - concurrent: number of federation requests to concurrently process
# from a single server
#
# The defaults are as shown below.
#
#rc_federation:
# window_size: 1000
# sleep_limit: 10
# sleep_delay: 500
# reject_limit: 50
# concurrent: 3
# Target outgoing federation transaction frequency for sending read-receipts,
# per-room.
#
# If we end up trying to send out more read-receipts, they will get buffered up
# into fewer transactions.
#
#federation_rr_transactions_per_room_per_second: 50
enable_authenticated_media: true
# Directory where uploaded images and attachments are stored.
#
media_store_path: "/media-store"
# Media storage providers allow media to be stored in different
# locations.
#
#media_storage_providers:
# - module: file_system
# # Whether to write new local files.
# store_local: false
# # Whether to write new remote media
# store_remote: false
# # Whether to block upload requests waiting for write to this
# # provider to complete
# store_synchronous: false
# config:
# directory: /mnt/some/other/directory
# Directory where in-progress uploads are stored.
#
uploads_path: "/tmp"
# The largest allowed upload size in bytes
#
#max_upload_size: 10M
# Maximum number of pixels that will be thumbnailed
#
#max_image_pixels: 32M
# Whether to generate new thumbnails on the fly to precisely match
# the resolution requested by the client. If true then whenever
# a new resolution is requested by the client the server will
# generate a new thumbnail. If false the server will pick a thumbnail
# from a precalculated list.
#
#dynamic_thumbnails: false
# List of thumbnails to precalculate when an image is uploaded.
#
#thumbnail_sizes:
# - width: 32
# height: 32
# method: crop
# - width: 96
# height: 96
# method: crop
# - width: 320
# height: 240
# method: scale
# - width: 640
# height: 480
# method: scale
# - width: 800
# height: 600
# method: scale
# Is the preview URL API enabled?
#
# 'false' by default: uncomment the following to enable it (and specify a
# url_preview_ip_range_blacklist blacklist).
#
#url_preview_enabled: true
# List of IP address CIDR ranges that the URL preview spider is denied
# from accessing. There are no defaults: you must explicitly
# specify a list for URL previewing to work. You should specify any
# internal services in your network that you do not want synapse to try
# to connect to, otherwise anyone in any Matrix room could cause your
# synapse to issue arbitrary GET requests to your internal services,
# causing serious security issues.
#
# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
# listed here, since they correspond to unroutable addresses.)
#
# This must be specified if url_preview_enabled is set. It is recommended that
# you uncomment the following list as a starting point.
#
#url_preview_ip_range_blacklist:
# - '127.0.0.0/8'
# - '10.0.0.0/8'
# - '172.16.0.0/12'
# - '192.168.0.0/16'
# - '100.64.0.0/10'
# - '169.254.0.0/16'
# - '::1/128'
# - 'fe80::/64'
# - 'fc00::/7'
# List of IP address CIDR ranges that the URL preview spider is allowed
# to access even if they are specified in url_preview_ip_range_blacklist.
# This is useful for specifying exceptions to wide-ranging blacklisted
# target IP ranges - e.g. for enabling URL previews for a specific private
# website only visible in your network.
#
#url_preview_ip_range_whitelist:
# - '192.168.1.1'
# Optional list of URL matches that the URL preview spider is
# denied from accessing. You should use url_preview_ip_range_blacklist
# in preference to this, otherwise someone could define a public DNS
# entry that points to a private IP address and circumvent the blacklist.
# This is more useful if you know there is an entire shape of URL that
# you know that will never want synapse to try to spider.
#
# Each list entry is a dictionary of url component attributes as returned
# by urlparse.urlsplit as applied to the absolute form of the URL. See
# https://docs.python.org/2/library/urlparse.html#urlparse.urlsplit
# The values of the dictionary are treated as an filename match pattern
# applied to that component of URLs, unless they start with a ^ in which
# case they are treated as a regular expression match. If all the
# specified component matches for a given list item succeed, the URL is
# blacklisted.
#
#url_preview_url_blacklist:
# # blacklist any URL with a username in its URI
# - username: '*'
#
# # blacklist all *.google.com URLs
# - netloc: 'google.com'
# - netloc: '*.google.com'
#
# # blacklist all plain HTTP URLs
# - scheme: 'http'
#
# # blacklist http(s)://www.acme.com/foo
# - netloc: 'www.acme.com'
# path: '/foo'
#
# # blacklist any URL with a literal IPv4 address
# - netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
# The largest allowed URL preview spidering size in bytes
#
#max_spider_size: 10M
## Captcha ##
# See docs/CAPTCHA_SETUP for full details of configuring this.
# This Home Server's ReCAPTCHA public key.
#
#recaptcha_public_key: "YOUR_PUBLIC_KEY"
# This Home Server's ReCAPTCHA private key.
#
#recaptcha_private_key: "YOUR_PRIVATE_KEY"
# Enables ReCaptcha checks when registering, preventing signup
# unless a captcha is answered. Requires a valid ReCaptcha
# public/private key.
#
#enable_registration_captcha: false
# A secret key used to bypass the captcha test entirely.
#
#captcha_bypass_secret: "YOUR_SECRET_HERE"
# The API endpoint to use for verifying m.login.recaptcha responses.
#
#recaptcha_siteverify_api: "https://www.recaptcha.net/recaptcha/api/siteverify"
## TURN ##
# The public URIs of the TURN server to give to clients
#
#turn_uris: []
# The shared secret used to compute passwords for the TURN server
#
#turn_shared_secret: "YOUR_SHARED_SECRET"
# The Username and password if the TURN server needs them and
# does not use a token
#
#turn_username: "TURNSERVER_USERNAME"
#turn_password: "TURNSERVER_PASSWORD"
# How long generated TURN credentials last
#
#turn_user_lifetime: 1h
# Whether guests should be allowed to use the TURN server.
# This defaults to True, otherwise VoIP will be unreliable for guests.
# However, it does introduce a slight security risk as it allows users to
# connect to arbitrary endpoints without having first signed up for a
# valid account (e.g. by passing a CAPTCHA).
#
#turn_allow_guests: True
## Registration ##
#
# Registration can be rate-limited using the parameters in the "Ratelimiting"
# section of this file.
# Enable registration for new users.
#
enable_registration: true
# Optional account validity configuration. This allows for accounts to be denied
# any request after a given period.
#
# ``enabled`` defines whether the account validity feature is enabled. Defaults
# to False.
#
# ``period`` allows setting the period after which an account is valid
# after its registration. When renewing the account, its validity period
# will be extended by this amount of time. This parameter is required when using
# the account validity feature.
#
# ``renew_at`` is the amount of time before an account's expiry date at which
# Synapse will send an email to the account's email address with a renewal link.
# This needs the ``email`` and ``public_baseurl`` configuration sections to be
# filled.
#
# ``renew_email_subject`` is the subject of the email sent out with the renewal
# link. ``%(app)s`` can be used as a placeholder for the ``app_name`` parameter
# from the ``email`` section.
#
# Once this feature is enabled, Synapse will look for registered users without an
# expiration date at startup and will add one to every account it found using the
# current settings at that time.
# This means that, if a validity period is set, and Synapse is restarted (it will
# then derive an expiration date from the current validity period), and some time
# after that the validity period changes and Synapse is restarted, the users'
# expiration dates won't be updated unless their account is manually renewed. This
# date will be randomly selected within a range [now + period - d ; now + period],
# where d is equal to 10% of the validity period.
#
#account_validity:
# enabled: True
# period: 6w
# renew_at: 1w
# renew_email_subject: "Renew your %(app)s account"
# Time that a user's session remains valid for, after they log in.
#
# Note that this is not currently compatible with guest logins.
#
# Note also that this is calculated at login time: changes are not applied
# retrospectively to users who have already logged in.
#
# By default, this is infinite.
#
#session_lifetime: 24h
# The user must provide all of the below types of 3PID when registering.
#
#registrations_require_3pid:
# - email
# - msisdn
# Explicitly disable asking for MSISDNs from the registration
# flow (overrides registrations_require_3pid if MSISDNs are set as required)
#
#disable_msisdn_registration: true
# Mandate that users are only allowed to associate certain formats of
# 3PIDs with accounts on this server.
#
#allowed_local_3pids:
# - medium: email
# pattern: '.*@matrix\.org'
# - medium: email
# pattern: '.*@vector\.im'
# - medium: msisdn
# pattern: '\+44'
# Enable 3PIDs lookup requests to identity servers from this server.
#
#enable_3pid_lookup: true
registration_requires_token: true
# If set, allows registration of standard or admin accounts by anyone who
# has the shared secret, even if registration is otherwise disabled.
#
registration_shared_secret: "y4aTYam;zxKZ#MnaHRrGDPs4&dS*3VEv_&Ck_;pe1=CrtM8*
gitextract_wac8c_3x/
├── .dockerignore
├── .editorconfig
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── publish.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CHANGELOG.md
├── Cargo.toml
├── Dockerfile
├── Dockerfile.ci
├── LICENSE
├── README.md
├── docs/
│ ├── README.md
│ ├── access.md
│ ├── agents.md
│ ├── configuration/
│ │ ├── README.md
│ │ ├── authentication.md
│ │ ├── handlers.md
│ │ ├── image-generation.md
│ │ ├── speech-to-text.md
│ │ ├── text-generation.md
│ │ └── text-to-speech.md
│ ├── development.md
│ ├── features.md
│ ├── installation.md
│ ├── providers.md
│ ├── sample-provider-configs/
│ │ ├── anthropic.yml
│ │ ├── groq.yml
│ │ ├── localai.yml
│ │ ├── mistral.yml
│ │ ├── ollama.yml
│ │ ├── openai-compatible.yml
│ │ ├── openai.yml
│ │ ├── openrouter.yml
│ │ └── together-ai.yml
│ └── usage.md
├── etc/
│ ├── app/
│ │ └── config.yml.dist
│ ├── assets/
│ │ └── baibot.xcf
│ └── services/
│ ├── continuwuity/
│ │ ├── compose.yml
│ │ ├── config/
│ │ │ └── continuwuity.toml
│ │ └── register-user.sh
│ ├── element-web/
│ │ ├── compose.yml
│ │ └── config.json.dist
│ ├── env.dist
│ ├── localai/
│ │ └── compose.yml
│ ├── ollama/
│ │ └── compose.yml
│ └── synapse/
│ ├── compose.yml
│ └── config/
│ ├── homeserver.yaml
│ ├── synapse.127.0.0.1.nip.io.log.config
│ └── synapse.127.0.0.1.nip.io.signing.key
├── justfile
├── mise.toml
├── renovate.json
├── rust-toolchain.toml
└── src/
├── agent/
│ ├── definition.rs
│ ├── identifier.rs
│ ├── instantiation.rs
│ ├── manager.rs
│ ├── mod.rs
│ ├── provider/
│ │ ├── anthropic/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── config.rs
│ │ ├── controller.rs
│ │ ├── entity/
│ │ │ ├── agent_provider.rs
│ │ │ ├── image.rs
│ │ │ ├── mod.rs
│ │ │ ├── ping.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation/
│ │ │ │ ├── mod.rs
│ │ │ │ └── prompt_variables.rs
│ │ │ └── text_to_speech.rs
│ │ ├── groq/
│ │ │ └── mod.rs
│ │ ├── localai/
│ │ │ └── mod.rs
│ │ ├── mistral/
│ │ │ └── mod.rs
│ │ ├── mod.rs
│ │ ├── ollama/
│ │ │ └── mod.rs
│ │ ├── openai/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── openai_compat/
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ ├── mod.rs
│ │ │ └── utils.rs
│ │ ├── openrouter/
│ │ │ └── mod.rs
│ │ └── togetherai/
│ │ └── mod.rs
│ ├── purpose.rs
│ └── utils.rs
├── bot/
│ ├── implementation.rs
│ ├── load_config.rs
│ ├── messaging.rs
│ ├── mod.rs
│ ├── reacting.rs
│ └── rooms.rs
├── controller/
│ ├── access/
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── dispatching.rs
│ │ ├── help.rs
│ │ ├── mod.rs
│ │ ├── room_local_agent_managers.rs
│ │ └── users.rs
│ ├── agent/
│ │ ├── create/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── delete/
│ │ │ └── mod.rs
│ │ ├── details/
│ │ │ └── mod.rs
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── help/
│ │ │ └── mod.rs
│ │ ├── list/
│ │ │ └── mod.rs
│ │ └── mod.rs
│ ├── cfg/
│ │ ├── common/
│ │ │ ├── generic_setting.rs
│ │ │ └── mod.rs
│ │ ├── controller_type.rs
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text/
│ │ │ │ ├── mod.rs
│ │ │ │ └── tests.rs
│ │ │ ├── tests.rs
│ │ │ ├── text_generation/
│ │ │ │ ├── mod.rs
│ │ │ │ └── tests.rs
│ │ │ └── text_to_speech/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── dispatching/
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation.rs
│ │ │ └── text_to_speech.rs
│ │ ├── global_config/
│ │ │ ├── generic_setting.rs
│ │ │ ├── handler.rs
│ │ │ └── mod.rs
│ │ ├── help.rs
│ │ ├── mod.rs
│ │ ├── room_config/
│ │ │ ├── generic_setting.rs
│ │ │ ├── handler.rs
│ │ │ └── mod.rs
│ │ └── status.rs
│ ├── chat_completion/
│ │ └── mod.rs
│ ├── controller_type.rs
│ ├── determination/
│ │ ├── mod.rs
│ │ └── tests.rs
│ ├── dispatching.rs
│ ├── help/
│ │ └── mod.rs
│ ├── image/
│ │ ├── determination/
│ │ │ ├── mod.rs
│ │ │ └── tests.rs
│ │ ├── edit.rs
│ │ ├── generation.rs
│ │ ├── mod.rs
│ │ └── prompt.rs
│ ├── join/
│ │ └── mod.rs
│ ├── mod.rs
│ ├── provider/
│ │ └── mod.rs
│ ├── reaction/
│ │ ├── mod.rs
│ │ └── text_to_speech.rs
│ ├── usage/
│ │ └── mod.rs
│ └── utils/
│ ├── agent.rs
│ ├── mod.rs
│ └── text_to_speech.rs
├── conversation/
│ ├── llm/
│ │ ├── entity.rs
│ │ ├── mod.rs
│ │ ├── tests.rs
│ │ ├── tokenization.rs
│ │ └── utils.rs
│ ├── matrix/
│ │ ├── entity.rs
│ │ ├── mod.rs
│ │ ├── room_display_name_fetcher.rs
│ │ ├── room_event_fetcher.rs
│ │ └── utils/
│ │ ├── mod.rs
│ │ └── tests.rs
│ ├── matrix_llm_bridge.rs
│ └── mod.rs
├── entity/
│ ├── catch_up_marker/
│ │ ├── delayed_catch_up_marker_manager.rs
│ │ ├── entity.rs
│ │ └── mod.rs
│ ├── cfg/
│ │ ├── config.rs
│ │ ├── config_tests.rs
│ │ ├── defaults.rs
│ │ ├── env.rs
│ │ └── mod.rs
│ ├── globalconfig/
│ │ ├── entity.rs
│ │ └── mod.rs
│ ├── interaction_context.rs
│ ├── message_context.rs
│ ├── message_payload.rs
│ ├── mod.rs
│ ├── room_config_context.rs
│ ├── roomconfig/
│ │ ├── defaults.rs
│ │ ├── entity/
│ │ │ ├── handler.rs
│ │ │ ├── mod.rs
│ │ │ ├── speech_to_text.rs
│ │ │ ├── text_generation.rs
│ │ │ └── text_to_speech.rs
│ │ └── mod.rs
│ └── trigger_event_info.rs
├── lib.rs
├── main.rs
├── strings/
│ ├── access.rs
│ ├── agent.rs
│ ├── cfg.rs
│ ├── error.rs
│ ├── global_config.rs
│ ├── help/
│ │ ├── access.rs
│ │ ├── agent.rs
│ │ ├── cfg.rs
│ │ ├── mod.rs
│ │ ├── provider.rs
│ │ └── usage.rs
│ ├── image_edit.rs
│ ├── image_generation.rs
│ ├── introduction.rs
│ ├── mod.rs
│ ├── provider.rs
│ ├── room_config.rs
│ ├── speech_to_text.rs
│ ├── text_to_speech.rs
│ └── usage.rs
└── utils/
├── base64.rs
├── mime.rs
├── mod.rs
├── status.rs
├── text.rs
└── text_to_speech.rs
SYMBOL INDEX (914 symbols across 151 files)
FILE: src/agent/definition.rs
function serialize_provider_to_string (line 7) | pub fn serialize_provider_to_string<S>(
function deserialize_provider_from_string (line 18) | pub fn deserialize_provider_from_string<'de, D>(deserializer: D) -> Resu...
type AgentDefinition (line 27) | pub struct AgentDefinition {
method new (line 40) | pub fn new(id: String, provider: AgentProvider, config: serde_yaml_ng:...
method eq (line 50) | fn eq(&self, other: &Self) -> bool {
FILE: src/agent/identifier.rs
type PublicIdentifier (line 4) | pub enum PublicIdentifier {
method from_str (line 11) | pub fn from_str(s: &str) -> Option<Self> {
method as_string (line 22) | pub fn as_string(&self) -> String {
method prefixless (line 30) | pub fn prefixless(&self) -> String {
method validate (line 38) | pub fn validate(&self) -> Result<(), String> {
method fmt (line 60) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function test_public_identifier_from_str (line 70) | fn test_public_identifier_from_str() {
function test_public_identifier_as_string (line 87) | fn test_public_identifier_as_string() {
FILE: src/agent/instantiation.rs
type Error (line 10) | pub enum Error {
type Result (line 21) | pub type Result<T> = std::result::Result<T, Error>;
type AgentInstance (line 24) | pub struct AgentInstance {
method new (line 31) | pub fn new(
method identifier (line 43) | pub fn identifier(&self) -> &PublicIdentifier {
method definition (line 47) | pub fn definition(&self) -> &AgentDefinition {
method controller (line 51) | pub fn controller(&self) -> &ControllerType {
function create (line 56) | pub(super) fn create(
function create_from_provider_and_yaml_value_config (line 69) | pub fn create_from_provider_and_yaml_value_config(
function create_controller_from_provider_and_json_value_config (line 79) | fn create_controller_from_provider_and_json_value_config(
function default_config_for_provider (line 115) | pub fn default_config_for_provider(provider: &AgentProvider) -> serde_ya...
FILE: src/agent/manager.rs
type Manager (line 8) | pub struct Manager {
method new (line 13) | pub fn new(static_agent_definitions: Vec<AgentDefinition>) -> anyhow::...
method available_room_agents_by_room_config_context (line 34) | pub fn available_room_agents_by_room_config_context(
FILE: src/agent/mod.rs
function default_prompt (line 23) | pub(super) fn default_prompt() -> &'static str {
FILE: src/agent/provider/anthropic/config.rs
type Config (line 6) | pub struct Config {
method default (line 15) | fn default() -> Self {
method validate (line 25) | fn validate(&self) -> Result<(), String> {
type TextGenerationConfig (line 41) | pub struct TextGenerationConfig {
method default (line 59) | fn default() -> Self {
function default_text_model_id (line 70) | fn default_text_model_id() -> String {
FILE: src/agent/provider/anthropic/controller.rs
type ControllerInner (line 24) | struct ControllerInner {
type Controller (line 29) | pub struct Controller {
method new (line 43) | pub fn new(config: Config) -> anyhow::Result<Self> {
method fmt (line 35) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method ping (line 67) | async fn ping(&self) -> anyhow::Result<PingResult> {
method generate_text (line 87) | async fn generate_text(
method speech_to_text (line 198) | async fn speech_to_text(
method generate_image (line 207) | async fn generate_image(
method create_image_edit (line 215) | async fn create_image_edit(
method text_to_speech (line 224) | async fn text_to_speech(
method supports_purpose (line 232) | fn supports_purpose(&self, purpose: AgentPurpose) -> bool {
method text_generation_model_id (line 242) | fn text_generation_model_id(&self) -> Option<String> {
method text_generation_prompt (line 249) | fn text_generation_prompt(&self) -> Option<String> {
method text_generation_temperature (line 256) | fn text_generation_temperature(&self) -> Option<f32> {
method text_to_speech_voice (line 263) | fn text_to_speech_voice(&self) -> Option<String> {
method text_to_speech_speed (line 267) | fn text_to_speech_speed(&self) -> Option<f32> {
FILE: src/agent/provider/anthropic/mod.rs
function create_controller_from_yaml_value_config (line 13) | pub fn create_controller_from_yaml_value_config(
function default_config (line 41) | pub fn default_config() -> Config {
FILE: src/agent/provider/anthropic/utils.rs
function create_anthropic_message_request (line 9) | pub(super) fn create_anthropic_message_request(llm_messages: Vec<LLMMess...
FILE: src/agent/provider/config.rs
type ConfigTrait (line 1) | pub trait ConfigTrait {
method validate (line 2) | fn validate(&self) -> Result<(), String>;
FILE: src/agent/provider/controller.rs
type ControllerTrait (line 11) | pub trait ControllerTrait {
method supports_purpose (line 12) | fn supports_purpose(&self, purpose: AgentPurpose) -> bool;
method ping (line 14) | fn ping(&self) -> impl std::future::Future<Output = anyhow::Result<Pin...
method text_generation_model_id (line 16) | fn text_generation_model_id(&self) -> Option<String>;
method text_generation_prompt (line 18) | fn text_generation_prompt(&self) -> Option<String>;
method text_generation_temperature (line 20) | fn text_generation_temperature(&self) -> Option<f32>;
method text_to_speech_voice (line 22) | fn text_to_speech_voice(&self) -> Option<String>;
method text_to_speech_speed (line 24) | fn text_to_speech_speed(&self) -> Option<f32>;
method generate_text (line 26) | fn generate_text(
method speech_to_text (line 32) | fn speech_to_text(
method generate_image (line 39) | fn generate_image(
method create_image_edit (line 45) | fn create_image_edit(
method text_to_speech (line 52) | fn text_to_speech(
method supports_purpose (line 67) | fn supports_purpose(&self, purpose: AgentPurpose) -> bool {
method text_generation_model_id (line 75) | fn text_generation_model_id(&self) -> Option<String> {
method text_generation_prompt (line 83) | fn text_generation_prompt(&self) -> Option<String> {
method text_to_speech_voice (line 91) | fn text_to_speech_voice(&self) -> Option<String> {
method text_to_speech_speed (line 99) | fn text_to_speech_speed(&self) -> Option<f32> {
method text_generation_temperature (line 107) | fn text_generation_temperature(&self) -> Option<f32> {
method ping (line 115) | async fn ping(&self) -> anyhow::Result<PingResult> {
method generate_text (line 123) | async fn generate_text(
method speech_to_text (line 141) | async fn speech_to_text(
method generate_image (line 160) | async fn generate_image(
method create_image_edit (line 176) | async fn create_image_edit(
method text_to_speech (line 195) | async fn text_to_speech(
type ControllerType (line 60) | pub enum ControllerType {
FILE: src/agent/provider/entity/agent_provider.rs
type AgentProvider (line 4) | pub enum AgentProvider {
method choices (line 17) | pub fn choices() -> Vec<&'static Self> {
method to_static_str (line 31) | pub fn to_static_str(&self) -> &'static str {
method from_string (line 45) | pub fn from_string(s: &str) -> Result<Self, &'static str> {
method info (line 60) | pub fn info(&self) -> AgentProviderInfo {
method fmt (line 189) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type AgentProviderInfo (line 194) | pub struct AgentProviderInfo {
FILE: src/agent/provider/entity/image.rs
type ImageGenerationParams (line 4) | pub struct ImageGenerationParams {
method with_smallest_size_possible (line 13) | pub fn with_smallest_size_possible(mut self, value: bool) -> Self {
method with_cheaper_model_switching_allowed (line 18) | pub fn with_cheaper_model_switching_allowed(mut self, value: bool) -> ...
method with_cheaper_quality_switching_allowed (line 23) | pub fn with_cheaper_quality_switching_allowed(mut self, value: bool) -...
type ImageGenerationResult (line 29) | pub struct ImageGenerationResult {
type ImageEditParams (line 36) | pub struct ImageEditParams {}
type ImageEditResult (line 38) | pub struct ImageEditResult {
type ImageSource (line 43) | pub struct ImageSource {
method new (line 50) | pub fn new(filename: String, bytes: Vec<u8>, mime_type: mime::Mime) ->...
function from (line 60) | fn from(value: ImageSource) -> Self {
FILE: src/agent/provider/entity/ping.rs
type PingResult (line 1) | pub enum PingResult {
FILE: src/agent/provider/entity/speech_to_text.rs
type SpeechToTextParams (line 2) | pub struct SpeechToTextParams {
type SpeechToTextResult (line 6) | pub struct SpeechToTextResult {
FILE: src/agent/provider/entity/text_generation/mod.rs
type TextGenerationParams (line 6) | pub struct TextGenerationParams {
type TextGenerationResult (line 13) | pub struct TextGenerationResult {
FILE: src/agent/provider/entity/text_generation/prompt_variables.rs
type TextGenerationPromptVariables (line 4) | pub struct TextGenerationPromptVariables {
method new (line 16) | pub fn new(
method format (line 41) | pub fn format(&self, text: &str) -> String {
method default (line 9) | fn default() -> Self {
function format_utc_time (line 53) | fn format_utc_time(time: DateTime<Utc>) -> String {
function test_new (line 63) | fn test_new() {
FILE: src/agent/provider/entity/text_to_speech.rs
type TextToSpeechParams (line 2) | pub struct TextToSpeechParams {
type TextToSpeechResult (line 7) | pub struct TextToSpeechResult {
FILE: src/agent/provider/groq/mod.rs
function default_config (line 5) | pub fn default_config() -> Config {
FILE: src/agent/provider/localai/mod.rs
function default_config (line 6) | pub fn default_config() -> Config {
FILE: src/agent/provider/mistral/mod.rs
function default_config (line 5) | pub fn default_config() -> Config {
FILE: src/agent/provider/mod.rs
function default_temperature (line 14) | fn default_temperature() -> f32 {
FILE: src/agent/provider/ollama/mod.rs
function default_config (line 6) | pub fn default_config() -> Config {
FILE: src/agent/provider/openai/config.rs
type Config (line 7) | pub struct Config {
method default (line 26) | fn default() -> Self {
method validate (line 39) | fn validate(&self) -> Result<(), String> {
type TextGenerationConfig (line 49) | pub struct TextGenerationConfig {
method default (line 73) | fn default() -> Self {
function default_text_model_id (line 86) | fn default_text_model_id() -> String {
type ToolsConfig (line 91) | pub struct ToolsConfig {
type SpeechToTextConfig (line 100) | pub struct SpeechToTextConfig {
method default (line 106) | fn default() -> Self {
function default_speech_to_text_model_id (line 113) | fn default_speech_to_text_model_id() -> String {
type TextToSpeechConfig (line 118) | pub struct TextToSpeechConfig {
method default (line 133) | fn default() -> Self {
function default_text_to_speech_model_id (line 143) | fn default_text_to_speech_model_id() -> async_openai::types::audio::Spee...
function default_text_to_speech_voice (line 147) | fn default_text_to_speech_voice() -> async_openai::types::audio::Voice {
function default_text_to_speech_speed (line 151) | fn default_text_to_speech_speed() -> f32 {
function default_text_to_speech_response_format (line 155) | fn default_text_to_speech_response_format() -> async_openai::types::audi...
type ImageGenerationConfig (line 162) | pub struct ImageGenerationConfig {
method model_id_as_openai_image_model (line 187) | pub fn model_id_as_openai_image_model(
method default (line 176) | fn default() -> Self {
function default_image_style (line 203) | fn default_image_style() -> Option<async_openai::types::images::ImageSty...
function default_image_size (line 207) | fn default_image_size() -> Option<async_openai::types::images::ImageSize> {
function default_image_quality (line 211) | fn default_image_quality() -> Option<async_openai::types::images::ImageQ...
FILE: src/agent/provider/openai/controller.rs
type Controller (line 45) | pub struct Controller {
method new (line 51) | pub fn new(config: Config) -> Self {
method ping (line 63) | async fn ping(&self) -> anyhow::Result<PingResult> {
method generate_text (line 83) | async fn generate_text(
method speech_to_text (line 207) | async fn speech_to_text(
method generate_image (line 249) | async fn generate_image(
method create_image_edit (line 385) | async fn create_image_edit(
method text_to_speech (line 487) | async fn text_to_speech(
method supports_purpose (line 552) | fn supports_purpose(&self, purpose: AgentPurpose) -> bool {
method text_generation_model_id (line 562) | fn text_generation_model_id(&self) -> Option<String> {
method text_generation_prompt (line 569) | fn text_generation_prompt(&self) -> Option<String> {
method text_generation_temperature (line 576) | fn text_generation_temperature(&self) -> Option<f32> {
method text_to_speech_voice (line 583) | fn text_to_speech_voice(&self) -> Option<String> {
method text_to_speech_speed (line 593) | fn text_to_speech_speed(&self) -> Option<f32> {
function response_format_to_mime_type (line 602) | fn response_format_to_mime_type(
function audio_mime_type_to_file_name (line 623) | fn audio_mime_type_to_file_name(mime_type: &mxlink::mime::Mime) -> Optio...
function get_sticker_size (line 641) | fn get_sticker_size(model: &ImageModel) -> async_openai::types::images::...
FILE: src/agent/provider/openai/mod.rs
constant OPENAI_IMAGE_MODEL_GPT_IMAGE_1_DOT_5 (line 19) | pub const OPENAI_IMAGE_MODEL_GPT_IMAGE_1_DOT_5: &str = "gpt-image-1.5";
function create_controller_from_yaml_value_config (line 21) | pub fn create_controller_from_yaml_value_config(
function default_config (line 46) | pub fn default_config() -> Config {
FILE: src/agent/provider/openai/utils.rs
function convert_llm_messages_to_openai_response_input (line 11) | pub fn convert_llm_messages_to_openai_response_input(
FILE: src/agent/provider/openai_compat/config.rs
type Config (line 16) | pub struct Config {
method default (line 35) | fn default() -> Self {
method validate (line 48) | fn validate(&self) -> Result<(), String> {
type TextGenerationConfig (line 58) | pub struct TextGenerationConfig {
type Error (line 88) | type Error = anyhow::Error;
method try_into (line 90) | fn try_into(self) -> Result<OpenAITextGenerationConfig, Self::Error> {
method default (line 76) | fn default() -> Self {
function default_text_model_id (line 103) | fn default_text_model_id() -> String {
type SpeechToTextConfig (line 108) | pub struct SpeechToTextConfig {
type Error (line 122) | type Error = anyhow::Error;
method try_into (line 124) | fn try_into(self) -> Result<OpenAISpeechToTextConfig, Self::Error> {
method default (line 114) | fn default() -> Self {
function default_speech_to_text_model_id (line 131) | fn default_speech_to_text_model_id() -> String {
type TextToSpeechConfig (line 136) | pub struct TextToSpeechConfig {
type Error (line 162) | type Error = String;
method try_into (line 164) | fn try_into(self) -> Result<OpenAITextToSpeechConfig, Self::Error> {
method default (line 151) | fn default() -> Self {
function default_text_to_speech_model_id (line 183) | fn default_text_to_speech_model_id() -> String {
function default_text_to_speech_voice (line 187) | fn default_text_to_speech_voice() -> String {
function default_text_to_speech_speed (line 191) | fn default_text_to_speech_speed() -> f32 {
function default_text_to_speech_response_format (line 195) | fn default_text_to_speech_response_format() -> String {
type ImageGenerationConfig (line 200) | pub struct ImageGenerationConfig {
type Error (line 225) | type Error = String;
method try_into (line 227) | fn try_into(self) -> Result<OpenAIImageGenerationConfig, Self::Error> {
method default (line 214) | fn default() -> Self {
function default_image_style (line 261) | fn default_image_style() -> Option<String> {
function default_image_size (line 265) | fn default_image_size() -> Option<String> {
function default_image_quality (line 269) | fn default_image_quality() -> Option<String> {
FILE: src/agent/provider/openai_compat/controller.rs
constant SMALLEST_IMAGE_SIZE (line 6) | const SMALLEST_IMAGE_SIZE: &str = "256x256";
type Controller (line 35) | pub struct Controller {
method new (line 41) | pub fn new(config: Config) -> Self {
method ping (line 60) | async fn ping(&self) -> anyhow::Result<PingResult> {
method generate_text (line 80) | async fn generate_text(
method speech_to_text (line 210) | async fn speech_to_text(
method generate_image (line 293) | async fn generate_image(
method create_image_edit (line 377) | async fn create_image_edit(
method text_to_speech (line 388) | async fn text_to_speech(
method supports_purpose (line 427) | fn supports_purpose(&self, purpose: AgentPurpose) -> bool {
method text_generation_model_id (line 437) | fn text_generation_model_id(&self) -> Option<String> {
method text_generation_prompt (line 444) | fn text_generation_prompt(&self) -> Option<String> {
method text_generation_temperature (line 451) | fn text_generation_temperature(&self) -> Option<f32> {
method text_to_speech_voice (line 458) | fn text_to_speech_voice(&self) -> Option<String> {
method text_to_speech_speed (line 468) | fn text_to_speech_speed(&self) -> Option<f32> {
FILE: src/agent/provider/openai_compat/mod.rs
function create_controller_from_yaml_value_config (line 27) | pub fn create_controller_from_yaml_value_config(
function default_config (line 54) | pub fn default_config() -> Config {
FILE: src/agent/provider/openai_compat/utils.rs
function convert_llm_messages_to_openai_messages (line 9) | pub fn convert_llm_messages_to_openai_messages(
function convert_llm_message_to_openai_message (line 25) | fn convert_llm_message_to_openai_message(llm_message: LLMMessage) -> Opt...
function convert_config_to_openai_config_lossy (line 52) | pub(super) fn convert_config_to_openai_config_lossy(config: &super::Conf...
function convert_string_to_enum (line 83) | pub(super) fn convert_string_to_enum<T>(value: &str) -> Result<T, String>
FILE: src/agent/provider/openrouter/mod.rs
function default_config (line 3) | pub fn default_config() -> Config {
FILE: src/agent/provider/togetherai/mod.rs
function default_config (line 3) | pub fn default_config() -> Config {
FILE: src/agent/purpose.rs
type AgentPurpose (line 2) | pub enum AgentPurpose {
method from_str (line 11) | pub fn from_str(s: &str) -> Option<Self> {
method as_str (line 22) | pub fn as_str(&self) -> &'static str {
method choices (line 32) | pub fn choices() -> Vec<&'static Self> {
method emoji (line 42) | pub fn emoji(&self) -> &'static str {
method heading (line 52) | pub fn heading(&self) -> &'static str {
method fmt (line 64) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: src/agent/utils.rs
type AgentForPurposeDeterminationInfo (line 10) | pub struct AgentForPurposeDeterminationInfo {
type AgentForPurposeDeterminationInfoConfigurationSource (line 16) | pub enum AgentForPurposeDeterminationInfoConfigurationSource {
type AgentForPurposeDeterminationError (line 22) | pub enum AgentForPurposeDeterminationError {
function get_effective_agent_for_purpose (line 32) | pub async fn get_effective_agent_for_purpose(
function get_effective_room_agent_identifier_for_purpose (line 75) | async fn get_effective_room_agent_identifier_for_purpose(
function get_effective_room_agent_raw_id_for_purpose (line 100) | async fn get_effective_room_agent_raw_id_for_purpose(
function get_global_agent_id_for_purpose (line 131) | async fn get_global_agent_id_for_purpose(
FILE: src/bot/implementation.rs
constant ROOM_EVENT_FETCHER_LRU_CACHE_SIZE (line 36) | const ROOM_EVENT_FETCHER_LRU_CACHE_SIZE: usize = 1000;
constant ROOM_DISPLAY_NAME_FETCHER_LRU_CACHE_SIZE (line 37) | const ROOM_DISPLAY_NAME_FETCHER_LRU_CACHE_SIZE: usize = 1000;
constant ROOM_CONFIG_MANAGER_LRU_CACHE_SIZE (line 38) | const ROOM_CONFIG_MANAGER_LRU_CACHE_SIZE: usize = 1000;
constant LOGO_BYTES (line 40) | const LOGO_BYTES: &[u8] = include_bytes!("../../etc/assets/baibot-torso-...
constant LOGO_MIME_TYPE (line 41) | const LOGO_MIME_TYPE: &str = "image/png";
constant DELAYED_CATCH_UP_MARKER_MANAGER_PERSIST_INTERVAL_DURATION (line 45) | const DELAYED_CATCH_UP_MARKER_MANAGER_PERSIST_INTERVAL_DURATION: std::ti...
constant DELAYED_CATCH_UP_MARKER_MANAGER_FEDERATION_DELAY_TOLERANCE_DURATION (line 51) | const DELAYED_CATCH_UP_MARKER_MANAGER_FEDERATION_DELAY_TOLERANCE_DURATIO...
type BotInner (line 54) | struct BotInner {
type Bot (line 71) | pub struct Bot {
method new (line 76) | pub async fn new(config: Config) -> anyhow::Result<Self> {
method admin_patterns (line 134) | pub(crate) fn admin_patterns(&self) -> &Vec<String> {
method name (line 138) | pub(crate) fn name(&self) -> &str {
method command_prefix (line 142) | pub(crate) fn command_prefix(&self) -> &str {
method post_join_self_introduction_enabled (line 146) | pub(crate) fn post_join_self_introduction_enabled(&self) -> bool {
method homeserver_name (line 150) | pub(crate) fn homeserver_name(&self) -> &str {
method global_config_manager (line 154) | pub(crate) fn global_config_manager(&self) -> &tokio::sync::Mutex<Glob...
method room_config_manager (line 158) | pub(crate) fn room_config_manager(&self) -> &tokio::sync::Mutex<RoomCo...
method room_event_fetcher (line 162) | pub(crate) fn room_event_fetcher(&self) -> Arc<RoomEventFetcher> {
method room_display_name_fetcher (line 166) | pub(crate) fn room_display_name_fetcher(&self) -> Arc<RoomDisplayNameF...
method agent_manager (line 170) | pub(crate) fn agent_manager(&self) -> &Manager {
method matrix_link (line 174) | pub(crate) fn matrix_link(&self) -> &MatrixLink {
method user_id (line 178) | pub(crate) fn user_id(&self) -> &OwnedUserId {
method user_display_name_in_room (line 182) | pub(crate) async fn user_display_name_in_room(&self, room: &Room) -> O...
method reacting (line 200) | pub(crate) fn reacting(&self) -> super::reacting::Reacting {
method rooms (line 204) | pub(crate) fn rooms(&self) -> super::rooms::Rooms {
method messaging (line 208) | pub(crate) fn messaging(&self) -> super::messaging::Messaging {
method admin_pattern_regexes (line 212) | pub(crate) fn admin_pattern_regexes(&self) -> &Vec<regex::Regex> {
method global_config (line 216) | pub(crate) async fn global_config(&self) -> Result<GlobalConfig, Confi...
method is_caught_up (line 222) | pub(crate) async fn is_caught_up(
method catch_up (line 232) | pub(crate) async fn catch_up(&self, event_origin_server_ts: MilliSecon...
method start_typing_notice (line 239) | pub(crate) async fn start_typing_notice(&self, room: &Room) -> TypingN...
method start (line 247) | pub async fn start(&self) -> anyhow::Result<()> {
method prepare_profile (line 263) | async fn prepare_profile(&self) -> anyhow::Result<()> {
method do_prepare_profile (line 288) | async fn do_prepare_profile(&self) -> anyhow::Result<()> {
function create_matrix_link (line 393) | async fn create_matrix_link(config: &Config) -> anyhow::Result<MatrixLin...
function create_global_configuration_manager (line 435) | pub fn create_global_configuration_manager(
function create_initial_global_config (line 456) | async fn create_initial_global_config(initial_global_config: GlobalConfi...
function create_room_configuration_manager (line 460) | pub fn create_room_configuration_manager(
function create_initial_room_config (line 479) | async fn create_initial_room_config(room: Room) -> RoomConfig {
function create_catch_up_marker_manager (line 483) | pub fn create_catch_up_marker_manager(matrix_link: MatrixLink) -> CatchU...
function create_initial_catch_up_marker (line 504) | async fn create_initial_catch_up_marker() -> CatchUpMarker {
FILE: src/bot/load_config.rs
function load (line 10) | pub fn load() -> anyhow::Result<Config> {
function optional_non_empty (line 132) | fn optional_non_empty(value: String) -> Option<String> {
FILE: src/bot/messaging.rs
type Messaging (line 19) | pub struct Messaging {
method new (line 24) | pub fn new(bot: super::Bot) -> Self {
method send_text_markdown_no_fail (line 28) | pub async fn send_text_markdown_no_fail(
method send_notice_markdown_no_fail (line 55) | pub async fn send_notice_markdown_no_fail(
method send_tooltip_markdown_no_fail (line 82) | pub async fn send_tooltip_markdown_no_fail(
method send_success_markdown_no_fail (line 97) | pub async fn send_success_markdown_no_fail(
method send_error_markdown_no_fail (line 112) | pub async fn send_error_markdown_no_fail(
method redact_event_no_fail (line 127) | pub async fn redact_event_no_fail(
method attach_event_handlers (line 155) | pub(super) async fn attach_event_handlers(&self) {
method on_actionable_message (line 165) | async fn on_actionable_message(
FILE: src/bot/reacting.rs
type Reacting (line 20) | pub struct Reacting {
method new (line 25) | pub fn new(bot: super::Bot) -> Self {
method react_no_fail (line 29) | pub async fn react_no_fail(
method attach_event_handlers (line 57) | pub(super) async fn attach_event_handlers(&self) {
method on_actionable_reaction (line 70) | async fn on_actionable_reaction(
FILE: src/bot/rooms.rs
type Rooms (line 16) | pub struct Rooms {
method new (line 21) | pub fn new(bot: super::Bot) -> Self {
method attach_event_handlers (line 25) | pub(super) async fn attach_event_handlers(&self) {
method on_invitation (line 41) | async fn on_invitation(
method on_joined (line 77) | async fn on_joined(
method on_being_last_member (line 132) | async fn on_being_last_member(
FILE: src/controller/access/determination/mod.rs
type AccessControllerType (line 7) | pub enum AccessControllerType {
function determine_controller (line 17) | pub fn determine_controller(text: &str) -> ControllerType {
FILE: src/controller/access/determination/tests.rs
function determine_controller (line 2) | fn determine_controller() {
FILE: src/controller/access/dispatching.rs
function dispatch_controller (line 7) | pub async fn dispatch_controller(
FILE: src/controller/access/help.rs
function handle (line 5) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
function build_section_intro (line 36) | fn build_section_intro() -> String {
function build_section_joining_rooms (line 46) | fn build_section_joining_rooms() -> String {
function build_section_users (line 60) | fn build_section_users(
function build_section_administrators (line 103) | fn build_section_administrators(admin_patterns: &[String]) -> String {
function build_section_room_local_agent_managers (line 122) | fn build_section_room_local_agent_managers(
FILE: src/controller/access/room_local_agent_managers.rs
function handle_get (line 5) | pub async fn handle_get(bot: &Bot, message_context: &MessageContext) -> ...
function handle_set (line 26) | pub async fn handle_set(
FILE: src/controller/access/users.rs
function handle_get (line 5) | pub async fn handle_get(bot: &Bot, message_context: &MessageContext) -> ...
function handle_set (line 22) | pub async fn handle_set(
FILE: src/controller/agent/create/mod.rs
type ParsedAgentConfig (line 16) | struct ParsedAgentConfig {
function handle_room_local (line 21) | pub async fn handle_room_local(
function handle_global (line 134) | pub async fn handle_global(
function send_guide (line 246) | async fn send_guide(
function parse_from_message_to_yaml_value (line 266) | fn parse_from_message_to_yaml_value(text: &str) -> Result<serde_yaml_ng:...
function parse_agent_config_from_message_or_complain (line 289) | async fn parse_agent_config_from_message_or_complain(
function try_to_ping_agent_or_complain (line 340) | async fn try_to_ping_agent_or_complain(
function send_completion_wrap_up (line 389) | async fn send_completion_wrap_up(
FILE: src/controller/agent/create/tests.rs
function agent_config_parsing_works (line 2) | fn agent_config_parsing_works() {
FILE: src/controller/agent/delete/mod.rs
function handle (line 8) | pub async fn handle(
function delete_room_local_agent (line 89) | async fn delete_room_local_agent(
function delete_global_agent (line 145) | async fn delete_global_agent(
FILE: src/controller/agent/details/mod.rs
function handle (line 5) | pub async fn handle(
FILE: src/controller/agent/determination/mod.rs
type AgentControllerType (line 7) | pub enum AgentControllerType {
function determine_controller (line 16) | pub fn determine_controller(command_prefix: &str, text: &str) -> Control...
FILE: src/controller/agent/determination/tests.rs
function determine_controller (line 2) | fn determine_controller() {
FILE: src/controller/agent/help/mod.rs
function handle (line 5) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
FILE: src/controller/agent/list/mod.rs
function handle (line 7) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
FILE: src/controller/agent/mod.rs
function dispatch_controller (line 12) | pub async fn dispatch_controller(
FILE: src/controller/cfg/common/generic_setting.rs
function handle_get (line 5) | pub async fn handle_get<T>(
FILE: src/controller/cfg/controller_type.rs
type SettingsStorageSource (line 12) | pub enum SettingsStorageSource {
type ConfigControllerType (line 18) | pub enum ConfigControllerType {
type ConfigSettingRelatedControllerType (line 27) | pub enum ConfigSettingRelatedControllerType {
type ConfigTextGenerationSettingRelatedControllerType (line 37) | pub enum ConfigTextGenerationSettingRelatedControllerType {
type ConfigSpeechToTextSettingRelatedControllerType (line 58) | pub enum ConfigSpeechToTextSettingRelatedControllerType {
type ConfigTextToSpeechSettingRelatedControllerType (line 72) | pub enum ConfigTextToSpeechSettingRelatedControllerType {
FILE: src/controller/cfg/determination/mod.rs
function determine_controller (line 18) | pub fn determine_controller(text: &str) -> ControllerType {
function do_determine_controller (line 51) | fn do_determine_controller(
FILE: src/controller/cfg/determination/speech_to_text/mod.rs
function determine (line 14) | pub(super) fn determine(
FILE: src/controller/cfg/determination/speech_to_text/tests.rs
function determine_controller_other (line 2) | fn determine_controller_other() {
function determine_controller_flow_type (line 25) | fn determine_controller_flow_type() {
function determine_controller_language (line 82) | fn determine_controller_language() {
FILE: src/controller/cfg/determination/tests.rs
function determine_controller (line 2) | fn determine_controller() {
FILE: src/controller/cfg/determination/text_generation/mod.rs
function determine (line 15) | pub(super) fn determine(
FILE: src/controller/cfg/determination/text_generation/tests.rs
function determine_controller_other (line 2) | fn determine_controller_other() {
function determine_controller_context_management (line 25) | fn determine_controller_context_management() {
function determine_controller_sender_context (line 94) | fn determine_controller_sender_context() {
function determine_controller_prefix_requirement_type (line 162) | fn determine_controller_prefix_requirement_type() {
function determine_controller_auto_usage (line 232) | fn determine_controller_auto_usage() {
function determine_controller_prompt_override (line 289) | fn determine_controller_prompt_override() {
function determine_controller_temperature_override (line 347) | fn determine_controller_temperature_override() {
FILE: src/controller/cfg/determination/text_to_speech/mod.rs
function determine (line 12) | pub(super) fn determine(
FILE: src/controller/cfg/determination/text_to_speech/tests.rs
function determine_controller_other (line 2) | fn determine_controller_other() {
function determine_controller_bot_msgs_flow_type (line 25) | fn determine_controller_bot_msgs_flow_type() {
function determine_controller_user_msgs_flow_type (line 84) | fn determine_controller_user_msgs_flow_type() {
function determine_controller_speed_override (line 143) | fn determine_controller_speed_override() {
function determine_controller_voice_override (line 197) | fn determine_controller_voice_override() {
FILE: src/controller/cfg/dispatching/mod.rs
function dispatch_controller (line 13) | pub async fn dispatch_controller(
function dispatch_config_related_handler (line 36) | async fn dispatch_config_related_handler(
FILE: src/controller/cfg/dispatching/speech_to_text.rs
function dispatch (line 17) | pub(super) async fn dispatch(
FILE: src/controller/cfg/dispatching/text_generation.rs
function dispatch (line 17) | pub(super) async fn dispatch(
FILE: src/controller/cfg/dispatching/text_to_speech.rs
function dispatch (line 16) | pub(super) async fn dispatch(
FILE: src/controller/cfg/global_config/generic_setting.rs
function handle_set (line 6) | pub async fn handle_set<T>(
FILE: src/controller/cfg/global_config/handler.rs
function handle_get (line 10) | pub async fn handle_get(
function handle_set (line 83) | pub async fn handle_set(
FILE: src/controller/cfg/help.rs
function handle (line 17) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
function build_section_intro (line 57) | fn build_section_intro() -> String {
function build_section_status (line 67) | fn build_section_status(command_prefix: &str) -> String {
function build_section_handlers (line 77) | fn build_section_handlers(command_prefix: &str) -> String {
function build_section_text_generation (line 108) | fn build_section_text_generation(command_prefix: &str, bot_username: &st...
function build_section_speech_to_text (line 347) | fn build_section_speech_to_text(command_prefix: &str) -> String {
function build_section_text_to_speech (line 463) | fn build_section_text_to_speech(command_prefix: &str) -> String {
function build_section_image_generation (line 619) | fn build_section_image_generation() -> String {
FILE: src/controller/cfg/room_config/generic_setting.rs
function handle_set (line 6) | pub async fn handle_set<T>(
FILE: src/controller/cfg/room_config/handler.rs
function handle_get (line 12) | pub async fn handle_get(
function handle_set (line 82) | pub async fn handle_set(
FILE: src/controller/cfg/status.rs
function handle (line 16) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
function generate_room_handlers_section (line 90) | fn generate_room_handlers_section(
function generate_global_config_handlers_section (line 124) | fn generate_global_config_handlers_section(
function generate_handler_line_for_purpose (line 158) | fn generate_handler_line_for_purpose(
function generate_room_agents_section (line 198) | fn generate_room_agents_section(
function generate_text_generation_section (line 242) | async fn generate_text_generation_section(
function generate_speech_to_text_section (line 481) | async fn generate_speech_to_text_section(
function generate_text_to_speech_section (line 597) | async fn generate_text_to_speech_section(
function generate_image_generation_section (line 783) | async fn generate_image_generation_section(
FILE: src/controller/chat_completion/mod.rs
type ChatCompletionControllerType (line 34) | pub enum ChatCompletionControllerType {
type TextToSpeechEligiblePayload (line 52) | struct TextToSpeechEligiblePayload {
type TextToSpeechParams (line 57) | enum TextToSpeechParams {
function handle (line 62) | pub async fn handle(
function handle_stage_speech_to_text (line 307) | async fn handle_stage_speech_to_text(
function handle_stage_text_generation (line 392) | async fn handle_stage_text_generation(
function handle_stage_speech_to_text_actual_transcribing (line 608) | async fn handle_stage_speech_to_text_actual_transcribing(
function send_tts_offer_for_message (line 713) | async fn send_tts_offer_for_message(
function generate_and_send_tts_for_message (line 741) | async fn generate_and_send_tts_for_message(
function inject_sender_context (line 774) | fn inject_sender_context(
function test_inject_sender_context_prefixes_text_messages (line 824) | fn test_inject_sender_context_prefixes_text_messages() {
function test_inject_sender_context_can_prefix_without_timestamp (line 852) | fn test_inject_sender_context_can_prefix_without_timestamp() {
function test_inject_sender_context_prefixes_assistant_messages (line 876) | fn test_inject_sender_context_prefixes_assistant_messages() {
function test_inject_sender_context_skips_prompt_messages (line 904) | fn test_inject_sender_context_skips_prompt_messages() {
function test_inject_sender_context_skips_messages_without_sender_id (line 926) | fn test_inject_sender_context_skips_messages_without_sender_id() {
function test_inject_sender_context_leaves_non_text_content_unchanged (line 950) | fn test_inject_sender_context_leaves_non_text_content_unchanged() {
function test_inject_sender_context_none_leaves_text_unchanged (line 987) | fn test_inject_sender_context_none_leaves_text_unchanged() {
FILE: src/controller/controller_type.rs
type ControllerType (line 2) | pub enum ControllerType {
FILE: src/controller/determination/mod.rs
function determine_controller (line 15) | pub fn determine_controller(
function determine_text_controller (line 82) | fn determine_text_controller(
FILE: src/controller/determination/tests.rs
function determine_text_controller (line 2) | fn determine_text_controller() {
FILE: src/controller/dispatching.rs
function dispatch_controller (line 7) | pub async fn dispatch_controller(
FILE: src/controller/help/mod.rs
function handle (line 5) | pub async fn handle(bot: &Bot, message_context: &MessageContext) -> anyh...
FILE: src/controller/image/determination/mod.rs
function determine_controller (line 4) | pub fn determine_controller(text: &str) -> ControllerType {
FILE: src/controller/image/determination/tests.rs
function determine_controller (line 2) | fn determine_controller() {
FILE: src/controller/image/edit.rs
function handle (line 16) | pub async fn handle(
function send_guide (line 152) | async fn send_guide(bot: &Bot, message_context: &MessageContext) -> anyh...
FILE: src/controller/image/generation.rs
function handle_image (line 15) | pub async fn handle_image(
function handle_sticker (line 147) | pub async fn handle_sticker(
FILE: src/controller/image/prompt.rs
function build (line 9) | pub fn build(original_prompt: &str, other_messages: Vec<Message>) -> Str...
type TestCase (line 45) | struct TestCase {
function test_build_prompt (line 52) | fn test_build_prompt() {
FILE: src/controller/join/mod.rs
function handle (line 6) | pub async fn handle(
FILE: src/controller/provider/mod.rs
function determine_controller (line 7) | pub fn determine_controller(_text: &str) -> ControllerType {
function handle_help (line 11) | pub async fn handle_help(message_context: &MessageContext, bot: &Bot) ->...
FILE: src/controller/reaction/mod.rs
function handle (line 13) | pub async fn handle(
FILE: src/controller/reaction/text_to_speech.rs
function handle (line 16) | pub(super) async fn handle(
function is_allowed_to_tts_for_event (line 73) | fn is_allowed_to_tts_for_event(
FILE: src/controller/usage/mod.rs
function determine_controller (line 7) | pub fn determine_controller(_text: &str) -> ControllerType {
function handle_help (line 11) | pub async fn handle_help(message_context: &MessageContext, bot: &Bot) ->...
FILE: src/controller/utils/agent.rs
function get_effective_agent_for_purpose_or_complain (line 13) | pub async fn get_effective_agent_for_purpose_or_complain(
FILE: src/controller/utils/mod.rs
function get_text_body_or_complain (line 11) | pub async fn get_text_body_or_complain<'a>(
FILE: src/controller/utils/text_to_speech.rs
function generate_and_send_tts_for_message (line 14) | pub async fn generate_and_send_tts_for_message(
function do_generate_and_send_tts_for_message (line 61) | async fn do_generate_and_send_tts_for_message(
FILE: src/conversation/llm/entity.rs
type Author (line 11) | pub enum Author {
type Message (line 18) | pub struct Message {
type ImageDetails (line 26) | pub struct ImageDetails {
method new (line 33) | pub fn new(event_content: ImageMessageEventContent, mime: Mime, data: ...
method filename (line 41) | pub fn filename(&self) -> String {
method from (line 50) | fn from(value: ImageDetails) -> Self {
type FileDetails (line 56) | pub struct FileDetails {
method new (line 63) | pub fn new(event_content: FileMessageEventContent, mime: Mime, data: V...
method filename (line 71) | pub fn filename(&self) -> String {
type MessageContent (line 80) | pub enum MessageContent {
method eq (line 87) | fn eq(&self, other: &Self) -> bool {
type Conversation (line 100) | pub struct Conversation {
method combine_consecutive_messages (line 115) | pub fn combine_consecutive_messages(&self) -> Conversation {
method start_time (line 155) | pub fn start_time(&self) -> Option<DateTime<Utc>> {
function combine_consecutive_messages (line 168) | fn combine_consecutive_messages() {
function combine_consecutive_messages_clears_sender_id_for_mixed_sender_turns (line 292) | fn combine_consecutive_messages_clears_sender_id_for_mixed_sender_turns() {
FILE: src/conversation/llm/tests.rs
function test_messages_by_the_bot_are_identified_correctly (line 9) | fn test_messages_by_the_bot_are_identified_correctly() {
function test_notice_messages_by_bot_with_speech_to_text_prefix_are_cleaned_up_and_considered_sent_by_user (line 31) | fn test_notice_messages_by_bot_with_speech_to_text_prefix_are_cleaned_up...
function test_notice_error_messages_by_bot_are_ignored (line 59) | fn test_notice_error_messages_by_bot_are_ignored() {
function test_user_messages_preserve_sender_id (line 81) | fn test_user_messages_preserve_sender_id() {
function test_other_notice_messages_by_the_bot_are_ignored (line 105) | fn test_other_notice_messages_by_the_bot_are_ignored() {
FILE: src/conversation/llm/tokenization.rs
function get_bpe_for_model (line 7) | fn get_bpe_for_model(model: &str) -> &'static CoreBPE {
function shorten_messages_list_to_context_size (line 15) | pub fn shorten_messages_list_to_context_size(
function calculate_token_size_for_message (line 58) | fn calculate_token_size_for_message(bpe: &CoreBPE, model: &str, message:...
function message_size_counting_works (line 85) | fn message_size_counting_works() {
function shortening_works_with_english (line 103) | fn shortening_works_with_english() {
function shortening_works_with_japanese (line 213) | fn shortening_works_with_japanese() {
FILE: src/conversation/llm/utils.rs
function convert_matrix_message_to_llm_message (line 7) | pub fn convert_matrix_message_to_llm_message(
function convert_bot_message (line 18) | fn convert_bot_message(matrix_message: &MatrixMessage) -> Option<Message> {
function convert_bot_text_message (line 51) | fn convert_bot_text_message(
function convert_bot_notice_message (line 64) | fn convert_bot_notice_message(
function convert_user_message (line 89) | fn convert_user_message(matrix_message: &MatrixMessage) -> Option<Messag...
FILE: src/conversation/matrix/entity.rs
type MatrixMessage (line 11) | pub struct MatrixMessage {
type MatrixMessageContent (line 19) | pub enum MatrixMessageContent {
type MatrixMessageProcessingParams (line 27) | pub struct MatrixMessageProcessingParams {
method new (line 44) | pub fn new(bot_user_id: OwnedUserId, allowed_users: Option<Vec<Regex>>...
method with_bot_user_prefixes_to_strip (line 55) | pub fn with_bot_user_prefixes_to_strip(mut self, value: Vec<String>) -...
method with_first_message_prefixes_to_strip (line 60) | pub fn with_first_message_prefixes_to_strip(mut self, value: Vec<Strin...
FILE: src/conversation/matrix/room_display_name_fetcher.rs
type RoomDisplayNameFetcher (line 7) | pub struct RoomDisplayNameFetcher {
method new (line 13) | pub fn new(matrix_link: MatrixLink, lru_cache_size: Option<usize>) -> ...
method own_display_name_in_room (line 23) | pub async fn own_display_name_in_room(
method get_uncached_value (line 50) | async fn get_uncached_value(&self, room: &Room) -> mxlink::matrix_sdk:...
FILE: src/conversation/matrix/room_event_fetcher.rs
type RoomEventFetcher (line 7) | pub struct RoomEventFetcher {
method new (line 12) | pub fn new(lru_cache_size: Option<usize>) -> Self {
method fetch_event_in_room (line 19) | pub async fn fetch_event_in_room(
FILE: src/conversation/matrix/utils/mod.rs
type DetailedMessagePayload (line 27) | struct DetailedMessagePayload {
function get_matrix_messages_in_thread (line 32) | pub async fn get_matrix_messages_in_thread(
function get_matrix_messages_in_reply_chain (line 57) | pub async fn get_matrix_messages_in_reply_chain(
function get_matrix_messages_in_reply_chain_native (line 81) | async fn get_matrix_messages_in_reply_chain_native(
function process_matrix_messages (line 140) | pub async fn process_matrix_messages(
function is_message_from_allowed_sender (line 198) | fn is_message_from_allowed_sender(
function convert_matrix_native_event_to_matrix_message (line 219) | pub async fn convert_matrix_native_event_to_matrix_message(
function determine_interaction_context_for_room_event (line 383) | pub async fn determine_interaction_context_for_room_event(
function determine_interaction_context_for_room_event_related_to_thread (line 437) | async fn determine_interaction_context_for_room_event_related_to_thread(
function determine_interaction_context_for_room_event_related_to_reply (line 516) | async fn determine_interaction_context_for_room_event_related_to_reply(
function is_event_mentioning_bot (line 540) | fn is_event_mentioning_bot(
function timeline_event_to_detailed_message_payload (line 572) | fn timeline_event_to_detailed_message_payload(
function create_list_of_bot_user_prefixes_to_strip (line 669) | pub fn create_list_of_bot_user_prefixes_to_strip(
FILE: src/conversation/matrix/utils/tests.rs
function is_message_from_allowed_sender (line 10) | fn is_message_from_allowed_sender() {
function process_matrix_messages (line 78) | async fn process_matrix_messages() {
function create_list_of_bot_user_prefixes_to_strip (line 292) | fn create_list_of_bot_user_prefixes_to_strip() {
FILE: src/conversation/matrix_llm_bridge.rs
function create_llm_conversation_for_matrix_thread (line 14) | pub async fn create_llm_conversation_for_matrix_thread(
function create_llm_conversation_for_matrix_reply_chain (line 29) | pub async fn create_llm_conversation_for_matrix_reply_chain(
function filter_messages_and_convert_to_llm_messages (line 46) | async fn filter_messages_and_convert_to_llm_messages(
FILE: src/entity/catch_up_marker/delayed_catch_up_marker_manager.rs
type DelayedCatchUpMarkerManager (line 23) | pub struct DelayedCatchUpMarkerManager {
method new (line 46) | pub fn new(
method catch_up (line 66) | pub async fn catch_up(&self, event_origin_server_ts_millis: i64) {
method is_caught_up (line 95) | pub(crate) async fn is_caught_up(
method start (line 117) | pub async fn start(&self) {
FILE: src/entity/catch_up_marker/entity.rs
type CatchUpMarkerCarrierContent (line 10) | pub struct CatchUpMarkerCarrierContent {
method payload (line 15) | fn payload(&self) -> &str {
method new (line 19) | fn new(payload: String) -> Self {
type CatchUpMarker (line 25) | pub struct CatchUpMarker {
method new (line 30) | pub fn new(caught_up_until_event_origin_server_ts_millis: i64) -> Self {
FILE: src/entity/catch_up_marker/mod.rs
type CatchUpMarkerManager (line 8) | pub type CatchUpMarkerManager =
FILE: src/entity/cfg/config.rs
type Config (line 13) | pub struct Config {
method validate (line 40) | pub fn validate(&self) -> anyhow::Result<()> {
type ConfigUserAuth (line 62) | pub enum ConfigUserAuth {
type ConfigHomeserver (line 75) | pub struct ConfigHomeserver {
method validate (line 81) | pub fn validate(&self) -> anyhow::Result<()> {
type Avatar (line 106) | pub enum Avatar {
method deserialize (line 117) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
method from_string (line 130) | pub fn from_string(value: String) -> Self {
type ConfigUser (line 142) | pub struct ConfigUser {
method validate (line 165) | pub fn validate(&self, homeserver_server_name: &str) -> anyhow::Result...
method auth_config (line 187) | pub fn auth_config(&self, homeserver_server_name: &str) -> anyhow::Res...
type ConfigUserEncryption (line 240) | pub struct ConfigUserEncryption {
method validate (line 246) | pub fn validate(&self) -> anyhow::Result<()> {
type PersistenceConfig (line 261) | pub struct PersistenceConfig {
method validate (line 277) | pub fn validate(&self) -> anyhow::Result<()> {
method session_file_path (line 295) | pub fn session_file_path(&self) -> anyhow::Result<PathBuf> {
method db_dir_path (line 309) | pub fn db_dir_path(&self) -> anyhow::Result<PathBuf> {
method session_encryption_key (line 323) | pub fn session_encryption_key(&self) -> anyhow::Result<Option<Encrypti...
method config_encryption_key (line 333) | pub fn config_encryption_key(&self) -> anyhow::Result<Option<Encryptio...
method parse_encryption_key (line 343) | fn parse_encryption_key(
type ConfigRoom (line 363) | pub struct ConfigRoom {
method validate (line 369) | pub fn validate(&self) -> anyhow::Result<()> {
method default (line 375) | fn default() -> Self {
type ConfigAccess (line 384) | pub struct ConfigAccess {
method admin_pattern_regexes (line 393) | pub fn admin_pattern_regexes(&self) -> anyhow::Result<Vec<regex::Regex...
method validate (line 403) | pub fn validate(&self) -> anyhow::Result<()> {
type ConfigAgents (line 418) | pub struct ConfigAgents {
method validate (line 423) | pub fn validate(&self) -> anyhow::Result<()> {
type ConfigInitialGlobalConfig (line 429) | pub struct ConfigInitialGlobalConfig {
method user_pattern_regexes (line 437) | fn user_pattern_regexes(&self) -> anyhow::Result<Option<Vec<regex::Reg...
method validate (line 454) | pub fn validate(self) -> anyhow::Result<()> {
type Error (line 505) | type Error = anyhow::Error;
method try_into (line 507) | fn try_into(self) -> anyhow::Result<GlobalConfig> {
FILE: src/entity/cfg/config_tests.rs
function base_user (line 4) | fn base_user() -> ConfigUser {
function auth_config_uses_password_mode (line 20) | fn auth_config_uses_password_mode() {
function auth_config_uses_access_token_mode (line 40) | fn auth_config_uses_access_token_mode() {
function auth_config_rejects_both_auth_methods (line 66) | fn auth_config_rejects_both_auth_methods() {
function auth_config_rejects_missing_auth (line 83) | fn auth_config_rejects_missing_auth() {
function auth_config_rejects_access_token_without_device_id (line 94) | fn auth_config_rejects_access_token_without_device_id() {
function auth_config_treats_empty_strings_as_unset (line 106) | fn auth_config_treats_empty_strings_as_unset() {
FILE: src/entity/cfg/defaults.rs
constant CONFIG_FILE_PATH (line 1) | const CONFIG_FILE_PATH: &str = "config.yml";
constant NAME (line 3) | const NAME: &str = "baibot";
constant COMMAND_PREFIX (line 4) | const COMMAND_PREFIX: &str = "!bai";
constant PERSISTENCE_SESSION_FILE_NAME (line 6) | const PERSISTENCE_SESSION_FILE_NAME: &str = "session.json";
constant PERSISTENCE_DB_DIR_NAME (line 7) | const PERSISTENCE_DB_DIR_NAME: &str = "db";
function name (line 9) | pub(crate) fn name() -> String {
function config_file_path (line 13) | pub(crate) fn config_file_path() -> String {
function command_prefix (line 17) | pub(super) fn command_prefix() -> String {
function room_post_join_self_introduction_enabled (line 21) | pub(super) fn room_post_join_self_introduction_enabled() -> bool {
function persistence_data_dir_path (line 25) | pub(super) fn persistence_data_dir_path() -> Option<String> {
function persistence_session_file_name (line 29) | pub(super) fn persistence_session_file_name() -> String {
function persistence_db_dir_name (line 33) | pub(super) fn persistence_db_dir_name() -> String {
function logging (line 37) | pub(super) fn logging() -> String {
FILE: src/entity/cfg/env.rs
constant BAIBOT_CONFIG_FILE_PATH (line 1) | pub const BAIBOT_CONFIG_FILE_PATH: &str = "BAIBOT_CONFIG_FILE_PATH";
constant BAIBOT_HOMESERVER_SERVER_NAME (line 3) | pub const BAIBOT_HOMESERVER_SERVER_NAME: &str = "BAIBOT_HOMESERVER_SERVE...
constant BAIBOT_HOMESERVER_URL (line 4) | pub const BAIBOT_HOMESERVER_URL: &str = "BAIBOT_HOMESERVER_URL";
constant BAIBOT_USER_MXID_LOCALPART (line 6) | pub const BAIBOT_USER_MXID_LOCALPART: &str = "BAIBOT_USER_MXID_LOCALPART";
constant BAIBOT_USER_PASSWORD (line 7) | pub const BAIBOT_USER_PASSWORD: &str = "BAIBOT_USER_PASSWORD";
constant BAIBOT_USER_ACCESS_TOKEN (line 8) | pub const BAIBOT_USER_ACCESS_TOKEN: &str = "BAIBOT_USER_ACCESS_TOKEN";
constant BAIBOT_USER_DEVICE_ID (line 9) | pub const BAIBOT_USER_DEVICE_ID: &str = "BAIBOT_USER_DEVICE_ID";
constant BAIBOT_USER_NAME (line 10) | pub const BAIBOT_USER_NAME: &str = "BAIBOT_USER_NAME";
constant BAIBOT_USER_AVATAR (line 11) | pub const BAIBOT_USER_AVATAR: &str = "BAIBOT_USER_AVATAR";
constant BAIBOT_USER_ENCRYPTION_RECOVERY_PASSPHRASE (line 12) | pub const BAIBOT_USER_ENCRYPTION_RECOVERY_PASSPHRASE: &str =
constant BAIBOT_USER_ENCRYPTION_RECOVERY_RESET_ALLOWED (line 14) | pub const BAIBOT_USER_ENCRYPTION_RECOVERY_RESET_ALLOWED: &str =
constant BAIBOT_COMMAND_PREFIX (line 17) | pub const BAIBOT_COMMAND_PREFIX: &str = "BAIBOT_COMMAND_PREFIX";
constant BAIBOT_ROOM_POST_JOIN_SELF_INTRODUCTION_ENABLED (line 19) | pub const BAIBOT_ROOM_POST_JOIN_SELF_INTRODUCTION_ENABLED: &str =
constant BAIBOT_LOGGING (line 22) | pub const BAIBOT_LOGGING: &str = "BAIBOT_LOGGING";
constant BAIBOT_ACCESS_ADMIN_PATTERNS (line 24) | pub const BAIBOT_ACCESS_ADMIN_PATTERNS: &str = "BAIBOT_ACCESS_ADMIN_PATT...
constant BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_CATCH_ALL (line 26) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_CATCH_ALL: &str =
constant BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_TEXT_GENERATION (line 28) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_TEXT_GENERATION: &str =
constant BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_TEXT_TO_SPEECH (line 30) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_TEXT_TO_SPEECH: &str =
constant BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_SPEECH_TO_TEXT (line 32) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_SPEECH_TO_TEXT: &str =
constant BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_IMAGE_GENERATION (line 34) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_HANDLER_IMAGE_GENERATION: &str =
constant BAIBOT_INITIAL_GLOBAL_CONFIG_USER_PATTERNS (line 37) | pub const BAIBOT_INITIAL_GLOBAL_CONFIG_USER_PATTERNS: &str =
constant BAIBOT_PERSISTENCE_DATA_DIR_PATH (line 40) | pub const BAIBOT_PERSISTENCE_DATA_DIR_PATH: &str = "BAIBOT_PERSISTENCE_D...
constant BAIBOT_PERSISTENCE_SESSION_ENCRYPTION_KEY (line 42) | pub const BAIBOT_PERSISTENCE_SESSION_ENCRYPTION_KEY: &str =
constant BAIBOT_PERSISTENCE_CONFIG_ENCRYPTION_KEY (line 45) | pub const BAIBOT_PERSISTENCE_CONFIG_ENCRYPTION_KEY: &str =
FILE: src/entity/globalconfig/entity.rs
type GlobalConfigCarrierContent (line 13) | pub struct GlobalConfigCarrierContent {
method payload (line 18) | fn payload(&self) -> &str {
method new (line 22) | fn new(payload: String) -> Self {
type GlobalConfig (line 28) | pub struct GlobalConfig {
method new (line 37) | pub fn new(user_patterns: Option<Vec<String>>) -> Self {
type GlobalConfigAccess (line 54) | pub struct GlobalConfigAccess {
FILE: src/entity/globalconfig/mod.rs
type GlobalConfigurationManager (line 7) | pub type GlobalConfigurationManager =
FILE: src/entity/interaction_context.rs
type InteractionContext (line 5) | pub struct InteractionContext {
type InteractionTrigger (line 10) | pub struct InteractionTrigger {
FILE: src/entity/message_context.rs
type MessageContext (line 12) | pub struct MessageContext {
method new (line 23) | pub fn new(
method with_bot_display_name (line 41) | pub fn with_bot_display_name(mut self, value: Option<String>) -> Self {
method bot_display_name (line 46) | pub fn bot_display_name(&self) -> &Option<String> {
method room (line 50) | pub fn room(&self) -> &Room {
method room_id (line 54) | pub fn room_id(&self) -> &RoomId {
method global_config (line 58) | pub fn global_config(&self) -> &GlobalConfig {
method room_config (line 62) | pub fn room_config(&self) -> &RoomConfig {
method room_config_context (line 66) | pub fn room_config_context(&self) -> &RoomConfigContext {
method event_id (line 70) | pub fn event_id(&self) -> &OwnedEventId {
method sender_id (line 74) | pub fn sender_id(&self) -> &OwnedUserId {
method payload (line 78) | pub fn payload(&self) -> &MessagePayload {
method thread_info (line 82) | pub fn thread_info(&self) -> &ThreadInfo {
method sender_can_manage_global_config (line 86) | pub fn sender_can_manage_global_config(&self) -> bool {
method sender_can_manage_room_local_agents (line 90) | pub fn sender_can_manage_room_local_agents(&self) -> mxidwc::Result<bo...
method combined_admin_and_user_regexes (line 95) | pub fn combined_admin_and_user_regexes(&self) -> Vec<regex::Regex> {
method sender_is_allowed_room_local_agent_manager (line 118) | fn sender_is_allowed_room_local_agent_manager(&self) -> mxidwc::Result...
FILE: src/entity/message_payload.rs
type MessagePayload (line 13) | pub enum MessagePayload {
type Error (line 48) | type Error = String;
method try_into (line 50) | fn try_into(self) -> Result<MessagePayload, Self::Error> {
FILE: src/entity/room_config_context.rs
type RoomConfigContext (line 14) | pub struct RoomConfigContext {
method new (line 20) | pub fn new(global_config: GlobalConfig, room_config: RoomConfig) -> Ro...
method speech_to_text_flow_type (line 27) | pub fn speech_to_text_flow_type(&self) -> SpeechToTextFlowType {
method speech_to_text_msg_type_for_non_threaded_only_transcribed_messages (line 41) | pub fn speech_to_text_msg_type_for_non_threaded_only_transcribed_messa...
method speech_to_text_language (line 59) | pub fn speech_to_text_language(&self) -> Option<String> {
method auto_text_generation_usage (line 74) | pub fn auto_text_generation_usage(&self) -> TextGenerationAutoUsage {
method should_auto_text_generate (line 88) | pub fn should_auto_text_generate(&self, original_message_is_audio: boo...
method text_generation_prompt_override (line 97) | pub fn text_generation_prompt_override(&self) -> Option<String> {
method text_generation_temperature_override (line 112) | pub fn text_generation_temperature_override(&self) -> Option<f32> {
method text_generation_context_management_enabled (line 125) | pub fn text_generation_context_management_enabled(&self) -> bool {
method text_generation_sender_context_mode (line 139) | pub fn text_generation_sender_context_mode(&self) -> TextGenerationSen...
method text_generation_prefix_requirement_type (line 153) | pub fn text_generation_prefix_requirement_type(&self) -> TextGeneratio...
method text_to_speech_bot_messages_flow_type (line 167) | pub fn text_to_speech_bot_messages_flow_type(&self) -> TextToSpeechBot...
method text_to_speech_user_messages_flow_type (line 181) | pub fn text_to_speech_user_messages_flow_type(&self) -> TextToSpeechUs...
method text_to_speech_speed_override (line 195) | pub fn text_to_speech_speed_override(&self) -> Option<f32> {
method text_to_speech_voice_override (line 204) | pub fn text_to_speech_voice_override(&self) -> Option<String> {
method is_user_allowed_room_local_agent_manager (line 219) | pub fn is_user_allowed_room_local_agent_manager(
FILE: src/entity/roomconfig/defaults.rs
constant TEXT_GENERATION_PREFIX_REQUIREMENT_TYPE (line 7) | pub const TEXT_GENERATION_PREFIX_REQUIREMENT_TYPE: TextGenerationPrefixR...
constant TEXT_GENERATION_AUTO_USAGE (line 10) | pub const TEXT_GENERATION_AUTO_USAGE: TextGenerationAutoUsage = TextGene...
constant TEXT_GENERATION_SENDER_CONTEXT_MODE (line 12) | pub const TEXT_GENERATION_SENDER_CONTEXT_MODE: TextGenerationSenderConte...
constant TEXT_TO_SPEECH_BOT_MESSAGES_FLOW_TYPE (line 15) | pub const TEXT_TO_SPEECH_BOT_MESSAGES_FLOW_TYPE: TextToSpeechBotMessages...
constant TEXT_TO_SPEECH_USER_MESSAGES_FLOW_TYPE (line 18) | pub const TEXT_TO_SPEECH_USER_MESSAGES_FLOW_TYPE: TextToSpeechUserMessag...
constant SPEECH_TO_TEXT_FLOW_TYPE (line 21) | pub const SPEECH_TO_TEXT_FLOW_TYPE: SpeechToTextFlowType =
constant SPEECH_TO_TEXT_ONLY_TRANSCRIBE_NON_THREADED_MESSAGE_TYPE (line 26) | pub const SPEECH_TO_TEXT_ONLY_TRANSCRIBE_NON_THREADED_MESSAGE_TYPE:
FILE: src/entity/roomconfig/entity/handler.rs
type RoomSettingsHandler (line 6) | pub struct RoomSettingsHandler {
method get_by_purpose (line 24) | pub fn get_by_purpose(&self, purpose: AgentPurpose) -> Option<String> {
method get_by_purpose_with_catch_all_fallback (line 34) | pub fn get_by_purpose_with_catch_all_fallback(&self, purpose: AgentPur...
method set_by_purpose (line 41) | pub fn set_by_purpose(&mut self, purpose: AgentPurpose, agent_id: Opti...
FILE: src/entity/roomconfig/entity/mod.rs
type RoomConfigCarrierContent (line 26) | pub struct RoomConfigCarrierContent {
method payload (line 31) | fn payload(&self) -> &str {
method new (line 35) | fn new(payload: String) -> Self {
type RoomConfig (line 41) | pub struct RoomConfig {
method with_room (line 50) | pub async fn with_room(mut self, room: Room) -> Self {
type RoomSettings (line 91) | pub struct RoomSettings {
FILE: src/entity/roomconfig/entity/speech_to_text.rs
type RoomSettingsSpeechToText (line 4) | pub struct RoomSettingsSpeechToText {
type SpeechToTextFlowType (line 27) | pub enum SpeechToTextFlowType {
method choices (line 43) | pub fn choices() -> Vec<Self> {
method from_str (line 51) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 62) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages (line 76) | pub enum SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages {
method choices (line 87) | pub fn choices() -> Vec<Self> {
method from_str (line 91) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 101) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: src/entity/roomconfig/entity/text_generation.rs
type RoomSettingsTextGeneration (line 4) | pub struct RoomSettingsTextGeneration {
type TextGenerationPrefixRequirementType (line 28) | pub enum TextGenerationPrefixRequirementType {
method choices (line 39) | pub fn choices() -> Vec<Self> {
method from_str (line 43) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 53) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type TextGenerationAutoUsage (line 64) | pub enum TextGenerationAutoUsage {
method choices (line 87) | pub fn choices() -> Vec<Self> {
method from_str (line 96) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 108) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type TextGenerationSenderContextMode (line 119) | pub enum TextGenerationSenderContextMode {
method choices (line 131) | pub fn choices() -> Vec<Self> {
method from_str (line 139) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 150) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: src/entity/roomconfig/entity/text_to_speech.rs
type RoomSettingsTextToSpeech (line 4) | pub struct RoomSettingsTextToSpeech {
type TextToSpeechBotMessagesFlowType (line 15) | pub enum TextToSpeechBotMessagesFlowType {
method choices (line 38) | pub fn choices() -> Vec<Self> {
method from_str (line 48) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 61) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type TextToSpeechUserMessagesFlowType (line 73) | pub enum TextToSpeechUserMessagesFlowType {
method choices (line 88) | pub fn choices() -> Vec<Self> {
method from_str (line 92) | pub fn from_str(s: &str) -> Option<Self> {
method fmt (line 103) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: src/entity/roomconfig/mod.rs
type RoomConfigurationManager (line 13) | pub type RoomConfigurationManager =
FILE: src/entity/trigger_event_info.rs
type TriggerEventInfo (line 6) | pub struct TriggerEventInfo {
method new (line 14) | pub fn new(
FILE: src/main.rs
function main (line 7) | async fn main() -> anyhow::Result<()> {
function run_with_config (line 14) | async fn run_with_config(config: Config) -> anyhow::Result<()> {
FILE: src/strings/access.rs
function users_no_patterns (line 1) | pub fn users_no_patterns() -> String {
function users_now_match_patterns (line 5) | pub fn users_now_match_patterns(patterns: &[String]) -> String {
function room_local_agent_managers_no_patterns (line 12) | pub fn room_local_agent_managers_no_patterns() -> String {
function room_local_agent_managers_now_match_patterns (line 16) | pub fn room_local_agent_managers_now_match_patterns(patterns: &[String])...
function failed_to_parse_patterns (line 23) | pub fn failed_to_parse_patterns(err: &str) -> String {
FILE: src/strings/agent.rs
function invalid_id_generic (line 6) | pub fn invalid_id_generic() -> String {
function invalid_id_validation_error (line 10) | pub fn invalid_id_validation_error(validation_error: String) -> String {
function agent_with_given_identifier_missing (line 14) | pub fn agent_with_given_identifier_missing(agent_identifier: &PublicIden...
function already_exists_see_help (line 18) | pub fn already_exists_see_help(agent_id: &str, command_prefix: &str) -> ...
function incorrect_creation_invocation (line 25) | pub fn incorrect_creation_invocation(command_prefix: &str) -> String {
function incorrect_invocation_expects_agent_id_arg (line 31) | pub fn incorrect_invocation_expects_agent_id_arg(command_prefix: &str) -...
function not_allowed_to_manage_room_local_agents_in_room (line 37) | pub fn not_allowed_to_manage_room_local_agents_in_room() -> String {
function not_allowed_to_manage_static_agents (line 41) | pub fn not_allowed_to_manage_static_agents() -> String {
function configuration_does_not_result_in_a_working_agent (line 45) | pub fn configuration_does_not_result_in_a_working_agent(err: anyhow::Err...
function configuration_agent_will_ping (line 52) | pub fn configuration_agent_will_ping() -> &'static str {
function configuration_agent_ping_inconclusive (line 56) | pub fn configuration_agent_ping_inconclusive() -> String {
function configuration_agent_ping_ok (line 60) | pub fn configuration_agent_ping_ok() -> String {
function created (line 64) | pub fn created(agent_identifier: &PublicIdentifier) -> String {
function post_creation_helpful_commands (line 68) | pub fn post_creation_helpful_commands(
function set_as_purpose_handler_in_room (line 129) | fn set_as_purpose_handler_in_room(
function set_as_purpose_handler_globally (line 141) | fn set_as_purpose_handler_globally(
function configuration_not_a_valid_yaml_hashmap (line 153) | pub fn configuration_not_a_valid_yaml_hashmap(err: String) -> String {
function creation_guide (line 160) | pub fn creation_guide(
function creation_welcome (line 178) | fn creation_welcome(agent_identifier: &PublicIdentifier, provider: &Agen...
function creation_example_config (line 186) | fn creation_example_config(pretty_yaml: &str) -> String {
function creation_howto (line 190) | fn creation_howto() -> String {
function creation_raw_or_codeblock_ok (line 198) | fn creation_raw_or_codeblock_ok() -> String {
function removed_room_local (line 202) | pub fn removed_room_local(agent_identifier: &PublicIdentifier, command_p...
function removed_global (line 218) | pub fn removed_global(agent_identifier: &PublicIdentifier, command_prefi...
function removed (line 236) | fn removed(agent_identifier: &PublicIdentifier) -> String {
function purpose_unrecognized (line 240) | pub fn purpose_unrecognized(purpose: &str) -> String {
function purpose_howto (line 244) | pub fn purpose_howto(purpose: &AgentPurpose) -> &'static str {
function agent_list_empty (line 254) | pub fn agent_list_empty() -> String {
function non_empty_agent_list_block (line 258) | pub fn non_empty_agent_list_block(agents: &Vec<AgentInstance>) -> String {
function agent_list_intro (line 283) | fn agent_list_intro() -> String {
function agent_list_legend_intro (line 287) | pub fn agent_list_legend_intro() -> String {
function error_while_serving_purpose (line 291) | pub fn error_while_serving_purpose(
function empty_response_returned (line 304) | pub fn empty_response_returned(agent_identifier: &PublicIdentifier) -> S...
function no_configuration_for_purpose_so_cannot_be_used (line 308) | pub fn no_configuration_for_purpose_so_cannot_be_used(purpose: &AgentPur...
function no_configuration_for_purpose_after_conversion_so_cannot_be_used (line 316) | pub fn no_configuration_for_purpose_after_conversion_so_cannot_be_used(
function create_support_badges_text (line 326) | pub fn create_support_badges_text(controller: &impl ControllerTrait) -> ...
FILE: src/strings/cfg.rs
function error_config_type_not_replaced (line 14) | pub fn error_config_type_not_replaced() -> String {
function create_display_text_for_value (line 18) | pub fn create_display_text_for_value(value: impl std::fmt::Display) -> S...
function value_currently_set_to (line 28) | pub fn value_currently_set_to(value: impl std::fmt::Display) -> String {
function value_currently_unset (line 35) | pub fn value_currently_unset() -> String {
function configuration_invocation_incorrect_more_values_expected (line 39) | pub fn configuration_invocation_incorrect_more_values_expected() -> Stri...
function configuration_getter_used_with_extra_text (line 44) | pub fn configuration_getter_used_with_extra_text(
function configuration_value_unrecognized (line 53) | pub fn configuration_value_unrecognized(value: &str) -> String {
function configuration_value_not_f32 (line 57) | pub fn configuration_value_not_f32(value: &str) -> String {
function status_room_config_handlers_heading (line 64) | pub fn status_room_config_handlers_heading() -> &'static str {
function status_room_config_handlers_intro (line 68) | pub fn status_room_config_handlers_intro() -> &'static str {
function status_room_config_handlers_outro (line 72) | pub fn status_room_config_handlers_outro(command_prefix: &str) -> String {
function status_global_config_handlers_heading (line 88) | pub fn status_global_config_handlers_heading() -> &'static str {
function status_global_config_handlers_intro (line 92) | pub fn status_global_config_handlers_intro() -> &'static str {
function status_global_config_handlers_outro (line 96) | pub fn status_global_config_handlers_outro(command_prefix: &str) -> Stri...
function status_agent_not_found (line 110) | fn status_agent_not_found() -> &'static str {
function status_handler_line_agent_found (line 114) | pub fn status_handler_line_agent_found(
function status_handler_line_catch_all_agent_not_set_globally (line 134) | pub fn status_handler_line_catch_all_agent_not_set_globally() -> String {
function status_handler_line_catch_all_agent_not_set_in_room_default_to_global (line 143) | pub fn status_handler_line_catch_all_agent_not_set_in_room_default_to_gl...
function status_handler_line_non_catch_all_agent_not_set_globally (line 152) | pub fn status_handler_line_non_catch_all_agent_not_set_globally(purpose:...
function status_handler_line_non_catch_all_agent_not_set_in_room_default_to_global (line 162) | pub fn status_handler_line_non_catch_all_agent_not_set_in_room_default_t...
function status_room_agents_heading (line 174) | pub fn status_room_agents_heading() -> &'static str {
function status_room_agents_intro (line 178) | pub fn status_room_agents_intro() -> &'static str {
function status_room_agents_empty (line 182) | pub fn status_room_agents_empty() -> &'static str {
function status_room_agents_outro (line 186) | pub fn status_room_agents_outro(command_prefix: &str) -> String {
function status_text_generation_heading (line 202) | pub fn status_text_generation_heading() -> String {
function status_speech_to_text_heading (line 210) | pub fn status_speech_to_text_heading() -> String {
function status_text_to_speech_heading (line 218) | pub fn status_text_to_speech_heading() -> String {
function status_image_generation_heading (line 226) | pub fn status_image_generation_heading() -> String {
function status_text_generation_entry_prefix_requirement_type (line 234) | pub fn status_text_generation_entry_prefix_requirement_type(
function status_text_generation_entry_auto_usage (line 241) | pub fn status_text_generation_entry_auto_usage(
function status_text_generation_entry_context_management (line 248) | pub fn status_text_generation_entry_context_management(value: bool, set_...
function status_text_generation_entry_sender_context (line 252) | pub fn status_text_generation_entry_sender_context(
function status_text_generation_entry_prompt (line 259) | pub fn status_text_generation_entry_prompt(value: &str, set_where: &str)...
function status_text_generation_entry_temperature (line 269) | pub fn status_text_generation_entry_temperature(value: Option<f32>, set_...
function status_speech_to_text_entry_flow_type (line 278) | pub fn status_speech_to_text_entry_flow_type(
function status_speech_to_text_entry_msg_type_for_non_threaded_only_transcribed_messages (line 285) | pub fn status_speech_to_text_entry_msg_type_for_non_threaded_only_transc...
function status_speech_to_text_entry_language (line 295) | pub fn status_speech_to_text_entry_language(value: Option<String>, set_w...
function status_text_to_speech_entry_bot_msgs_flow_type (line 304) | pub fn status_text_to_speech_entry_bot_msgs_flow_type(
function status_text_to_speech_entry_user_msgs_flow_type (line 314) | pub fn status_text_to_speech_entry_user_msgs_flow_type(
function status_text_to_speech_entry_speed (line 324) | pub fn status_text_to_speech_entry_speed(value: Option<f32>, set_where: ...
function status_text_to_speech_entry_voice (line 333) | pub fn status_text_to_speech_entry_voice(value: Option<String>, set_wher...
function status_entry_effective_agent_error (line 342) | pub fn status_entry_effective_agent_error() -> String {
function status_entry_effective_agent (line 346) | pub fn status_entry_effective_agent(
function status_badge_set_in_room_config (line 365) | pub fn status_badge_set_in_room_config() -> &'static str {
function status_badge_set_in_global_config (line 369) | pub fn status_badge_set_in_global_config() -> &'static str {
function status_badge_using_hardcoded_default (line 373) | pub fn status_badge_using_hardcoded_default() -> &'static str {
function status_badge_set_in_agent_config (line 377) | pub fn status_badge_set_in_agent_config() -> &'static str {
FILE: src/strings/error.rs
function unknown_command_see_help (line 1) | pub fn unknown_command_see_help(command_prefix: &str) -> String {
function error_while_processing_message (line 5) | pub fn error_while_processing_message() -> &'static str {
function message_is_encrypted (line 9) | pub fn message_is_encrypted() -> &'static str {
function first_message_in_thread_is_encrypted (line 13) | pub fn first_message_in_thread_is_encrypted() -> &'static str {
FILE: src/strings/global_config.rs
function no_permissions_to_administrate (line 3) | pub fn no_permissions_to_administrate() -> &'static str {
function not_allowed_to_use_agent_in_global_config (line 7) | pub fn not_allowed_to_use_agent_in_global_config(agent_identifier: &Publ...
function global_config_lacks_specific_agent_for_purpose (line 14) | pub fn global_config_lacks_specific_agent_for_purpose(purpose: AgentPurp...
function configured_to_use_agent_for_purpose (line 21) | pub fn configured_to_use_agent_for_purpose(
function configures_agent_for_purpose_but_does_not_exist (line 31) | pub fn configures_agent_for_purpose_but_does_not_exist(
function reconfigured_to_use_agent_for_purpose (line 41) | pub fn reconfigured_to_use_agent_for_purpose(
function reconfigured_to_not_specify_agent_for_purpose (line 51) | pub fn reconfigured_to_not_specify_agent_for_purpose(purpose: AgentPurpo...
function value_was_set_to (line 58) | pub fn value_was_set_to(value: impl std::fmt::Display) -> String {
function value_was_unset (line 65) | pub fn value_was_unset() -> String {
FILE: src/strings/help/access.rs
function heading (line 1) | pub fn heading() -> String {
function intro (line 5) | pub fn intro() -> String {
function room_auto_join_heading (line 9) | pub fn room_auto_join_heading() -> String {
function room_auto_join_intro (line 13) | pub fn room_auto_join_intro() -> String {
function users_heading (line 18) | pub fn users_heading() -> String {
function users_intro (line 22) | pub fn users_intro() -> String {
function users_access (line 26) | pub fn users_access() -> String {
function users_command_get (line 30) | pub fn users_command_get(command_prefix: &str) -> String {
function users_command_set (line 34) | pub fn users_command_set(command_prefix: &str) -> String {
function example_user_patterns (line 40) | pub fn example_user_patterns(own_server_name: &str) -> String {
function administrators_heading (line 44) | pub fn administrators_heading() -> String {
function administrators_intro (line 48) | pub fn administrators_intro() -> String {
function administrators_now_match_patterns (line 52) | pub fn administrators_now_match_patterns(patterns: &[String]) -> String {
function administrators_outro (line 59) | pub fn administrators_outro() -> String {
function room_local_agent_managers_heading (line 64) | pub fn room_local_agent_managers_heading() -> String {
function room_local_agent_managers_intro (line 68) | pub fn room_local_agent_managers_intro(command_prefix: &str) -> String {
function room_local_agent_managers_security_warning (line 74) | pub fn room_local_agent_managers_security_warning() -> String {
function room_local_agent_managers_command_get (line 78) | pub fn room_local_agent_managers_command_get(command_prefix: &str) -> St...
function room_local_agent_managers_command_set (line 84) | pub fn room_local_agent_managers_command_set(command_prefix: &str) -> St...
FILE: src/strings/help/agent.rs
function heading (line 1) | pub fn heading() -> String {
function intro (line 5) | pub fn intro(command_prefix: &str) -> String {
function intro_handler_relation (line 11) | pub fn intro_handler_relation(command_prefix: &str) -> String {
function intro_capabilities (line 17) | pub fn intro_capabilities() -> String {
function no_permission_to_create_agents (line 21) | pub fn no_permission_to_create_agents() -> &'static str {
function list_agents (line 25) | pub fn list_agents(command_prefix: &str) -> String {
function show_agent_details (line 29) | pub fn show_agent_details(command_prefix: &str) -> String {
function create_agent_intro (line 35) | pub fn create_agent_intro() -> &'static str {
function create_agent_room_local (line 39) | pub fn create_agent_room_local(command_prefix: &str) -> String {
function create_agent_global (line 45) | pub fn create_agent_global(command_prefix: &str) -> String {
function create_agent_example (line 51) | pub fn create_agent_example(command_prefix: &str) -> String {
function delete_agent (line 55) | pub fn delete_agent(command_prefix: &str) -> String {
function available_commands_outro_update_note (line 59) | pub fn available_commands_outro_update_note() -> &'static str {
FILE: src/strings/help/cfg.rs
function heading (line 3) | pub fn heading() -> String {
function intro_short (line 7) | pub fn intro_short() -> &'static str {
function intro_long (line 11) | pub fn intro_long() -> String {
function status_heading (line 21) | pub fn status_heading() -> String {
function status_intro (line 25) | pub fn status_intro(command_prefix: &str) -> String {
function handlers_heading (line 31) | pub fn handlers_heading() -> String {
function handlers_intro_common (line 35) | pub fn handlers_intro_common() -> String {
function handlers_intro_purposes (line 43) | pub fn handlers_intro_purposes() -> String {
function handlers_show (line 61) | pub fn handlers_show(command_prefix: &str) -> String {
function handlers_set (line 67) | pub fn handlers_set(command_prefix: &str) -> String {
function handlers_unset (line 73) | pub fn handlers_unset(command_prefix: &str) -> String {
function text_generation_heading (line 79) | pub fn text_generation_heading() -> String {
function text_generation_common (line 87) | pub fn text_generation_common() -> String {
function text_generation_prefix_requirement_type_heading (line 100) | pub fn text_generation_prefix_requirement_type_heading() -> &'static str {
function text_generation_prefix_requirement_type_intro (line 104) | pub fn text_generation_prefix_requirement_type_intro() -> String {
function text_generation_prefix_requirement_type_outro (line 109) | pub fn text_generation_prefix_requirement_type_outro(bot_username: &str)...
function text_generation_auto_usage_heading (line 115) | pub fn text_generation_auto_usage_heading() -> &'static str {
function text_generation_auto_usage_intro (line 119) | pub fn text_generation_auto_usage_intro() -> String {
function text_generation_context_management_heading (line 123) | pub fn text_generation_context_management_heading() -> &'static str {
function text_generation_context_management_intro (line 127) | pub fn text_generation_context_management_intro() -> String {
function text_generation_sender_context_heading (line 135) | pub fn text_generation_sender_context_heading() -> &'static str {
function text_generation_sender_context_intro (line 139) | pub fn text_generation_sender_context_intro() -> String {
function text_generation_prompt_override_heading (line 147) | pub fn text_generation_prompt_override_heading() -> &'static str {
function text_generation_prompt_override_intro (line 151) | pub fn text_generation_prompt_override_intro() -> String {
function text_generation_temperature_override_heading (line 155) | pub fn text_generation_temperature_override_heading() -> &'static str {
function text_generation_temperature_override_intro (line 159) | pub fn text_generation_temperature_override_intro() -> String {
function current_setting_show (line 163) | pub fn current_setting_show(command_prefix: &str, setting_path_parts: &s...
function current_setting_set (line 169) | pub fn current_setting_set(command_prefix: &str, setting_path_parts: &st...
function current_setting_unset (line 173) | pub fn current_setting_unset(command_prefix: &str, setting_path_parts: &...
function the_following_configuration_values_are_recognized (line 177) | pub fn the_following_configuration_values_are_recognized(
function speech_to_text_heading (line 191) | pub fn speech_to_text_heading() -> String {
function speech_to_text_common (line 199) | pub fn speech_to_text_common() -> String {
function speech_to_text_flow_type_heading (line 217) | pub fn speech_to_text_flow_type_heading() -> &'static str {
function speech_to_text_flow_type_intro (line 221) | pub fn speech_to_text_flow_type_intro() -> &'static str {
function speech_to_text_msg_type_for_non_threaded_only_transcribed_messages_heading (line 225) | pub fn speech_to_text_msg_type_for_non_threaded_only_transcribed_message...
function speech_to_text_msg_type_for_non_threaded_only_transcribed_messages_intro (line 230) | pub fn speech_to_text_msg_type_for_non_threaded_only_transcribed_message...
function speech_to_text_language_heading (line 234) | pub fn speech_to_text_language_heading() -> &'static str {
function speech_to_text_language_intro (line 238) | pub fn speech_to_text_language_intro() -> &'static str {
function text_to_speech_heading (line 242) | pub fn text_to_speech_heading() -> String {
function text_to_speech_common (line 250) | pub fn text_to_speech_common() -> &'static str {
function text_to_speech_bot_msgs_flow_type_heading (line 254) | pub fn text_to_speech_bot_msgs_flow_type_heading() -> &'static str {
function text_to_speech_bot_msgs_flow_type_intro (line 258) | pub fn text_to_speech_bot_msgs_flow_type_intro() -> String {
function text_to_speech_user_msgs_flow_type_heading (line 262) | pub fn text_to_speech_user_msgs_flow_type_heading() -> &'static str {
function text_to_speech_user_msgs_flow_type_intro (line 266) | pub fn text_to_speech_user_msgs_flow_type_intro() -> String {
function text_to_speech_speed_override_heading (line 270) | pub fn text_to_speech_speed_override_heading() -> &'static str {
function text_to_speech_speed_override_intro (line 274) | pub fn text_to_speech_speed_override_intro() -> String {
function text_to_speech_voice_override_heading (line 282) | pub fn text_to_speech_voice_override_heading() -> &'static str {
function text_to_speech_voice_override_intro (line 286) | pub fn text_to_speech_voice_override_intro() -> String {
function image_generation_heading (line 294) | pub fn image_generation_heading() -> String {
function image_generation_common (line 302) | pub fn image_generation_common() -> &'static str {
FILE: src/strings/help/mod.rs
function heading_introduction (line 7) | pub fn heading_introduction() -> String {
function available_commands_intro (line 11) | pub fn available_commands_intro() -> &'static str {
function learn_more_send_a_command (line 15) | pub fn learn_more_send_a_command(command_prefix: &str, command_parts: &s...
FILE: src/strings/help/provider.rs
function heading (line 1) | pub fn heading() -> String {
function intro (line 5) | pub fn intro() -> String {
FILE: src/strings/help/usage.rs
function heading (line 1) | pub fn heading() -> &'static str {
function intro (line 5) | pub fn intro() -> &'static str {
FILE: src/strings/image_edit.rs
function guide_how_to_proceed (line 1) | pub fn guide_how_to_proceed() -> String {
FILE: src/strings/image_generation.rs
function revised_prompt (line 1) | pub fn revised_prompt(prompt: &str) -> String {
function guide_how_to_proceed (line 5) | pub fn guide_how_to_proceed() -> String {
FILE: src/strings/introduction.rs
function hello (line 7) | fn hello() -> &'static str {
function its_me (line 11) | pub fn its_me(name: &str) -> String {
function purposes_intro (line 24) | fn purposes_intro() -> &'static str {
function create_on_join_introduction (line 28) | pub async fn create_on_join_introduction(
function create_short_introduction (line 116) | pub fn create_short_introduction(name: &str) -> String {
function make_use_of_me_simply_send_a_message (line 120) | fn make_use_of_me_simply_send_a_message(
function make_use_of_me_agent_creation (line 142) | fn make_use_of_me_agent_creation(
function send_a_text_message (line 175) | fn send_a_text_message(
function learn_more_from_usage_or_help (line 191) | fn learn_more_from_usage_or_help(command_prefix: &str) -> String {
function create_one_or_more_agents (line 197) | pub fn create_one_or_more_agents(command_prefix: &str) -> String {
function set_new_agent_as_handler (line 203) | pub fn set_new_agent_as_handler(command_prefix: &str) -> String {
FILE: src/strings/mod.rs
constant PROGRESS_INDICATOR_EMOJI (line 16) | pub const PROGRESS_INDICATOR_EMOJI: &str = "⏳";
function the_following_commands_are_available (line 18) | pub fn the_following_commands_are_available() -> &'static str {
FILE: src/strings/provider.rs
function invalid (line 6) | pub fn invalid(provider: &str) -> String {
function invalid_configuration_for_provider (line 19) | pub fn invalid_configuration_for_provider(
function providers_list_intro (line 29) | pub fn providers_list_intro() -> String {
function help_how_to_choose_heading (line 33) | pub fn help_how_to_choose_heading() -> String {
function help_how_to_choose_description (line 37) | pub fn help_how_to_choose_description(command_prefix: &str) -> String {
function help_how_to_use_heading (line 49) | pub fn help_how_to_use_heading() -> String {
function help_how_to_use_description (line 53) | pub fn help_how_to_use_description(command_prefix: &str) -> String {
function help_provider_heading (line 74) | pub fn help_provider_heading(provider_name: &str, homepage_url: &Option<...
function help_provider_details (line 81) | pub fn help_provider_details(id: &str, info: &AgentProviderInfo) -> Stri...
FILE: src/strings/room_config.rs
function room_not_configured_with_specific_agent_for_purpose (line 3) | pub fn room_not_configured_with_specific_agent_for_purpose(purpose: Agen...
function configured_to_use_agent_for_purpose (line 10) | pub fn configured_to_use_agent_for_purpose(
function configures_agent_for_purpose_but_does_not_exist (line 19) | pub fn configures_agent_for_purpose_but_does_not_exist(
function configures_agent_for_purpose_but_agent_does_not_support_it (line 28) | pub fn configures_agent_for_purpose_but_agent_does_not_support_it(
function reconfigured_to_use_agent_for_purpose (line 41) | pub fn reconfigured_to_use_agent_for_purpose(
function reconfigured_to_not_specify_agent_for_purpose (line 51) | pub fn reconfigured_to_not_specify_agent_for_purpose(purpose: AgentPurpo...
function value_was_set_to (line 58) | pub fn value_was_set_to(value: impl std::fmt::Display) -> String {
function value_was_unset (line 65) | pub fn value_was_unset() -> String {
FILE: src/strings/speech_to_text.rs
function redaction_reason_done (line 1) | pub fn redaction_reason_done() -> &'static str {
function redaction_reason_failed (line 5) | pub fn redaction_reason_failed() -> &'static str {
function language_code_invalid (line 9) | pub fn language_code_invalid(value: &str) -> String {
FILE: src/strings/text_to_speech.rs
function redaction_reason_done (line 1) | pub fn redaction_reason_done() -> &'static str {
function redaction_reason_failed (line 5) | pub fn redaction_reason_failed() -> &'static str {
FILE: src/strings/usage.rs
function intro (line 1) | pub fn intro(command_prefix: &str) -> String {
FILE: src/utils/base64.rs
function base64_decode (line 3) | pub(crate) fn base64_decode(base64_string: &str) -> Result<Vec<u8>, base...
function base64_encode (line 7) | pub(crate) fn base64_encode(data: &[u8]) -> String {
FILE: src/utils/mime.rs
function get_file_extension (line 3) | pub fn get_file_extension(mime_type: &mime::Mime) -> String {
function get_mime_type_from_file_name (line 19) | pub fn get_mime_type_from_file_name(file_name: &str) -> mime::Mime {
FILE: src/utils/status.rs
function create_error_message_text (line 1) | pub fn create_error_message_text(text: &str) -> String {
function create_success_message_text (line 5) | pub fn create_success_message_text(text: &str) -> String {
function create_tooltip_message_text (line 9) | pub fn create_tooltip_message_text(text: &str) -> String {
FILE: src/utils/text.rs
function block_quote (line 1) | pub fn block_quote(text: &str) -> String {
function block_unquote (line 8) | pub fn block_unquote(text: &str) -> String {
FILE: src/utils/text_to_speech.rs
function create_transcribed_message_text (line 11) | pub fn create_transcribed_message_text(text: &str) -> String {
function parse_transcribed_message_text (line 20) | pub fn parse_transcribed_message_text(text: &str) -> Option<String> {
function test_transcribed_message_text_creation (line 38) | fn test_transcribed_message_text_creation() {
function test_transcribed_message_text_parsing (line 48) | fn test_transcribed_message_text_parsing() {
Condensed preview — 221 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (945K chars).
[
{
"path": ".dockerignore",
"chars": 13,
"preview": "/target\n/var\n"
},
{
"path": ".editorconfig",
"chars": 618,
"preview": "# This file is the top-most EditorConfig file\nroot = true\n\n# All Files\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style"
},
{
"path": ".github/workflows/ci.yml",
"chars": 633,
"preview": "name: CI\non:\n workflow_dispatch:\n pull_request:\n branches: [ \"main\" ]\n push:\n branches:\n - \"**\"\n tags: "
},
{
"path": ".github/workflows/publish.yml",
"chars": 3932,
"preview": "name: Publish\non:\n workflow_run:\n workflows: [ \"CI\" ]\n types: [ \"completed\" ]\npermissions:\n contents: read\nconcu"
},
{
"path": ".gitignore",
"chars": 13,
"preview": "/target\n/var\n"
},
{
"path": ".pre-commit-config.yaml",
"chars": 902,
"preview": "repos:\n # Fast built-in hooks (Rust-native, no dependencies)\n - repo: builtin\n hooks:\n - id: trailing-whitespa"
},
{
"path": "CHANGELOG.md",
"chars": 22591,
"preview": "# (2026-05-21) Version 1.19.2\n\n- (**Internal Improvement**) Update [async-openai](https://crates.io/crates/async-openai)"
},
{
"path": "Cargo.toml",
"chars": 1644,
"preview": "[package]\nname = \"baibot\"\ndescription = \"A Matrix bot for using diffent capabilities (text-generation, text-to-speech, s"
},
{
"path": "Dockerfile",
"chars": 1367,
"preview": "#######################################\n# #\n# Stage 1: building #\n"
},
{
"path": "Dockerfile.ci",
"chars": 873,
"preview": "#######################################\n# #\n# Stage 1: building #\n"
},
{
"path": "LICENSE",
"chars": 34523,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "README.md",
"chars": 4569,
"preview": "<p align=\"center\">\n\t<img src=\"./etc/assets/baibot.svg\" alt=\"baibot logo\" width=\"150\" />\n\t<h1 align=\"center\">baibot</h1>\n"
},
{
"path": "docs/README.md",
"chars": 326,
"preview": "# Table of Contents\n\n- [🔒 Access](./access.md)\n- [🤖 Agents](./agents.md)\n- [🛠️ Configuration](./configuration/README.md)"
},
{
"path": "docs/access.md",
"chars": 2620,
"preview": "## 🔒 Access\n\nThis bot employs access control to decide who can use its services and manage its configuration.\n\n\n### 👋 Jo"
},
{
"path": "docs/agents.md",
"chars": 3649,
"preview": "## 🤖 Agents\n\nAn agent is an instantiation and configuration of some [☁️ provider](./providers.md).\nIt can support differ"
},
{
"path": "docs/configuration/README.md",
"chars": 2878,
"preview": "## 🛠️ Configuration\n\nThe bot's behavior is controlled by a combination of [static](#static-configuration) and [dynamic]("
},
{
"path": "docs/configuration/authentication.md",
"chars": 764,
"preview": "## 🔐 Authentication\n\nbaibot supports 2 authentication modes for the Matrix account (`user.*` keys in config).\n\nSet **exa"
},
{
"path": "docs/configuration/handlers.md",
"chars": 2045,
"preview": "## 🤝 Handlers\n\n### Introduction\n\nYou can use **different models in different rooms** (e.g. [OpenAI](../providers.md#open"
},
{
"path": "docs/configuration/image-generation.md",
"chars": 739,
"preview": "\n## Image Generation\n\nThe Image Creation and Image Editing features are not configurable at this moment.\n\nYou may also w"
},
{
"path": "docs/configuration/speech-to-text.md",
"chars": 3312,
"preview": "## 🦻 Speech-to-Text\n\nBelow are some configuration settings related to Speech-to-Text.\n\nYou may also wish to see:\n\n- [🌟 F"
},
{
"path": "docs/configuration/text-generation.md",
"chars": 7703,
"preview": "\n## 💬 Text Generation\n\nBelow are some [🛠️ dynamic configuration settings](./README.md#dynamic-configuration) related to "
},
{
"path": "docs/configuration/text-to-speech.md",
"chars": 3967,
"preview": "\n## 🗣️ Text-to-Speech\n\nBelow are some configuration settings related to Text-to-Speech.\n\nYou may also wish to see:\n\n- [🌟"
},
{
"path": "docs/development.md",
"chars": 9611,
"preview": "## 🧑💻 Development\n\nThis documentation page contains information about **running the bot locally for development purpose"
},
{
"path": "docs/features.md",
"chars": 15665,
"preview": "## 🌟 Features\n\n### 🎨 Mixing & matching models\n\nYou can use **different models in different rooms** (e.g. [OpenAI](./prov"
},
{
"path": "docs/installation.md",
"chars": 5520,
"preview": "## 🚀 Installation\n\n☁️ The easiest way to use the bot is to **get a managed Matrix server from [etke.cc](https://etke.cc/"
},
{
"path": "docs/providers.md",
"chars": 10573,
"preview": "## ☁️ Providers\n\n[🤖 Agents](./agents.md) are powered by a provider. The provider could be a **local service** or a **clo"
},
{
"path": "docs/sample-provider-configs/anthropic.yml",
"chars": 401,
"preview": "base_url: https://api.anthropic.com/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: claude-3-7-sonnet-2025021"
},
{
"path": "docs/sample-provider-configs/groq.yml",
"chars": 437,
"preview": "base_url: https://api.groq.com/openai/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: llama3-70b-8192\n promp"
},
{
"path": "docs/sample-provider-configs/localai.yml",
"chars": 619,
"preview": "base_url: http://my-localai-self-hosted-service:8080/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: gpt-4\n "
},
{
"path": "docs/sample-provider-configs/mistral.yml",
"chars": 392,
"preview": "base_url: https://api.mistral.ai/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: mistral-large-latest\n promp"
},
{
"path": "docs/sample-provider-configs/ollama.yml",
"chars": 401,
"preview": "base_url: http://my-ollama-self-hosted-service:11434/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: gemma2:2"
},
{
"path": "docs/sample-provider-configs/openai-compatible.yml",
"chars": 397,
"preview": "base_url: ''\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: some-model\n prompt: \"You are a brief, but helpful "
},
{
"path": "docs/sample-provider-configs/openai.yml",
"chars": 908,
"preview": "base_url: https://api.openai.com/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: gpt-5.4\n prompt: \"You are a"
},
{
"path": "docs/sample-provider-configs/openrouter.yml",
"chars": 403,
"preview": "base_url: https://openrouter.ai/api/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: mattshumer/reflection-70b"
},
{
"path": "docs/sample-provider-configs/together-ai.yml",
"chars": 417,
"preview": "base_url: https://api.together.xyz/v1\napi_key: YOUR_API_KEY_HERE\ntext_generation:\n model_id: meta-llama/Meta-Llama-3.1-"
},
{
"path": "docs/usage.md",
"chars": 7019,
"preview": "## 📖 Usage\n\nThis document covers how to use the bot in a room.\n\nThe [🌟 Features](./features.md) page also includes detai"
},
{
"path": "etc/app/config.yml.dist",
"chars": 7285,
"preview": "homeserver:\n # The canonical homeserver domain name\n server_name: __HOMESERVER_SERVER_NAME__\n url: __HOMESERVER_URL__"
},
{
"path": "etc/services/continuwuity/compose.yml",
"chars": 641,
"preview": "services:\n continuwuity:\n image: forgejo.ellis.link/continuwuation/continuwuity:v0.5.9\n user: \"${UID}:${GID}\"\n "
},
{
"path": "etc/services/continuwuity/config/continuwuity.toml",
"chars": 416,
"preview": "[global]\nserver_name = \"continuwuity.127.0.0.1.nip.io\"\n\naddress = \"0.0.0.0\"\nport = 6167\n\ndatabase_path = \"/var/lib/conti"
},
{
"path": "etc/services/continuwuity/register-user.sh",
"chars": 1852,
"preview": "#!/bin/sh\nset -eu\n\nif [ $# -ne 3 ]; then\n\techo \"Usage: $0 <env-file> <username> <password>\"\n\texit 1\nfi\n\nENV_FILE=\"$1\"\nUS"
},
{
"path": "etc/services/element-web/compose.yml",
"chars": 531,
"preview": "services:\n element-web:\n image: ghcr.io/element-hq/element-web:v1.12.18\n user: \"${UID}:${GID}\"\n restart: unles"
},
{
"path": "etc/services/element-web/config.json.dist",
"chars": 395,
"preview": "{\n \"default_hs_url\": \"__HOMESERVER_CLIENT_URL__\",\n \"default_is_url\": \"https://vector.im\",\n \"integrations_ui_url"
},
{
"path": "etc/services/env.dist",
"chars": 529,
"preview": "SERVICE_SYNAPSE_BIND_PORT_CLIENT_API=127.0.0.1:42020\nSERVICE_SYNAPSE_BIND_PORT_FEDERATION_API=127.0.0.1:42028\n\nSERVICE_E"
},
{
"path": "etc/services/localai/compose.yml",
"chars": 448,
"preview": "services:\n localai:\n image: ${SERVICE_LOCALAI_IMAGE_NAME}\n restart: unless-stopped\n healthcheck:\n test: ["
},
{
"path": "etc/services/ollama/compose.yml",
"chars": 261,
"preview": "services:\n ollama:\n image: docker.io/ollama/ollama:0.24.0\n restart: unless-stopped\n ports:\n - \"${SERVICE_"
},
{
"path": "etc/services/synapse/compose.yml",
"chars": 887,
"preview": "services:\n postgres:\n image: docker.io/postgres:18.4-alpine\n user: ${UID}:${GID}\n restart: unless-stopped\n "
},
{
"path": "etc/services/synapse/config/homeserver.yaml",
"chars": 47598,
"preview": "#jinja2: lstrip_blocks: \"True\"\n# Configuration file for Synapse.\n#\n# This is a YAML file: see [1] for a quick introducti"
},
{
"path": "etc/services/synapse/config/synapse.127.0.0.1.nip.io.log.config",
"chars": 706,
"preview": "\nversion: 1\n\nformatters:\n precise:\n format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s"
},
{
"path": "etc/services/synapse/config/synapse.127.0.0.1.nip.io.signing.key",
"chars": 59,
"preview": "ed25519 a_FEMe JGs8Fk83GHIrVyhBYa/VRUFbU4+Fxtf8iOsJ7CMamcM\n"
},
{
"path": "justfile",
"chars": 14901,
"preview": "project_name := \"baibot\"\ncontainer_image_name := \"localhost/baibot\"\nproject_container_network := \"baibot\"\n\nadmin_usernam"
},
{
"path": "mise.toml",
"chars": 103,
"preview": "[tools]\nprek = \"0.4.1\"\n\n[settings]\n# Disable automatic trust prompts - we trust this config\nyes = true\n"
},
{
"path": "renovate.json",
"chars": 143,
"preview": "{\n\t\"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n\t\"extends\": [\n\t\t\"config:recommended\"\n\t],\n\t\"labels\": ["
},
{
"path": "rust-toolchain.toml",
"chars": 86,
"preview": "[toolchain]\nchannel = \"1.95.0\"\ncomponents = [\"rustfmt\", \"clippy\"]\nprofile = \"default\"\n"
},
{
"path": "src/agent/definition.rs",
"chars": 1327,
"preview": "use serde::de::Error as DeError;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\n\nuse super::provider::Ag"
},
{
"path": "src/agent/identifier.rs",
"chars": 3122,
"preview": "use std::fmt;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum PublicIdentifier {\n Static(String),\n DynamicGlobal("
},
{
"path": "src/agent/instantiation.rs",
"chars": 5484,
"preview": "use super::{\n AgentDefinition, AgentProvider, PublicIdentifier,\n provider::{self, ControllerType},\n};\n\n// Dead-cod"
},
{
"path": "src/agent/manager.rs",
"chars": 2275,
"preview": "use super::AgentDefinition;\nuse super::PublicIdentifier;\nuse super::instantiation;\nuse super::instantiation::AgentInstan"
},
{
"path": "src/agent/mod.rs",
"chars": 839,
"preview": "mod definition;\nmod identifier;\nmod instantiation;\nmod manager;\npub mod provider;\nmod purpose;\npub mod utils;\n\npub use i"
},
{
"path": "src/agent/provider/anthropic/config.rs",
"chars": 1857,
"preview": "use serde::{Deserialize, Serialize};\n\nuse crate::agent::{default_prompt, provider::ConfigTrait};\n\n#[derive(Debug, Clone,"
},
{
"path": "src/agent/provider/anthropic/controller.rs",
"chars": 8938,
"preview": "use std::fmt::Debug;\nuse std::sync::Arc;\n\nuse anthropic::client::{Client, ClientBuilder};\nuse anthropic::types::ContentB"
},
{
"path": "src/agent/provider/anthropic/mod.rs",
"chars": 1146,
"preview": "mod config;\nmod controller;\nmod utils;\n\npub use config::Config;\npub use controller::Controller;\n\nuse super::super::Agent"
},
{
"path": "src/agent/provider/anthropic/utils.rs",
"chars": 1717,
"preview": "use anthropic::types::{\n ContentBlock, ImageSource, Message, MessagesRequest, MessagesRequestBuilder, Role,\n};\n\nuse c"
},
{
"path": "src/agent/provider/config.rs",
"chars": 72,
"preview": "pub trait ConfigTrait {\n fn validate(&self) -> Result<(), String>;\n}\n"
},
{
"path": "src/agent/provider/controller.rs",
"chars": 7630,
"preview": "use crate::{agent::AgentPurpose, conversation::llm::Conversation};\n\nuse super::{\n ImageEditParams, ImageGenerationPar"
},
{
"path": "src/agent/provider/entity/agent_provider.rs",
"chars": 10536,
"preview": "use crate::agent::AgentPurpose;\n\n#[derive(Debug, Clone)]\npub enum AgentProvider {\n Anthropic,\n Groq,\n LocalAI,\n"
},
{
"path": "src/agent/provider/entity/image.rs",
"chars": 1481,
"preview": "use mxlink::mime;\n\n#[derive(Default)]\npub struct ImageGenerationParams {\n pub smallest_size_possible: bool,\n\n pub "
},
{
"path": "src/agent/provider/entity/mod.rs",
"chars": 547,
"preview": "mod agent_provider;\nmod image;\nmod ping;\nmod speech_to_text;\nmod text_generation;\nmod text_to_speech;\n\npub use agent_pro"
},
{
"path": "src/agent/provider/entity/ping.rs",
"chars": 58,
"preview": "pub enum PingResult {\n Inconclusive,\n Successful,\n}\n"
},
{
"path": "src/agent/provider/entity/speech_to_text.rs",
"chars": 153,
"preview": "#[derive(Default)]\npub struct SpeechToTextParams {\n pub language_override: Option<String>,\n}\n\npub struct SpeechToText"
},
{
"path": "src/agent/provider/entity/text_generation/mod.rs",
"chars": 378,
"preview": "mod prompt_variables;\n\npub use prompt_variables::TextGenerationPromptVariables;\n\n#[derive(Default)]\npub struct TextGener"
},
{
"path": "src/agent/provider/entity/text_generation/prompt_variables.rs",
"chars": 3326,
"preview": "use chrono::{DateTime, Utc};\nuse std::collections::HashMap;\n\npub struct TextGenerationPromptVariables {\n map: HashMap"
},
{
"path": "src/agent/provider/entity/text_to_speech.rs",
"chars": 228,
"preview": "#[derive(Default)]\npub struct TextToSpeechParams {\n pub speed_override: Option<f32>,\n pub voice_override: Option<S"
},
{
"path": "src/agent/provider/groq/mod.rs",
"chars": 723,
"preview": "// Groq is based on openai_compat, because it's not fully compatible with async-openai.\n\nuse super::openai_compat::Confi"
},
{
"path": "src/agent/provider/localai/mod.rs",
"chars": 988,
"preview": "// At the time of testing, LocalAI can be powered by `openai`, but we use `openai_compat` for better reliability\n// in t"
},
{
"path": "src/agent/provider/mistral/mod.rs",
"chars": 576,
"preview": "// Mistral is based on openai_compat, because it's not fully compatible with async-openai.\n\nuse super::openai_compat::Co"
},
{
"path": "src/agent/provider/mod.rs",
"chars": 607,
"preview": "pub mod anthropic;\nmod config;\nmod controller;\nmod entity;\npub(super) mod groq;\npub mod localai;\npub(super) mod mistral;"
},
{
"path": "src/agent/provider/ollama/mod.rs",
"chars": 708,
"preview": "// At the time of testing, Ollama can be powered by `openai`, but we use `openai_compat` for better reliability\n// in th"
},
{
"path": "src/agent/provider/openai/config.rs",
"chars": 6260,
"preview": "use serde::{Deserialize, Serialize};\n\nuse super::OPENAI_IMAGE_MODEL_GPT_IMAGE_1_DOT_5;\nuse crate::agent::{default_prompt"
},
{
"path": "src/agent/provider/openai/controller.rs",
"chars": 23119,
"preview": "use std::ops::Deref;\n\nuse async_openai::{\n Client as OpenAIClient,\n config::OpenAIConfig,\n types::{\n aud"
},
{
"path": "src/agent/provider/openai/mod.rs",
"chars": 1381,
"preview": "mod config;\nmod controller;\nmod utils;\n\npub use config::Config;\npub use controller::Controller;\n\n// openai_compat needs "
},
{
"path": "src/agent/provider/openai/utils.rs",
"chars": 2250,
"preview": "use async_openai::types::responses::{\n EasyInputContent, EasyInputMessage, ImageDetail, InputContent, InputFileArgs,\n"
},
{
"path": "src/agent/provider/openai_compat/config.rs",
"chars": 7306,
"preview": "use serde::{Deserialize, Serialize};\n\nuse crate::agent::default_prompt;\nuse crate::agent::provider::openai::{\n ImageG"
},
{
"path": "src/agent/provider/openai_compat/controller.rs",
"chars": 16199,
"preview": "use etke_openai_api_rust::audio::{AudioApi, AudioBody};\nuse etke_openai_api_rust::chat::{ChatApi, ChatBody};\nuse etke_op"
},
{
"path": "src/agent/provider/openai_compat/mod.rs",
"chars": 2379,
"preview": "// The openai_compat provider aims to support a wider ranger of OpenAI-compatible providers.\n//\n// The `openai` provider"
},
{
"path": "src/agent/provider/openai_compat/utils.rs",
"chars": 3040,
"preview": "use etke_openai_api_rust::{Message, Role};\n\nuse crate::agent::provider::openai::Config as OpenAIConfig;\n\nuse crate::conv"
},
{
"path": "src/agent/provider/openrouter/mod.rs",
"chars": 543,
"preview": "use super::openai_compat::Config;\n\npub fn default_config() -> Config {\n let mut config = Config {\n base_url: \""
},
{
"path": "src/agent/provider/togetherai/mod.rs",
"chars": 557,
"preview": "use super::openai_compat::Config;\n\npub fn default_config() -> Config {\n let mut config = Config {\n base_url: \""
},
{
"path": "src/agent/purpose.rs",
"chars": 1934,
"preview": "#[derive(Debug, Clone, Copy, PartialEq)]\npub enum AgentPurpose {\n CatchAll,\n ImageGeneration,\n TextGeneration,\n"
},
{
"path": "src/agent/utils.rs",
"chars": 4079,
"preview": "use crate::{\n agent::{\n AgentInstance, AgentPurpose, ControllerTrait, Manager as AgentManager, PublicIdentifie"
},
{
"path": "src/bot/implementation.rs",
"chars": 17737,
"preview": "use std::fs;\nuse std::sync::Arc;\nuse std::{future::Future, pin::Pin};\n\nuse mxlink::matrix_sdk::Room;\nuse mxlink::matrix_"
},
{
"path": "src/bot/load_config.rs",
"chars": 5509,
"preview": "use std::env;\nuse std::path::PathBuf;\n\nuse anyhow::anyhow;\n\nuse crate::agent::AgentPurpose;\n\npub use crate::entity::cfg:"
},
{
"path": "src/bot/messaging.rs",
"chars": 9752,
"preview": "use mxlink::matrix_sdk::{\n Room,\n ruma::{\n OwnedEventId, api::client::receipt::create_receipt::v3::ReceiptT"
},
{
"path": "src/bot/mod.rs",
"chars": 149,
"preview": "mod implementation;\nmod load_config;\nmod messaging;\nmod reacting;\nmod rooms;\n\npub use implementation::Bot;\npub use load_"
},
{
"path": "src/bot/reacting.rs",
"chars": 8432,
"preview": "use mxlink::matrix_sdk::{\n Room,\n ruma::{\n OwnedEventId, OwnedUserId,\n events::{\n AnySync"
},
{
"path": "src/bot/rooms.rs",
"chars": 4452,
"preview": "use mxlink::{\n InvitationDecision,\n matrix_sdk::{\n Room,\n ruma::events::{AnySyncTimelineEvent, room:"
},
{
"path": "src/controller/access/determination/mod.rs",
"chars": 1773,
"preview": "#[cfg(test)]\nmod tests;\n\nuse super::super::ControllerType;\n\n#[derive(Debug, PartialEq)]\npub enum AccessControllerType {\n"
},
{
"path": "src/controller/access/determination/tests.rs",
"chars": 2047,
"preview": "#[test]\nfn determine_controller() {\n struct TestCase {\n name: &'static str,\n input: &'static str,\n "
},
{
"path": "src/controller/access/dispatching.rs",
"chars": 1722,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\nuse super::AccessControllerType;\n\n"
},
{
"path": "src/controller/access/help.rs",
"chars": 5430,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle(bot: &Bot, mes"
},
{
"path": "src/controller/access/mod.rs",
"chars": 204,
"preview": "mod determination;\nmod dispatching;\npub mod help;\nmod room_local_agent_managers;\nmod users;\n\npub use determination::{Acc"
},
{
"path": "src/controller/access/room_local_agent_managers.rs",
"chars": 2112,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle_get(bot: &Bot,"
},
{
"path": "src/controller/access/users.rs",
"chars": 1961,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle_get(bot: &Bot,"
},
{
"path": "src/controller/agent/create/mod.rs",
"chars": 12620,
"preview": "#[cfg(test)]\nmod tests;\n\nuse mxlink::MessageResponseType;\n\nuse crate::agent::PublicIdentifier;\nuse crate::agent::provide"
},
{
"path": "src/controller/agent/create/tests.rs",
"chars": 1929,
"preview": "#[test]\nfn agent_config_parsing_works() {\n struct TestCase {\n input: String,\n expected: Option<serde_ya"
},
{
"path": "src/controller/agent/delete/mod.rs",
"chars": 6334,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::entity::{\n MessageContext, globalconfig::GlobalConfigurationManager, roo"
},
{
"path": "src/controller/agent/details/mod.rs",
"chars": 2861,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, agent::PublicIdentifier, entity::MessageContext, strings};\n\npub async"
},
{
"path": "src/controller/agent/determination/mod.rs",
"chars": 3530,
"preview": "#[cfg(test)]\nmod tests;\n\nuse crate::{agent::PublicIdentifier, controller::ControllerType, strings};\n\n#[derive(Debug, Par"
},
{
"path": "src/controller/agent/determination/tests.rs",
"chars": 5007,
"preview": "#[test]\nfn determine_controller() {\n use crate::agent::PublicIdentifier;\n\n struct TestCase {\n name: &'stati"
},
{
"path": "src/controller/agent/help/mod.rs",
"chars": 2507,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle(bot: &Bot, mes"
},
{
"path": "src/controller/agent/list/mod.rs",
"chars": 1227,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::agent::AgentPurpose;\nuse crate::strings;\nuse crate::{Bot, entity::MessageCo"
},
{
"path": "src/controller/agent/mod.rs",
"chars": 1600,
"preview": "use crate::{Bot, entity::MessageContext};\n\npub mod create;\npub mod delete;\npub mod details;\npub mod determination;\npub m"
},
{
"path": "src/controller/cfg/common/generic_setting.rs",
"chars": 993,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle_get<T>(\n bo"
},
{
"path": "src/controller/cfg/common/mod.rs",
"chars": 32,
"preview": "pub(super) mod generic_setting;\n"
},
{
"path": "src/controller/cfg/controller_type.rs",
"chars": 2367,
"preview": "use crate::{\n agent::{AgentPurpose, PublicIdentifier},\n entity::roomconfig::{\n SpeechToTextFlowType, Speech"
},
{
"path": "src/controller/cfg/determination/mod.rs",
"chars": 4826,
"preview": "#[cfg(test)]\nmod tests;\n\nmod speech_to_text;\nmod text_generation;\nmod text_to_speech;\n\nuse crate::{\n agent::{AgentPur"
},
{
"path": "src/controller/cfg/determination/speech_to_text/mod.rs",
"chars": 4323,
"preview": "#[cfg(test)]\nmod tests;\n\nuse crate::{\n controller::ControllerType,\n entity::roomconfig::{\n SpeechToTextFlow"
},
{
"path": "src/controller/cfg/determination/speech_to_text/tests.rs",
"chars": 4523,
"preview": "#[test]\nfn determine_controller_other() {\n use super::ConfigSpeechToTextSettingRelatedControllerType;\n use super::"
},
{
"path": "src/controller/cfg/determination/tests.rs",
"chars": 11599,
"preview": "#[test]\nfn determine_controller() {\n use super::super::controller_type;\n use crate::agent::{AgentPurpose, PublicId"
},
{
"path": "src/controller/cfg/determination/text_generation/mod.rs",
"chars": 7923,
"preview": "#[cfg(test)]\nmod tests;\n\nuse crate::{\n controller::ControllerType,\n entity::roomconfig::{\n TextGenerationAu"
},
{
"path": "src/controller/cfg/determination/text_generation/tests.rs",
"chars": 14360,
"preview": "#[test]\nfn determine_controller_other() {\n use super::ConfigTextGenerationSettingRelatedControllerType;\n use super"
},
{
"path": "src/controller/cfg/determination/text_to_speech/mod.rs",
"chars": 5107,
"preview": "#[cfg(test)]\nmod tests;\n\nuse crate::{\n controller::ControllerType,\n entity::roomconfig::{TextToSpeechBotMessagesFl"
},
{
"path": "src/controller/cfg/determination/text_to_speech/tests.rs",
"chars": 8725,
"preview": "#[test]\nfn determine_controller_other() {\n use super::ConfigTextToSpeechSettingRelatedControllerType;\n use super::"
},
{
"path": "src/controller/cfg/dispatching/mod.rs",
"chars": 4223,
"preview": "use crate::strings;\nuse crate::{Bot, entity::MessageContext};\nuse mxlink::MessageResponseType;\n\nuse super::controller_ty"
},
{
"path": "src/controller/cfg/dispatching/speech_to_text.rs",
"chars": 4510,
"preview": "use crate::entity::roomconfig::{\n RoomSettings, SpeechToTextFlowType,\n SpeechToTextMessageTypeForNonThreadedOnlyTr"
},
{
"path": "src/controller/cfg/dispatching/text_generation.rs",
"chars": 7614,
"preview": "use crate::entity::roomconfig::{\n RoomSettings, TextGenerationAutoUsage, TextGenerationPrefixRequirementType,\n Tex"
},
{
"path": "src/controller/cfg/dispatching/text_to_speech.rs",
"chars": 5300,
"preview": "use crate::entity::roomconfig::{\n RoomSettings, TextToSpeechBotMessagesFlowType, TextToSpeechUserMessagesFlowType,\n};"
},
{
"path": "src/controller/cfg/global_config/generic_setting.rs",
"chars": 1021,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::entity::{MessageContext, roomconfig::RoomSettings};\nuse crate::{Bot, string"
},
{
"path": "src/controller/cfg/global_config/handler.rs",
"chars": 5162,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n agent::{AgentPurpose, PublicIdentifier},\n entity::{Messag"
},
{
"path": "src/controller/cfg/global_config/mod.rs",
"chars": 56,
"preview": "pub(super) mod generic_setting;\npub(super) mod handler;\n"
},
{
"path": "src/controller/cfg/help.rs",
"chars": 18700,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n entity::{\n MessageContext,\n roomconfig::{\n "
},
{
"path": "src/controller/cfg/mod.rs",
"chars": 262,
"preview": "mod common;\nmod controller_type;\nmod determination;\nmod dispatching;\nmod global_config;\nmod help;\nmod room_config;\nmod s"
},
{
"path": "src/controller/cfg/room_config/generic_setting.rs",
"chars": 1017,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::entity::{MessageContext, roomconfig::RoomSettings};\nuse crate::{Bot, string"
},
{
"path": "src/controller/cfg/room_config/handler.rs",
"chars": 4334,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n agent::{AgentPurpose, PublicIdentifier},\n entity::Message"
},
{
"path": "src/controller/cfg/room_config/mod.rs",
"chars": 56,
"preview": "pub(super) mod generic_setting;\npub(super) mod handler;\n"
},
{
"path": "src/controller/cfg/status.rs",
"chars": 25485,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n agent::{\n AgentInstance, AgentPurpose, ControllerTrai"
},
{
"path": "src/controller/chat_completion/mod.rs",
"chars": 34028,
"preview": "use mxlink::matrix_sdk::ruma::OwnedEventId;\nuse mxlink::matrix_sdk::ruma::events::room::message::AudioMessageEventConten"
},
{
"path": "src/controller/controller_type.rs",
"chars": 548,
"preview": "#[derive(Debug, PartialEq)]\npub enum ControllerType {\n // Denotes that the message is to be ignored.\n Ignore,\n\n "
},
{
"path": "src/controller/determination/mod.rs",
"chars": 5987,
"preview": "#[cfg(test)]\nmod tests;\n\nuse super::chat_completion::ChatCompletionControllerType;\nuse crate::{\n entity::{\n In"
},
{
"path": "src/controller/determination/tests.rs",
"chars": 7483,
"preview": "#[test]\nfn determine_text_controller() {\n use super::super::chat_completion::ChatCompletionControllerType;\n use su"
},
{
"path": "src/controller/dispatching.rs",
"chars": 3856,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\nuse super::ControllerType;\n\npub as"
},
{
"path": "src/controller/help/mod.rs",
"chars": 2912,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\npub async fn handle(bot: &Bot, mes"
},
{
"path": "src/controller/image/determination/mod.rs",
"chars": 438,
"preview": "use crate::controller::ControllerType;\nmod tests;\n\npub fn determine_controller(text: &str) -> ControllerType {\n let t"
},
{
"path": "src/controller/image/determination/tests.rs",
"chars": 1231,
"preview": "#[test]\nfn determine_controller() {\n struct TestCase {\n name: &'static str,\n input: &'static str,\n "
},
{
"path": "src/controller/image/edit.rs",
"chars": 4854,
"preview": "use mxlink::{MatrixLink, MessageResponseType};\n\nuse tracing::Instrument;\n\nuse crate::agent::AgentPurpose;\nuse crate::age"
},
{
"path": "src/controller/image/generation.rs",
"chars": 6875,
"preview": "use mxlink::{MatrixLink, MessageResponseType};\n\nuse tracing::Instrument;\n\nuse crate::agent::AgentPurpose;\nuse crate::age"
},
{
"path": "src/controller/image/mod.rs",
"chars": 111,
"preview": "mod determination;\npub mod edit;\npub mod generation;\nmod prompt;\n\npub use determination::determine_controller;\n"
},
{
"path": "src/controller/image/prompt.rs",
"chars": 5276,
"preview": "use crate::conversation::llm::{Author, Message, MessageContent};\n\n/// Builds a prompt from the original prompt and other"
},
{
"path": "src/controller/join/mod.rs",
"chars": 886,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::entity::RoomConfigContext;\nuse crate::{Bot, strings};\n\npub async fn handle("
},
{
"path": "src/controller/mod.rs",
"chars": 361,
"preview": "mod controller_type;\n\npub mod access;\npub mod agent;\npub mod cfg;\npub mod chat_completion;\nmod determination;\nmod dispat"
},
{
"path": "src/controller/provider/mod.rs",
"chars": 3338,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, agent::AgentProvider, entity::MessageContext, strings};\n\nuse super::C"
},
{
"path": "src/controller/reaction/mod.rs",
"chars": 1373,
"preview": "use std::ops::Deref;\n\nuse mxlink::MatrixLink;\n\nuse crate::{\n Bot,\n agent::AgentPurpose,\n entity::{MessageContex"
},
{
"path": "src/controller/reaction/text_to_speech.rs",
"chars": 3485,
"preview": "use mxlink::{MatrixLink, MessageResponseType};\n\nuse mxlink::matrix_sdk::ruma::{\n OwnedEventId, OwnedUserId, events::r"
},
{
"path": "src/controller/usage/mod.rs",
"chars": 585,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{Bot, entity::MessageContext, strings};\n\nuse super::ControllerType;\n\npub fn"
},
{
"path": "src/controller/utils/agent.rs",
"chars": 2164,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n agent::{\n AgentInstance, AgentPurpose,\n utils:"
},
{
"path": "src/controller/utils/mod.rs",
"chars": 774,
"preview": "use mxlink::MessageResponseType;\n\nuse crate::{\n Bot,\n entity::{MessageContext, MessagePayload},\n};\n\npub mod agent;"
},
{
"path": "src/controller/utils/text_to_speech.rs",
"chars": 4626,
"preview": "use mxlink::matrix_sdk::ruma::OwnedEventId;\nuse mxlink::{MatrixLink, MessageResponseType};\n\nuse tracing::Instrument;\n\nus"
},
{
"path": "src/conversation/llm/entity.rs",
"chars": 11205,
"preview": "use chrono::{DateTime, Utc};\nuse mxlink::matrix_sdk::ruma::OwnedUserId;\nuse mxlink::matrix_sdk::ruma::events::room::mess"
},
{
"path": "src/conversation/llm/mod.rs",
"chars": 165,
"preview": "mod entity;\nmod tokenization;\nmod utils;\n\n#[cfg(test)]\nmod tests;\n\npub use entity::*;\npub use tokenization::shorten_mess"
},
{
"path": "src/conversation/llm/tests.rs",
"chars": 4597,
"preview": "use mxlink::matrix_sdk::ruma::OwnedUserId;\n\nuse crate::utils::status::create_error_message_text;\nuse crate::utils::text_"
},
{
"path": "src/conversation/llm/tokenization.rs",
"chars": 9749,
"preview": "use tiktoken_rs::CoreBPE;\nuse tiktoken_rs::bpe_for_tokenizer;\nuse tiktoken_rs::tokenizer;\n\nuse super::{Author, Message, "
},
{
"path": "src/conversation/llm/utils.rs",
"chars": 4899,
"preview": "use mxlink::matrix_sdk::ruma::OwnedUserId;\n\nuse super::entity::{Author, FileDetails, ImageDetails, Message, MessageConte"
},
{
"path": "src/conversation/matrix/entity.rs",
"chars": 2011,
"preview": "use chrono::{DateTime, Utc};\nuse regex::Regex;\n\nuse mxlink::matrix_sdk::ruma::OwnedUserId;\nuse mxlink::matrix_sdk::ruma:"
},
{
"path": "src/conversation/matrix/mod.rs",
"chars": 318,
"preview": "mod entity;\nmod room_display_name_fetcher;\nmod room_event_fetcher;\nmod utils;\n\npub(crate) use room_display_name_fetcher:"
},
{
"path": "src/conversation/matrix/room_display_name_fetcher.rs",
"chars": 1593,
"preview": "use mxlink::matrix_sdk::Room;\nuse mxlink::matrix_sdk::ruma::OwnedRoomId;\n\nuse mxlink::MatrixLink;\nuse quick_cache::sync:"
},
{
"path": "src/conversation/matrix/room_event_fetcher.rs",
"chars": 1340,
"preview": "use mxlink::matrix_sdk::Room;\nuse mxlink::matrix_sdk::deserialized_responses::TimelineEvent;\nuse mxlink::matrix_sdk::rum"
},
{
"path": "src/conversation/matrix/utils/mod.rs",
"chars": 24209,
"preview": "#[cfg(test)]\nmod tests;\n\nuse std::sync::Arc;\n\nuse mxlink::matrix_sdk::ruma::{OwnedEventId, OwnedUserId};\nuse mxlink::mat"
},
{
"path": "src/conversation/matrix/utils/tests.rs",
"chars": 11753,
"preview": "use chrono::{TimeZone, Utc};\n\nuse mxlink::matrix_sdk::ruma::OwnedUserId;\n\nuse crate::conversation::matrix::{\n MatrixM"
},
{
"path": "src/conversation/matrix_llm_bridge.rs",
"chars": 2025,
"preview": "use std::sync::Arc;\n\nuse mxlink::MatrixLink;\nuse mxlink::matrix_sdk::ruma::OwnedEventId;\n\nuse crate::conversation::matri"
},
{
"path": "src/conversation/mod.rs",
"chars": 201,
"preview": "pub(crate) mod llm;\npub(crate) mod matrix;\nmod matrix_llm_bridge;\n\npub(crate) use matrix_llm_bridge::{\n create_llm_co"
},
{
"path": "src/entity/catch_up_marker/delayed_catch_up_marker_manager.rs",
"chars": 8370,
"preview": "use std::sync::Arc;\n\nuse tokio::sync::Mutex;\nuse tokio::time::Duration;\n\nuse mxlink::helpers::account_data_config::Confi"
},
{
"path": "src/entity/catch_up_marker/entity.rs",
"chars": 1023,
"preview": "use mxlink::matrix_sdk::ruma::events::macros::EventContent;\n\nuse serde::{Deserialize, Serialize};\n\nuse mxlink::helpers::"
},
{
"path": "src/entity/catch_up_marker/mod.rs",
"chars": 394,
"preview": "mod delayed_catch_up_marker_manager;\nmod entity;\n\nuse mxlink::helpers::account_data_config::GlobalConfigManager as Accou"
},
{
"path": "src/entity/cfg/config.rs",
"chars": 16582,
"preview": "use std::path::PathBuf;\n\nuse mxlink::helpers::encryption::EncryptionKey;\nuse mxlink::matrix_sdk::ruma::{OwnedDeviceId, O"
},
{
"path": "src/entity/cfg/config_tests.rs",
"chars": 3250,
"preview": "use super::{Avatar, ConfigUser, ConfigUserAuth, ConfigUserEncryption};\nuse crate::entity::cfg::env;\n\nfn base_user() -> C"
},
{
"path": "src/entity/cfg/defaults.rs",
"chars": 869,
"preview": "const CONFIG_FILE_PATH: &str = \"config.yml\";\n\nconst NAME: &str = \"baibot\";\nconst COMMAND_PREFIX: &str = \"!bai\";\n\nconst P"
},
{
"path": "src/entity/cfg/env.rs",
"chars": 2213,
"preview": "pub const BAIBOT_CONFIG_FILE_PATH: &str = \"BAIBOT_CONFIG_FILE_PATH\";\n\npub const BAIBOT_HOMESERVER_SERVER_NAME: &str = \"B"
},
{
"path": "src/entity/cfg/mod.rs",
"chars": 94,
"preview": "mod config;\npub mod defaults;\npub mod env;\n\npub use config::{Avatar, Config, ConfigUserAuth};\n"
},
{
"path": "src/entity/globalconfig/entity.rs",
"chars": 2020,
"preview": "use mxlink::matrix_sdk::ruma::events::macros::EventContent;\n\nuse serde::{Deserialize, Serialize};\n\nuse mxlink::helpers::"
},
{
"path": "src/entity/globalconfig/mod.rs",
"chars": 288,
"preview": "mod entity;\n\nuse mxlink::helpers::account_data_config::GlobalConfigManager as AccountDataGlobalConfigManager;\n\npub use e"
},
{
"path": "src/entity/interaction_context.rs",
"chars": 258,
"preview": "use mxlink::ThreadInfo;\n\nuse super::MessagePayload;\n\npub struct InteractionContext {\n pub thread_info: ThreadInfo,\n "
},
{
"path": "src/entity/message_context.rs",
"chars": 3287,
"preview": "use mxlink::matrix_sdk::Room;\nuse mxlink::matrix_sdk::ruma::{OwnedEventId, OwnedUserId, RoomId};\n\nuse mxlink::ThreadInfo"
},
{
"path": "src/entity/message_payload.rs",
"chars": 2957,
"preview": "use mxlink::matrix_sdk::ruma::events::room::message::{\n AudioMessageEventContent, FileMessageEventContent, ImageMessa"
},
{
"path": "src/entity/mod.rs",
"chars": 444,
"preview": "pub mod catch_up_marker;\npub mod cfg;\npub mod globalconfig;\nmod interaction_context;\nmod message_context;\nmod message_pa"
},
{
"path": "src/entity/room_config_context.rs",
"chars": 7457,
"preview": "use mxlink::matrix_sdk::ruma::OwnedUserId;\n\nuse super::globalconfig::GlobalConfig;\nuse super::roomconfig::RoomConfig;\n\nu"
},
{
"path": "src/entity/roomconfig/defaults.rs",
"chars": 1409,
"preview": "use super::{SpeechToTextFlowType, SpeechToTextMessageTypeForNonThreadedOnlyTranscribedMessages};\nuse super::{\n TextGe"
},
{
"path": "src/entity/roomconfig/entity/handler.rs",
"chars": 2055,
"preview": "use serde::{Deserialize, Serialize};\n\nuse crate::agent::AgentPurpose;\n\n#[derive(Clone, Debug, Default, Deserialize, Seri"
},
{
"path": "src/entity/roomconfig/entity/mod.rs",
"chars": 3247,
"preview": "use mxlink::helpers::account_data_config::RoomConfig as RoomConfigTrait;\nuse mxlink::helpers::account_data_config::RoomC"
},
{
"path": "src/entity/roomconfig/entity/speech_to_text.rs",
"chars": 4157,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Clone, Debug, Default, Deserialize, Serialize)]\npub struct RoomSettingsSp"
},
{
"path": "src/entity/roomconfig/entity/text_generation.rs",
"chars": 5470,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Clone, Debug, Default, Deserialize, Serialize)]\npub struct RoomSettingsTe"
},
{
"path": "src/entity/roomconfig/entity/text_to_speech.rs",
"chars": 3852,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Clone, Debug, Default, Deserialize, Serialize)]\npub struct RoomSettingsTe"
},
{
"path": "src/entity/roomconfig/mod.rs",
"chars": 604,
"preview": "pub mod defaults;\nmod entity;\n\nuse mxlink::helpers::account_data_config::RoomConfigManager as AccountDataRoomConfigManag"
},
{
"path": "src/entity/trigger_event_info.rs",
"chars": 569,
"preview": "use mxlink::matrix_sdk::ruma::{OwnedEventId, OwnedUserId};\n\nuse super::MessagePayload;\n\n#[derive(Debug)]\npub struct Trig"
},
{
"path": "src/lib.rs",
"chars": 469,
"preview": "// rustc 1.94+ trips a query-depth overflow when computing async layouts in\n// the matrix-sdk timeline future graph. mat"
},
{
"path": "src/main.rs",
"chars": 881,
"preview": "use tracing_subscriber::EnvFilter;\nuse tracing_subscriber::fmt::format::FmtSpan;\n\nuse baibot::{Bot, Config, load_config}"
},
{
"path": "src/strings/access.rs",
"chars": 969,
"preview": "pub fn users_no_patterns() -> String {\n \"No user patterns are configured, so the bot can only be used by administrato"
},
{
"path": "src/strings/agent.rs",
"chars": 11480,
"preview": "use crate::{\n agent::{AgentInstance, AgentProvider, AgentPurpose, ControllerTrait, PublicIdentifier},\n utils::text"
},
{
"path": "src/strings/cfg.rs",
"chars": 11040,
"preview": "use crate::{\n agent::{\n AgentInstance, AgentPurpose, PublicIdentifier,\n utils::AgentForPurposeDetermina"
},
{
"path": "src/strings/error.rs",
"chars": 611,
"preview": "pub fn unknown_command_see_help(command_prefix: &str) -> String {\n format!(\"Unknown command. See help (`{command_pref"
},
{
"path": "src/strings/global_config.rs",
"chars": 2050,
"preview": "use crate::agent::{AgentPurpose, PublicIdentifier};\n\npub fn no_permissions_to_administrate() -> &'static str {\n \"You "
},
{
"path": "src/strings/help/access.rs",
"chars": 2921,
"preview": "pub fn heading() -> String {\n \"🔒 Access\".to_owned()\n}\n\npub fn intro() -> String {\n \"This bot employs access contro"
}
]
// ... and 21 more files (download for full content)
About this extraction
This page contains the full source code of the etkecc/baibot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 221 files (877.6 KB), approximately 204.5k tokens, and a symbol index with 914 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.