mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-19 08:02:30 +00:00
fix(skills): improve create-instance for cross-platform and add channel reference
- Make SKILL.md platform-agnostic (remove Windows-only path rules) - Add 14-channel quick-reference table with required fields - Create references/channels.md with detailed per-channel config - Inherit model from parent config when not explicitly specified - Consolidate duplicate file reads in _patch_config - Add email channel consent_granted field documentation - Fix auto_reply_enabled default value (true, not false) - Add troubleshooting section to SKILL.md
This commit is contained in:
parent
a7aeb1d2ea
commit
b815aa8c0e
@ -1,50 +1,64 @@
|
||||
---
|
||||
name: create-instance
|
||||
description: "Create a new nanobot instance with separate config and workspace. Use when the user wants to set up a new bot for a different channel, persona, or purpose."
|
||||
description: "Create a new nanobot instance with separate config and workspace. Use when the user wants to set up a new bot, create a new instance for a different channel, persona, or purpose. Triggers on: create instance, new bot, set up bot, add bot, create telegram/discord/feishu/slack/wechat/wecom/dingtalk/qq/email/matrix/msteams/whatsapp bot, multi-instance setup."
|
||||
---
|
||||
|
||||
# Create Instance
|
||||
|
||||
Set up a new nanobot instance with its own config and workspace.
|
||||
|
||||
## When to Use
|
||||
|
||||
When the user wants to create a new bot instance — typically for a different channel (Telegram, Discord, WeChat, etc.) or with different settings.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Collect information from the user** (ask one at a time if not already provided):
|
||||
- **Instance name** (required): a short identifier like `telegram-bot`, `discord-bot`
|
||||
- **Channel type** (required): e.g. `telegram`, `discord`, `weixin`, `feishu`, `slack`
|
||||
- **Model** (optional): LLM model to use. Defaults to the same model as the current instance.
|
||||
1. **Collect information** (ask one at a time if not already provided):
|
||||
- **Instance name** (required): short identifier, e.g. `telegram-bot`, `work-slack`
|
||||
- **Channel type** (required): see table below
|
||||
- **Model** (optional): LLM model, defaults to current instance
|
||||
|
||||
2. **Do NOT collect sensitive information** in the chat (API keys, bot tokens, secrets). API keys are automatically copied from the current instance. Channel-specific tokens (e.g. `telegram.token`) still need to be filled in manually.
|
||||
2. **Do NOT collect secrets** in the chat (API keys, bot tokens). API keys are automatically inherited from the current instance via `--inherit-config`. Channel-specific tokens must be filled in manually after creation.
|
||||
|
||||
3. **Run the creation script** using the exec tool — always pass `--inherit-config` with the current instance's config path so API keys are copied:
|
||||
3. **Run the creation script**:
|
||||
|
||||
```bash
|
||||
python D:/path/to/nanobot/skills/create-instance/scripts/create_instance.py --name <name> --channel <channel> --inherit-config ~/.nanobot/config.json [--model <model>] [--config-dir <path>]
|
||||
python <skill-dir>/scripts/create_instance.py --name <name> --channel <channel> --inherit-config <current-config>
|
||||
```
|
||||
|
||||
**Path rules (critical on Windows):**
|
||||
- Use **forward-slash absolute paths** to the script, e.g. `D:/path/to/create_instance.py`
|
||||
- Do **NOT** wrap paths in quotes — the exec tool will mangle them
|
||||
- Do **NOT** use `cd` — the exec tool ignores it; working directory stays as workspace
|
||||
- Do **NOT** use backslash paths like `D:\path` — they will fail
|
||||
- `<skill-dir>` — the directory containing this SKILL.md
|
||||
- `<current-config>` — current instance's config path, typically `~/.nanobot/config.json`
|
||||
- Optional: `--model <model>`, `--config-dir <path>`
|
||||
|
||||
Use `~/.nanobot/config.json` as the `--inherit-config` path unless the current instance uses a custom config location.
|
||||
**Exec tool constraints:**
|
||||
- Use forward-slash paths (works on all platforms)
|
||||
- Do not wrap paths in quotes
|
||||
- Do not use `cd`; pass the full script path directly
|
||||
|
||||
4. **Report results to the user**:
|
||||
- Where the config and workspace were created
|
||||
- Which fields they need to fill in (the script will list them)
|
||||
- The command to start the instance: `nanobot gateway --config <config-path>`
|
||||
4. **Report results** to the user:
|
||||
- Config and workspace paths (script outputs them)
|
||||
- Required fields to fill in (script lists them)
|
||||
- Start command: `nanobot gateway --config <config-path>`
|
||||
|
||||
## Examples
|
||||
## Available Channels
|
||||
|
||||
User: "help me create a Telegram bot" (or similar request)
|
||||
| Channel | Key | Required Fields |
|
||||
|---------|-----|-----------------|
|
||||
| Telegram | `telegram` | token |
|
||||
| Discord | `discord` | token |
|
||||
| Feishu / Lark | `feishu` | app_id, app_secret |
|
||||
| DingTalk | `dingtalk` | client_id, client_secret |
|
||||
| Slack | `slack` | bot_token, app_token |
|
||||
| WeCom | `wecom` | bot_id, secret |
|
||||
| WeChat OA | `weixin` | token |
|
||||
| WhatsApp | `whatsapp` | bridge_token |
|
||||
| QQ | `qq` | app_id, secret |
|
||||
| Email | `email` | imap_host, imap_username, imap_password, smtp_host, smtp_username, smtp_password, from_address |
|
||||
| Matrix | `matrix` | user_id, password or access_token |
|
||||
| MS Teams | `msteams` | app_id, app_password, tenant_id |
|
||||
| MoChat | `mochat` | claw_token |
|
||||
| WebSocket | `websocket` | token |
|
||||
|
||||
→ Ask for an instance name if not obvious from context
|
||||
→ Ask which model to use (optional, can skip if user doesn't care)
|
||||
→ Run: `python D:/path/to/nanobot/skills/create-instance/scripts/create_instance.py --name telegram-bot --channel telegram --inherit-config ~/.nanobot/config.json`
|
||||
(Replace `D:/path/to/nanobot` with the actual nanobot source directory)
|
||||
→ Tell user: config created at `~/.nanobot-telegram/config.json`, fill in `channels.telegram.token`, then start with `nanobot gateway --config ~/.nanobot-telegram/config.json`
|
||||
For detailed channel configuration including optional fields, see `references/channels.md`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Unknown channel"**: Channel name must match the Key column exactly. Run the script without arguments to see usage.
|
||||
- **"Config already exists"**: Use a different `--name` or `--config-dir` to create in a new location.
|
||||
- **Port conflicts**: The script auto-assigns free ports for gateway and API if defaults are in use.
|
||||
|
||||
194
nanobot/skills/create-instance/references/channels.md
Normal file
194
nanobot/skills/create-instance/references/channels.md
Normal file
@ -0,0 +1,194 @@
|
||||
# Channel Configuration Reference
|
||||
|
||||
Detailed configuration for each supported channel.
|
||||
|
||||
## Field Types
|
||||
|
||||
- **Required**: defaults to empty string `""`, must be filled in before the instance can start
|
||||
- **Optional**: has a sensible default, can be customized
|
||||
|
||||
---
|
||||
|
||||
## telegram
|
||||
|
||||
**Required:**
|
||||
- `token` — Bot token from @BotFather
|
||||
|
||||
**Notable optional:**
|
||||
- `proxy` — HTTP proxy URL
|
||||
- `group_policy` — `"open"` (all messages) or `"mention"` (default, only when @mentioned)
|
||||
- `streaming` — Enable streaming responses (default: true)
|
||||
- `reply_to_message` — Reply to the triggering message (default: false)
|
||||
- `react_emoji` — Emoji for "thinking" reaction (default: `"eyes"`)
|
||||
- `inline_keyboards` — Enable inline keyboard buttons (default: false)
|
||||
|
||||
## discord
|
||||
|
||||
**Required:**
|
||||
- `token` — Bot token from Discord Developer Portal
|
||||
|
||||
**Notable optional:**
|
||||
- `allow_channels` — Restrict to specific channel IDs
|
||||
- `group_policy` — `"mention"` (default) or `"open"`
|
||||
- `streaming` — Enable streaming (default: true)
|
||||
- `proxy` — HTTP proxy URL
|
||||
- `intents` — Discord gateway intents (default: 37377)
|
||||
- `read_receipt_emoji` — Emoji for read receipt
|
||||
- `working_emoji` — Emoji for "working" indicator
|
||||
|
||||
## feishu
|
||||
|
||||
**Required:**
|
||||
- `app_id` — Feishu app ID
|
||||
- `app_secret` — Feishu app secret
|
||||
|
||||
**Notable optional:**
|
||||
- `encrypt_key` — Event encryption key
|
||||
- `verification_token` — Event verification token
|
||||
- `domain` — `"feishu"` (default) or `"lark"`
|
||||
- `group_policy` — `"mention"` (default) or `"open"`
|
||||
- `streaming` — Enable streaming (default: true)
|
||||
|
||||
## dingtalk
|
||||
|
||||
**Required:**
|
||||
- `client_id` — DingTalk app client ID
|
||||
- `client_secret` — DingTalk app client secret
|
||||
|
||||
**Notable optional:**
|
||||
- `allow_from` — Allowed user IDs
|
||||
|
||||
## slack
|
||||
|
||||
**Required:**
|
||||
- `bot_token` — Bot OAuth token (`xoxb-...`)
|
||||
- `app_token` — App-level token (`xapp-...`)
|
||||
|
||||
**Notable optional:**
|
||||
- `mode` — `"socket"` (default, Socket Mode) or `"webhook"`
|
||||
- `reply_in_thread` — Reply in thread (default: true)
|
||||
- `react_emoji` — "thinking" emoji (default: `"eyes"`)
|
||||
- `done_emoji` — "done" emoji (default: `"white_check_mark"`)
|
||||
- `group_policy` — `"mention"` (default) or `"open"`
|
||||
- `dm.enabled` — Enable DM support
|
||||
- `dm.policy` — DM policy
|
||||
- `dm.allow_from` — Allowed DM users
|
||||
|
||||
## wecom
|
||||
|
||||
**Required:**
|
||||
- `bot_id` — WeCom bot ID
|
||||
- `secret` — WeCom bot secret
|
||||
|
||||
**Notable optional:**
|
||||
- `allow_from` — Allowed users
|
||||
- `welcome_message` — Welcome message for new chats
|
||||
|
||||
## weixin
|
||||
|
||||
**Required:**
|
||||
- `token` — WeChat Official Account token
|
||||
|
||||
**Notable optional:**
|
||||
- `base_url` — API base URL
|
||||
- `cdn_base_url` — CDN base URL
|
||||
- `state_dir` — State persistence directory
|
||||
- `poll_timeout` — Long polling timeout
|
||||
|
||||
## whatsapp
|
||||
|
||||
**Required:**
|
||||
- `bridge_token` — WhatsApp bridge token (auto-generated if absent)
|
||||
|
||||
**Notable optional:**
|
||||
- `bridge_url` — Bridge WebSocket URL (default: `"ws://localhost:3001"`)
|
||||
- `group_policy` — `"open"` (default) or `"mention"`
|
||||
|
||||
## qq
|
||||
|
||||
**Required:**
|
||||
- `app_id` — QQ bot app ID
|
||||
- `secret` — QQ bot secret
|
||||
|
||||
**Notable optional:**
|
||||
- `msg_format` — `"plain"` or `"markdown"`
|
||||
- `ack_message` — Acknowledgment message text
|
||||
- `media_dir` — Media file directory
|
||||
|
||||
## email
|
||||
|
||||
**Required:**
|
||||
- `imap_host` — IMAP server hostname
|
||||
- `imap_username` — IMAP login username
|
||||
- `imap_password` — IMAP login password
|
||||
- `smtp_host` — SMTP server hostname
|
||||
- `smtp_username` — SMTP login username
|
||||
- `smtp_password` — SMTP login password
|
||||
- `from_address` — Sender email address
|
||||
|
||||
**Notable optional:**
|
||||
- `imap_port` — IMAP port (default: 993)
|
||||
- `smtp_port` — SMTP port (default: 587)
|
||||
- `imap_use_ssl` — Use SSL for IMAP (default: true)
|
||||
- `smtp_use_tls` — Use TLS for SMTP (default: true)
|
||||
- `poll_interval_seconds` — Polling interval (default: 30)
|
||||
- `mark_seen` — Mark emails as read (default: true)
|
||||
- `max_body_chars` — Max email body length (default: 12000)
|
||||
- `subject_prefix` — Reply subject prefix (default: `"Re: "`)
|
||||
- `verify_dkim` — Verify DKIM signatures (default: true)
|
||||
- `verify_spf` — Verify SPF records (default: true)
|
||||
- `allowed_attachment_types` — Allowed file extensions
|
||||
- `max_attachment_size` — Max attachment size in bytes
|
||||
- `consent_granted` — Must be set to `true` for the channel to start (default: false)
|
||||
- `auto_reply_enabled` — Enable auto-reply (default: true)
|
||||
|
||||
## matrix
|
||||
|
||||
**Required:**
|
||||
- `user_id` — Matrix user ID (e.g. `@bot:matrix.org`)
|
||||
- `password` or `access_token` — Login password OR access token
|
||||
|
||||
**Notable optional:**
|
||||
- `homeserver` — Homeserver URL (default: `"https://matrix.org"`)
|
||||
- `device_id` — Device ID
|
||||
- `e2eeEnabled` — Enable end-to-end encryption (default: true)
|
||||
- `group_policy` — `"open"`, `"mention"`, or `"allowlist"`
|
||||
- `streaming` — Enable streaming (default: false)
|
||||
- `max_media_bytes` — Max media file size (default: 20MB)
|
||||
|
||||
## msteams
|
||||
|
||||
**Required:**
|
||||
- `app_id` — Azure AD app ID
|
||||
- `app_password` — Azure AD app password/secret
|
||||
- `tenant_id` — Azure AD tenant ID
|
||||
|
||||
**Notable optional:**
|
||||
- `host` — Listen host (default: `"0.0.0.0"`)
|
||||
- `port` — Listen port (default: 3978)
|
||||
- `reply_in_thread` — Reply in thread (default: true)
|
||||
- `validate_inbound_auth` — Validate incoming auth (default: true)
|
||||
|
||||
## mochat
|
||||
|
||||
**Required:**
|
||||
- `claw_token` — MoChat Claw token
|
||||
|
||||
**Notable optional:**
|
||||
- `base_url` — API base URL
|
||||
- `socket_url` — WebSocket URL
|
||||
- `refresh_interval_ms` — Refresh interval in ms
|
||||
- `watch_timeout_ms` — Watch timeout in ms
|
||||
|
||||
## websocket
|
||||
|
||||
Built-in WebSocket channel for programmatic access.
|
||||
|
||||
**Required:**
|
||||
- `token` — Authentication token (enabled by default; set `websocket_requires_token: false` to disable)
|
||||
|
||||
**Notable optional:**
|
||||
- `host` — Listen host (default: `"127.0.0.1"`)
|
||||
- `port` — Listen port (default: 8765)
|
||||
- `allow_from` — Allowed origins (default: `["*"]`)
|
||||
- `streaming` — Enable streaming (default: true)
|
||||
@ -73,18 +73,27 @@ def _patch_config(
|
||||
"""Patch the generated config: enable channel, set workspace, optionally set model."""
|
||||
data = json.loads(config_path.read_text(encoding="utf-8"))
|
||||
|
||||
# Inherit providers (API keys, api_base, etc.) from current instance
|
||||
# Inherit providers and model from current instance
|
||||
if inherit_config_path and inherit_config_path.exists():
|
||||
try:
|
||||
src = json.loads(inherit_config_path.read_text(encoding="utf-8"))
|
||||
|
||||
# Inherit providers (API keys, api_base, etc.)
|
||||
src_providers = src.get("providers", {})
|
||||
if src_providers:
|
||||
data.setdefault("providers", {})
|
||||
for key, val in src_providers.items():
|
||||
if isinstance(val, dict) and val.get("apiKey"):
|
||||
data["providers"][key] = val
|
||||
|
||||
# Inherit model if not explicitly overridden
|
||||
if not model:
|
||||
parent_model = src.get("agents", {}).get("defaults", {}).get("model")
|
||||
if parent_model:
|
||||
model = parent_model
|
||||
|
||||
except Exception as exc:
|
||||
print(f"[WARN] Could not inherit providers from {inherit_config_path}: {exc}", file=sys.stderr)
|
||||
print(f"[WARN] Could not inherit from {inherit_config_path}: {exc}", file=sys.stderr)
|
||||
|
||||
# Set workspace and model
|
||||
data.setdefault("agents", {}).setdefault("defaults", {})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user