docs: align engine terminology in telegram and docs (#162)

This commit is contained in:
banteg
2026-01-17 13:55:49 +04:00
committed by GitHub
parent 0818e848b3
commit 9d7c6fcd8c
26 changed files with 64 additions and 63 deletions
+1 -1
View File
@@ -165,7 +165,7 @@ sequenceDiagram
Command->>RunnerBridge: run_one/run_many (optional) Command->>RunnerBridge: run_one/run_many (optional)
RunnerBridge->>Telegram: Send progress/final RunnerBridge->>Telegram: Send progress/final
else Default routing else Default routing
Bridge->>Bridge: Parse directives<br/>(/engine, /project, @branch) Bridge->>Bridge: Parse directives<br/>(/&lt;engine-id&gt;, /&lt;project-alias&gt;, @branch)
Bridge->>Bridge: Extract resume token<br/>from reply Bridge->>Bridge: Extract resume token<br/>from reply
Bridge->>Bridge: Resolve worktree<br/>(if @branch) Bridge->>Bridge: Resolve worktree<br/>(if @branch)
+1 -1
View File
@@ -72,7 +72,7 @@ This lets you:
## IDs and collisions ## IDs and collisions
Entrypoint names become plugin IDs and appear in user-facing surfaces (CLI subcommands, Telegram commands, `/engine` directives). Entrypoint names become plugin IDs and appear in user-facing surfaces (CLI subcommands, Telegram commands, `/<engine-id>` directives).
Takopi validates IDs and rejects collisions with reserved names. Takopi validates IDs and rejects collisions with reserved names.
Plugin IDs must match: Plugin IDs must match:
+1 -1
View File
@@ -27,7 +27,7 @@ Reply-to-continue works even if topics or chat sessions are enabled.
For each message, Takopi: For each message, Takopi:
- parses directive prefixes (`/engine`, `/project`, `@branch`) from the first non-empty line - parses directive prefixes (`/<engine-id>`, `/<project-alias>`, `@branch`) from the first non-empty line
- attempts to extract a resume token by polling available runners - attempts to extract a resume token by polling available runners
- if a resume token is found, routes to the matching runner; otherwise uses the configured default engine - if a resume token is found, routes to the matching runner; otherwise uses the configured default engine
+1 -2
View File
@@ -29,7 +29,7 @@ Use `/agent`:
- In normal chats, it affects the whole chat. - In normal chats, it affects the whole chat.
- In group chats, only admins can change defaults. - In group chats, only admins can change defaults.
Selection precedence (highest to lowest): resume token → `/engine` directive → topic default → chat default → project default → global default. Selection precedence (highest to lowest): resume token → `/<engine-id>` directive → topic default → chat default → project default → global default.
## Engine installation ## Engine installation
@@ -40,4 +40,3 @@ Takopi shells out to engine CLIs. Install them and make sure theyre on your `
- [Commands & directives](../reference/commands-and-directives.md) - [Commands & directives](../reference/commands-and-directives.md)
- [Config reference](../reference/config.md) - [Config reference](../reference/config.md)
+3 -3
View File
@@ -1,6 +1,6 @@
# Topics # Topics
Topics bind Telegram **forum threads** to a project/branch context. Each topic keeps its own session and default agent, which is ideal for teams or multi-project work. Topics bind Telegram **forum threads** to a project/branch context. Each topic keeps its own session and default engine, which is ideal for teams or multi-project work.
!!! tip "Workspace workflow" !!! tip "Workspace workflow"
If you chose the **workspace** workflow during [onboarding](../tutorials/install.md), topics are already enabled. This guide covers advanced topic configuration and usage. If you chose the **workspace** workflow during [onboarding](../tutorials/install.md), topics are already enabled. This guide covers advanced topic configuration and usage.
@@ -9,7 +9,7 @@ Topics bind Telegram **forum threads** to a project/branch context. Each topic k
- Keep each thread tied to a repo + branch - Keep each thread tied to a repo + branch
- Avoid context collisions in busy team chats - Avoid context collisions in busy team chats
- Set a default agent per topic with `/agent set` - Set a default engine per topic with `/agent set`
## Requirements checklist ## Requirements checklist
@@ -76,7 +76,7 @@ Note: Outside topics (private chats or main group chats), `/ctx` binds the chat
Use `/new` inside the topic to clear stored sessions for that thread. Use `/new` inside the topic to clear stored sessions for that thread.
## Set a default agent per topic ## Set a default engine per topic
Use `/agent set` inside the topic: Use `/agent set` inside the topic:
+1 -1
View File
@@ -44,7 +44,7 @@ echo ".worktrees/" >> ~/.config/git/ignore
## Context persistence ## Context persistence
When project/worktree context is active, Takopi includes a `ctx:` footer in messages. When project/worktree context is active, Takopi includes a `ctx:` footer in messages.
When you reply, this context carries forward (you usually dont need to repeat `/project @branch`). When you reply, this context carries forward (you usually dont need to repeat `/<project-alias> @branch`).
## Related ## Related
+3 -1
View File
@@ -24,7 +24,9 @@ mytransport = "mytransport.backend:BACKEND"
mycommand = "mycommand.backend:BACKEND" mycommand = "mycommand.backend:BACKEND"
``` ```
## Engine backend plugin (runner) ## Engine backend plugin
An engine backend builds a `Runner` via `build_runner(...)`.
Minimal example: Minimal example:
+1 -1
View File
@@ -68,7 +68,7 @@ Step-by-step guides for new users:
1. [Install & onboard](tutorials/install.md) — set up Takopi and your bot 1. [Install & onboard](tutorials/install.md) — set up Takopi and your bot
2. [First run](tutorials/first-run.md) — send a task, watch it stream, continue the conversation 2. [First run](tutorials/first-run.md) — send a task, watch it stream, continue the conversation
3. [Projects & branches](tutorials/projects-and-branches.md) — target repos from anywhere, run on feature branches 3. [Projects & branches](tutorials/projects-and-branches.md) — target repos from anywhere, run on feature branches
4. [Multi-engine](tutorials/multi-engine.md) — use different agents for different tasks 4. [Multi-engine](tutorials/multi-engine.md) — use different engines for different tasks
## How-to guides ## How-to guides
+3 -3
View File
@@ -8,8 +8,8 @@ Takopi parses the first non-empty line of a message for a directive prefix.
| Directive | Example | Effect | | Directive | Example | Effect |
|----------|---------|--------| |----------|---------|--------|
| `/engine` | `/codex fix flaky test` | Select an engine for this message. | | `/<engine-id>` | `/codex fix flaky test` | Select an engine for this message. |
| `/project` | `/happy-gadgets add escape-pod` | Select a project alias. | | `/<project-alias>` | `/happy-gadgets add escape-pod` | Select a project alias. |
| `@branch` | `@feat/happy-camera rewind to checkpoint` | Run in a worktree for the branch. | | `@branch` | `@feat/happy-camera rewind to checkpoint` | Run in a worktree for the branch. |
| Combined | `/happy-gadgets @feat/flower-pin observe unseen` | Project + branch. | | Combined | `/happy-gadgets @feat/flower-pin observe unseen` | Project + branch. |
@@ -35,7 +35,7 @@ This line is parsed from replies and takes precedence over new directives.
| Command | Description | | Command | Description |
|---------|-------------| |---------|-------------|
| `/cancel` | Reply to the progress message to stop the current run. | | `/cancel` | Reply to the progress message to stop the current run. |
| `/agent` | Show/set the default agent for the current scope. | | `/agent` | Show/set the default engine for the current scope. |
| `/model` | Show/set the model override for the current scope. | | `/model` | Show/set the model override for the current scope. |
| `/reasoning` | Show/set the reasoning override for the current scope. | | `/reasoning` | Show/set the reasoning override for the current scope. |
| `/trigger` | Show/set trigger mode (mentions-only vs all). | | `/trigger` | Show/set trigger mode (mentions-only vs all). |
+3 -3
View File
@@ -92,8 +92,8 @@ Takopi parses the first non-empty line of a message for a directive prefix.
Supported directives: Supported directives:
- `/engine` or `/engine@bot`: chooses the engine - `/<engine-id>` or `/<engine-id>@bot`: chooses the engine
- `/project`: chooses a project alias - `/<project-alias>`: chooses a project alias
- `@branch`: chooses a git branch/worktree - `@branch`: chooses a git branch/worktree
Rules: Rules:
@@ -117,7 +117,7 @@ The `ctx:` line is parsed from replies and takes precedence over new directives.
When a message arrives in a chat whose `chat_id` matches `projects.<alias>.chat_id`, When a message arrives in a chat whose `chat_id` matches `projects.<alias>.chat_id`,
Takopi defaults the project context to that alias unless a reply `ctx:` or explicit Takopi defaults the project context to that alias unless a reply `ctx:` or explicit
`/project` directive is present. `/<project-alias>` directive is present.
In non-topic chats, `/ctx` can bind a chat context. That bound context is treated as In non-topic chats, `/ctx` can bind a chat context. That bound context is treated as
ambient and takes precedence over the default project mapping until cleared. ambient and takes precedence over the default project mapping until cleared.
+1 -1
View File
@@ -8,7 +8,7 @@ If youre trying to understand the *why*, use **[Explanation](../explanation/i
## Most-used reference pages ## Most-used reference pages
- [Commands & directives](commands-and-directives.md) - [Commands & directives](commands-and-directives.md)
- Message prefixes like `/engine`, `/project`, and `@branch` - Message prefixes like `/<engine-id>`, `/<project-alias>`, and `@branch`
- In-chat commands like `/cancel`, `/new`, `/ctx`, `/file …`, `/topic …` - In-chat commands like `/cancel`, `/new`, `/ctx`, `/file …`, `/topic …`
- [Configuration](config.md) - [Configuration](config.md)
- `takopi.toml` options and defaults - `takopi.toml` options and defaults
+1 -1
View File
@@ -65,7 +65,7 @@ To restore “only respond when invoked” behavior, use trigger mode:
Explicit invocation includes any of: Explicit invocation includes any of:
- `@botname` mention in the message. - `@botname` mention in the message.
- `/engine` or `/project_alias` as the first token. - `/<engine-id>` or `/<project-alias>` as the first token.
- Replying to a bot message. - Replying to a bot message.
- Built-in or plugin slash commands (for example `/agent`, `/model`, `/reasoning`, `/file`, `/trigger`). - Built-in or plugin slash commands (for example `/agent`, `/model`, `/reasoning`, `/file`, `/trigger`).
+1 -1
View File
@@ -38,7 +38,7 @@ To pin a project or branch for the chat, use:
`/new` clears the session but keeps the bound context. `/new` clears the session but keeps the bound context.
Tip: set a default agent for this chat with `/agent set claude`. Tip: set a default engine for this chat with `/agent set claude`.
## Stateless (reply-to-continue) ## Stateless (reply-to-continue)
+3 -3
View File
@@ -19,7 +19,7 @@ Takopi keeps running in your terminal. In Telegram, your bot will post a startup
🐙 takopi is ready 🐙 takopi is ready
default: codex<br> default: codex<br>
agents: codex, claude<br> engines: codex, claude<br>
projects: none<br> projects: none<br>
mode: chat<br> mode: chat<br>
topics: disabled<br> topics: disabled<br>
@@ -29,7 +29,7 @@ Takopi keeps running in your terminal. In Telegram, your bot will post a startup
The engines/projects list reflects your setup. This tells you: The engines/projects list reflects your setup. This tells you:
- Which engine is the default - Which engine is the default
- Which agents are available (and any missing ones) - Which engines are available (and any missing ones)
- Which projects are registered - Which projects are registered
- Which directory Takopi will run in - Which directory Takopi will run in
@@ -131,7 +131,7 @@ If a resume token was already issued (and resume lines are enabled), it will sti
## 7. Try a different engine ## 7. Try a different engine
Want to use a different agent for one message? Prefix your message with `/<engine>`: Want to use a different engine for one message? Prefix your message with `/<engine>`:
!!! user "You" !!! user "You"
/claude explain the error handling in this codebase /claude explain the error handling in this codebase
+3 -3
View File
@@ -228,9 +228,9 @@ Once Takopi receives your message:
Takopi scans your PATH for installed agent CLIs: Takopi scans your PATH for installed agent CLIs:
``` ```
step 4: default agent step 4: default engine
takopi runs these agents on your computer. switch anytime with /agent. takopi runs these engines on your computer. switch anytime with /agent.
engine status install command engine status install command
─────────────────────────────────────────── ───────────────────────────────────────────
@@ -239,7 +239,7 @@ takopi runs these agents on your computer. switch anytime with /agent.
opencode ✗ not found npm install -g opencode-ai@latest opencode ✗ not found npm install -g opencode-ai@latest
pi ✗ not found npm install -g @mariozechner/pi-coding-agent pi ✗ not found npm install -g @mariozechner/pi-coding-agent
? choose default agent: ? choose default engine:
codex codex
claude claude
``` ```
+7 -7
View File
@@ -1,14 +1,14 @@
# Multi-engine workflows # Multi-engine workflows
This tutorial shows you how to use different agents for different tasks and set up defaults so you don't have to think about it. This tutorial shows you how to use different engines for different tasks and set up defaults so you don't have to think about it.
**What you'll learn:** Engine directives, persistent defaults, and when to use which agent. **What you'll learn:** Engine directives, persistent defaults, and when to use which engine.
## Why multiple engines? ## Why multiple engines?
Different agents have different strengths: Different engines have different strengths:
| Agent | Good at | | Engine | Good at |
|-------|---------| |-------|---------|
| **Codex** | Fast edits, shell commands, quick fixes | | **Codex** | Fast edits, shell commands, quick fixes |
| **Claude Code** | Complex refactors, architecture, long context | | **Claude Code** | Complex refactors, architecture, long context |
@@ -65,7 +65,7 @@ Use `/agent set` to change the default for the current scope:
Response: Response:
!!! takopi "Takopi" !!! takopi "Takopi"
chat default agent set to claude chat default engine set to claude
Now all new conversations in this chat use Claude (unless you explicitly override with `/codex`). Now all new conversations in this chat use Claude (unless you explicitly override with `/codex`).
@@ -77,7 +77,7 @@ Check the current default:
Example response: Example response:
!!! takopi "Takopi" !!! takopi "Takopi"
agent: claude (chat default)<br> engine: claude (chat default)<br>
defaults: topic: none, chat: claude, project: none, global: codex<br> defaults: topic: none, chat: claude, project: none, global: codex<br>
available: codex, claude, opencode, pi available: codex, claude, opencode, pi
@@ -89,7 +89,7 @@ Clear it:
Response: Response:
!!! takopi "Takopi" !!! takopi "Takopi"
chat default agent cleared. chat default engine cleared.
## 4. Defaults in topics ## 4. Defaults in topics
+3 -3
View File
@@ -2,7 +2,7 @@
This tutorial shows you how to register repos as projects and run tasks on feature branches without switching directories. This tutorial shows you how to register repos as projects and run tasks on feature branches without switching directories.
**What you'll learn:** How to target repos from anywhere with `/project`, and run on branches with `@branch`. **What you'll learn:** How to target repos from anywhere with `/<project-alias>`, and run on branches with `@branch`.
## The problem ## The problem
@@ -123,7 +123,7 @@ Replies stay on the same branch. Your main checkout is untouched.
## 5. Context persistence ## 5. Context persistence
Once you've set a context (via `/project @branch` or by replying), it sticks: Once you've set a context (via `/<project-alias> @branch` or by replying), it sticks:
!!! user "You" !!! user "You"
/happy-gadgets @feat/new-login add tests /happy-gadgets @feat/new-login add tests
@@ -155,7 +155,7 @@ If you mostly work in one repo, set it as the default:
default_project = "happy-gadgets" default_project = "happy-gadgets"
``` ```
Now messages without a `/project` prefix go to that repo: Now messages without a `/<project-alias>` prefix go to that repo:
!!! user "You" !!! user "You"
add a health check endpoint add a health check endpoint
+1 -1
View File
@@ -71,7 +71,7 @@ def _build_startup_message(
return ( return (
f"\N{OCTOPUS} **takopi is ready**\n\n" f"\N{OCTOPUS} **takopi is ready**\n\n"
f"default: `{runtime.default_engine}` \n" f"default: `{runtime.default_engine}` \n"
f"agents: `{engine_list}` \n" f"engines: `{engine_list}` \n"
f"projects: `{project_list}` \n" f"projects: `{project_list}` \n"
f"mode: `{session_mode}` \n" f"mode: `{session_mode}` \n"
f"topics: `{topics_label}` \n" f"topics: `{topics_label}` \n"
+9 -9
View File
@@ -25,17 +25,17 @@ async def _check_agent_permissions(
reply = make_reply(cfg, msg) reply = make_reply(cfg, msg)
sender_id = msg.sender_id sender_id = msg.sender_id
if sender_id is None: if sender_id is None:
await reply(text="cannot verify sender for agent defaults.") await reply(text="cannot verify sender for engine defaults.")
return False return False
if msg.is_private: if msg.is_private:
return True return True
member = await cfg.bot.get_chat_member(msg.chat_id, sender_id) member = await cfg.bot.get_chat_member(msg.chat_id, sender_id)
if member is None: if member is None:
await reply(text="failed to verify agent permissions.") await reply(text="failed to verify engine permissions.")
return False return False
if member.status in {"creator", "administrator"}: if member.status in {"creator", "administrator"}:
return True return True
await reply(text="changing default agents is restricted to group admins.") await reply(text="changing default engines is restricted to group admins.")
return False return False
@@ -86,7 +86,7 @@ async def _handle_agent_command(
"project_default": "project default", "project_default": "project default",
"global_default": "global default", "global_default": "global default",
} }
agent_line = f"agent: {selection.engine} ({source_labels[selection.source]})" agent_line = f"engine: {selection.engine} ({source_labels[selection.source]})"
topic_override = None topic_override = None
if tkey is not None and topic_store is not None: if tkey is not None and topic_store is not None:
topic_override = await topic_store.get_engine_override( topic_override = await topic_store.get_engine_override(
@@ -159,7 +159,7 @@ async def _handle_agent_command(
if engine not in cfg.runtime.engine_ids: if engine not in cfg.runtime.engine_ids:
available = ", ".join(cfg.runtime.engine_ids) available = ", ".join(cfg.runtime.engine_ids)
await reply( await reply(
text=f"unknown engine `{engine}`.\navailable agents: `{available}`", text=f"unknown engine `{engine}`.\navailable engines: `{available}`",
) )
return return
if tkey is not None: if tkey is not None:
@@ -167,13 +167,13 @@ async def _handle_agent_command(
await reply(text="topic defaults are unavailable.") await reply(text="topic defaults are unavailable.")
return return
await topic_store.set_default_engine(tkey[0], tkey[1], engine) await topic_store.set_default_engine(tkey[0], tkey[1], engine)
await reply(text=f"topic default agent set to `{engine}`") await reply(text=f"topic default engine set to `{engine}`")
return return
if chat_prefs is None: if chat_prefs is None:
await reply(text="chat defaults are unavailable (no config path).") await reply(text="chat defaults are unavailable (no config path).")
return return
await chat_prefs.set_default_engine(msg.chat_id, engine) await chat_prefs.set_default_engine(msg.chat_id, engine)
await reply(text=f"chat default agent set to `{engine}`") await reply(text=f"chat default engine set to `{engine}`")
return return
if action == "clear": if action == "clear":
@@ -184,13 +184,13 @@ async def _handle_agent_command(
await reply(text="topic defaults are unavailable.") await reply(text="topic defaults are unavailable.")
return return
await topic_store.clear_default_engine(tkey[0], tkey[1]) await topic_store.clear_default_engine(tkey[0], tkey[1])
await reply(text="topic default agent cleared.") await reply(text="topic default engine cleared.")
return return
if chat_prefs is None: if chat_prefs is None:
await reply(text="chat defaults are unavailable (no config path).") await reply(text="chat defaults are unavailable (no config path).")
return return
await chat_prefs.clear_default_engine(msg.chat_id) await chat_prefs.clear_default_engine(msg.chat_id)
await reply(text="chat default agent cleared.") await reply(text="chat default engine cleared.")
return return
await reply(text=AGENT_USAGE) await reply(text=AGENT_USAGE)
+2 -2
View File
@@ -29,7 +29,7 @@ def build_bot_commands(
cmd = engine_id.lower() cmd = engine_id.lower()
if cmd in seen: if cmd in seen:
continue continue
commands.append({"command": cmd, "description": f"use agent: {cmd}"}) commands.append({"command": cmd, "description": f"use engine: {cmd}"})
seen.add(cmd) seen.add(cmd)
for alias in runtime.project_aliases(): for alias in runtime.project_aliases():
cmd = alias.lower() cmd = alias.lower()
@@ -73,7 +73,7 @@ def build_bot_commands(
for cmd, description in [ for cmd, description in [
("new", "start a new thread"), ("new", "start a new thread"),
("ctx", "show or update context"), ("ctx", "show or update context"),
("agent", "set default agent"), ("agent", "set default engine"),
("model", "set model override"), ("model", "set model override"),
("reasoning", "set reasoning override"), ("reasoning", "set reasoning override"),
("trigger", "set trigger mode"), ("trigger", "set trigger mode"),
+2 -2
View File
@@ -122,7 +122,7 @@ async def _handle_model_command(
if engine not in engine_ids: if engine not in engine_ids:
available = ", ".join(cfg.runtime.engine_ids) available = ", ".join(cfg.runtime.engine_ids)
await reply( await reply(
text=f"unknown engine `{engine}`.\navailable agents: `{available}`" text=f"unknown engine `{engine}`.\navailable engines: `{available}`"
) )
return return
scope = await apply_engine_override( scope = await apply_engine_override(
@@ -187,7 +187,7 @@ async def _handle_model_command(
if engine not in engine_ids: if engine not in engine_ids:
available = ", ".join(cfg.runtime.engine_ids) available = ", ".join(cfg.runtime.engine_ids)
await reply( await reply(
text=f"unknown engine `{engine}`.\navailable agents: `{available}`" text=f"unknown engine `{engine}`.\navailable engines: `{available}`"
) )
return return
scope = await apply_engine_override( scope = await apply_engine_override(
+2 -2
View File
@@ -130,7 +130,7 @@ async def _handle_reasoning_command(
if engine not in engine_ids: if engine not in engine_ids:
available = ", ".join(cfg.runtime.engine_ids) available = ", ".join(cfg.runtime.engine_ids)
await reply( await reply(
text=f"unknown engine `{engine}`.\navailable agents: `{available}`" text=f"unknown engine `{engine}`.\navailable engines: `{available}`"
) )
return return
normalized_level = level.strip().lower() normalized_level = level.strip().lower()
@@ -206,7 +206,7 @@ async def _handle_reasoning_command(
if engine not in engine_ids: if engine not in engine_ids:
available = ", ".join(cfg.runtime.engine_ids) available = ", ".join(cfg.runtime.engine_ids)
await reply( await reply(
text=f"unknown engine `{engine}`.\navailable agents: `{available}`" text=f"unknown engine `{engine}`.\navailable engines: `{available}`"
) )
return return
scope = await apply_engine_override( scope = await apply_engine_override(
+4 -4
View File
@@ -877,7 +877,7 @@ async def step_capture_chat(ui: UI, svc: Services, state: OnboardingState) -> No
async def step_default_engine(ui: UI, svc: Services, state: OnboardingState) -> None: async def step_default_engine(ui: UI, svc: Services, state: OnboardingState) -> None:
ui.print("takopi runs these agents on your computer. switch anytime with /agent.") ui.print("takopi runs these engines on your computer. switch anytime with /agent.")
rows = svc.list_engines() rows = svc.list_engines()
render_engine_table(ui, rows) render_engine_table(ui, rows)
installed_ids = [engine_id for engine_id, installed, _ in rows if installed] installed_ids = [engine_id for engine_id, installed, _ in rows if installed]
@@ -885,13 +885,13 @@ async def step_default_engine(ui: UI, svc: Services, state: OnboardingState) ->
if installed_ids: if installed_ids:
ui.print("") ui.print("")
default_engine = await ui.select( default_engine = await ui.select(
"choose default agent:", "choose default engine:",
choices=[(engine_id, engine_id) for engine_id in installed_ids], choices=[(engine_id, engine_id) for engine_id in installed_ids],
) )
state.default_engine = require_value(default_engine) state.default_engine = require_value(default_engine)
return return
ui.print("no agents found. install one and rerun --onboard.") ui.print("no engines found. install one and rerun --onboard.")
ui.print("") ui.print("")
save_anyway = await ui.confirm("save config anyway?", default=False) save_anyway = await ui.confirm("save config anyway?", default=False)
if not save_anyway: if not save_anyway:
@@ -945,7 +945,7 @@ STEPS: list[OnboardingStep] = [
OnboardingStep("bot token", 1, step_token_and_bot), OnboardingStep("bot token", 1, step_token_and_bot),
OnboardingStep("pick your workflow", 2, step_persona), OnboardingStep("pick your workflow", 2, step_persona),
OnboardingStep("connect chat", 3, step_capture_chat), OnboardingStep("connect chat", 3, step_capture_chat),
OnboardingStep("default agent", 4, step_default_engine), OnboardingStep("default engine", 4, step_default_engine),
OnboardingStep("save config", 5, step_save_config), OnboardingStep("save config", 5, step_save_config),
] ]
@@ -62,7 +62,7 @@ async def test_agent_show_private_defaults() -> None:
) )
text = _last_text(transport) text = _last_text(transport)
assert "agent: codex" in text assert "engine: codex" in text
assert "available: codex" in text assert "available: codex" in text
@@ -83,7 +83,7 @@ async def test_agent_set_clear_group_admin(tmp_path: Path) -> None:
) )
assert await prefs.get_default_engine(msg.chat_id) == "codex" assert await prefs.get_default_engine(msg.chat_id) == "codex"
assert "chat default agent set" in _last_text(transport) assert "chat default engine set" in _last_text(transport)
await _handle_agent_command( await _handle_agent_command(
cfg, cfg,
@@ -95,7 +95,7 @@ async def test_agent_set_clear_group_admin(tmp_path: Path) -> None:
) )
assert await prefs.get_default_engine(msg.chat_id) is None assert await prefs.get_default_engine(msg.chat_id) is None
assert "chat default agent cleared" in _last_text(transport) assert "chat default engine cleared" in _last_text(transport)
@pytest.mark.anyio @pytest.mark.anyio
@@ -135,7 +135,7 @@ async def test_agent_set_invalid_engine(tmp_path: Path) -> None:
text = _last_text(transport) text = _last_text(transport)
assert "unknown engine" in text assert "unknown engine" in text
assert "available agents" in text assert "available engines" in text
@pytest.mark.anyio @pytest.mark.anyio
+2 -2
View File
@@ -50,7 +50,7 @@ def test_build_startup_message_includes_missing_engines(tmp_path: Path) -> None:
) )
assert "takopi is ready" in message assert "takopi is ready" in message
assert "agents: `codex (not installed: pi)`" in message assert "engines: `codex (not installed: pi)`" in message
assert "projects: `none`" in message assert "projects: `none`" in message
@@ -92,7 +92,7 @@ def test_build_startup_message_surfaces_unavailable_engine_reasons(
topics=TelegramTopicsSettings(), topics=TelegramTopicsSettings(),
) )
assert "agents: `codex" in message assert "engines: `codex" in message
assert "misconfigured: pi" in message assert "misconfigured: pi" in message
assert "failed to load: claude" in message assert "failed to load: claude" in message
+1 -1
View File
@@ -136,7 +136,7 @@ def test_build_bot_commands_includes_cancel_and_engine() -> None:
assert {"command": "file", "description": "upload or fetch files"} in commands assert {"command": "file", "description": "upload or fetch files"} in commands
assert {"command": "new", "description": "start a new thread"} in commands assert {"command": "new", "description": "start a new thread"} in commands
assert {"command": "ctx", "description": "show or update context"} in commands assert {"command": "ctx", "description": "show or update context"} in commands
assert {"command": "agent", "description": "set default agent"} in commands assert {"command": "agent", "description": "set default engine"} in commands
assert any(cmd["command"] == "codex" for cmd in commands) assert any(cmd["command"] == "codex" for cmd in commands)