@qwen-code/qwen-code 0.13.2 → 0.14.0-nightly.20260402.a5f17ee39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/loop/SKILL.md +61 -0
- package/bundled/qc-helper/docs/extension/extension-releasing.md +85 -2
- package/bundled/qc-helper/docs/extension/introduction.md +41 -6
- package/bundled/qc-helper/docs/features/_meta.ts +2 -0
- package/bundled/qc-helper/docs/features/channels/_meta.ts +7 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +134 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +336 -0
- package/bundled/qc-helper/docs/features/channels/plugins.md +87 -0
- package/bundled/qc-helper/docs/features/channels/telegram.md +120 -0
- package/bundled/qc-helper/docs/features/channels/weixin.md +106 -0
- package/bundled/qc-helper/docs/features/hooks.md +12 -7
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +139 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +12 -8
- package/bundled/review/SKILL.md +144 -6
- package/cli.js +159510 -128448
- package/locales/de.js +13 -0
- package/locales/en.js +13 -0
- package/locales/ja.js +13 -0
- package/locales/pt.js +13 -0
- package/locales/ru.js +13 -0
- package/locales/zh.js +13 -0
- package/package.json +8 -8
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loop
|
|
3
|
+
description: Create a recurring loop that runs a prompt on a schedule. Usage - /loop 5m check the build, /loop check the PR every 30m, /loop run tests (defaults to 10m). /loop list to show jobs, /loop clear to cancel all.
|
|
4
|
+
allowedTools:
|
|
5
|
+
- cron_create
|
|
6
|
+
- cron_list
|
|
7
|
+
- cron_delete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /loop — schedule a recurring prompt
|
|
11
|
+
|
|
12
|
+
## Subcommands
|
|
13
|
+
|
|
14
|
+
If the input (after stripping the `/loop` prefix) is exactly one of these keywords, run the subcommand instead of scheduling:
|
|
15
|
+
|
|
16
|
+
- **`list`** — call CronList and display the results. Done.
|
|
17
|
+
- **`clear`** — call CronList, then call CronDelete for every job returned. Confirm how many were cancelled. Done.
|
|
18
|
+
|
|
19
|
+
Otherwise, parse the input below into `[interval] <prompt…>` and schedule it with CronCreate.
|
|
20
|
+
|
|
21
|
+
## Parsing (in priority order)
|
|
22
|
+
|
|
23
|
+
1. **Leading token**: if the first whitespace-delimited token matches `^\d+[smhd]$` (e.g. `5m`, `2h`), that's the interval; the rest is the prompt.
|
|
24
|
+
2. **Trailing "every" clause**: otherwise, if the input ends with `every <N><unit>` or `every <N> <unit-word>` (e.g. `every 20m`, `every 5 minutes`, `every 2 hours`), extract that as the interval and strip it from the prompt. Only match when what follows "every" is a time expression — `check every PR` has no interval.
|
|
25
|
+
3. **Default**: otherwise, interval is `10m` and the entire input is the prompt.
|
|
26
|
+
|
|
27
|
+
If the resulting prompt is empty, show usage `/loop [interval] <prompt>` and stop — do not call CronCreate.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
|
|
31
|
+
- `5m /babysit-prs` → interval `5m`, prompt `/babysit-prs` (rule 1)
|
|
32
|
+
- `check the deploy every 20m` → interval `20m`, prompt `check the deploy` (rule 2)
|
|
33
|
+
- `run tests every 5 minutes` → interval `5m`, prompt `run tests` (rule 2)
|
|
34
|
+
- `check the deploy` → interval `10m`, prompt `check the deploy` (rule 3)
|
|
35
|
+
- `check every PR` → interval `10m`, prompt `check every PR` (rule 3 — "every" not followed by time)
|
|
36
|
+
- `5m` → empty prompt → show usage
|
|
37
|
+
|
|
38
|
+
## Interval → cron
|
|
39
|
+
|
|
40
|
+
Supported suffixes: `s` (seconds, rounded up to nearest minute, min 1), `m` (minutes), `h` (hours), `d` (days). Convert:
|
|
41
|
+
|
|
42
|
+
| Interval pattern | Cron expression | Notes |
|
|
43
|
+
| ----------------- | ---------------------- | ----------------------------------------- |
|
|
44
|
+
| `Nm` where N ≤ 59 | `*/N * * * *` | every N minutes |
|
|
45
|
+
| `Nm` where N ≥ 60 | `0 */H * * *` | round to hours (H = N/60, must divide 24) |
|
|
46
|
+
| `Nh` where N ≤ 23 | `0 */N * * *` | every N hours |
|
|
47
|
+
| `Nd` | `0 0 */N * *` | every N days at midnight local |
|
|
48
|
+
| `Ns` | treat as `ceil(N/60)m` | cron minimum granularity is 1 minute |
|
|
49
|
+
|
|
50
|
+
**If the interval doesn't cleanly divide its unit** (e.g. `7m` → `*/7 * * * *` gives uneven gaps at :56→:00; `90m` → 1.5h which cron can't express), pick the nearest clean interval and tell the user what you rounded to before scheduling.
|
|
51
|
+
|
|
52
|
+
## Action
|
|
53
|
+
|
|
54
|
+
1. Call CronCreate with:
|
|
55
|
+
- `cron`: the expression from the table above
|
|
56
|
+
- `prompt`: the parsed prompt from above, verbatim (slash commands are passed through unchanged)
|
|
57
|
+
- `recurring`: `true`
|
|
58
|
+
2. Briefly confirm: what's scheduled, the cron expression, the human-readable cadence, that recurring tasks auto-expire after 3 days, and that they can cancel sooner with CronDelete (include the job ID).
|
|
59
|
+
3. **Then immediately execute the parsed prompt now** — don't wait for the first cron fire. If it's a slash command, invoke it via the Skill tool; otherwise act on it directly.
|
|
60
|
+
|
|
61
|
+
## Input
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Extension Releasing
|
|
2
2
|
|
|
3
|
-
There are
|
|
3
|
+
There are three primary ways of releasing extensions to users:
|
|
4
4
|
|
|
5
5
|
- [Git repository](#releasing-through-a-git-repository)
|
|
6
6
|
- [Github Releases](#releasing-through-github-releases)
|
|
7
|
+
- [npm Registry](#releasing-through-npm-registry)
|
|
7
8
|
|
|
8
|
-
Git repository releases tend to be the simplest and most flexible approach, while GitHub releases can be more efficient on initial install as they are shipped as single archives instead of requiring a git clone which downloads each file individually. Github releases may also contain platform specific archives if you need to ship platform specific binary files.
|
|
9
|
+
Git repository releases tend to be the simplest and most flexible approach, while GitHub releases can be more efficient on initial install as they are shipped as single archives instead of requiring a git clone which downloads each file individually. Github releases may also contain platform specific archives if you need to ship platform specific binary files. npm registry releases are ideal for teams that already use npm for package distribution, especially with private registries.
|
|
9
10
|
|
|
10
11
|
## Releasing through a git repository
|
|
11
12
|
|
|
@@ -119,3 +120,85 @@ jobs:
|
|
|
119
120
|
release/linux.arm64.my-tool.tar.gz
|
|
120
121
|
release/win32.arm64.my-tool.zip
|
|
121
122
|
```
|
|
123
|
+
|
|
124
|
+
## Releasing through npm registry
|
|
125
|
+
|
|
126
|
+
You can publish Qwen Code extensions as scoped npm packages (e.g. `@your-org/my-extension`). This is a good fit when:
|
|
127
|
+
|
|
128
|
+
- Your team already uses npm for package distribution
|
|
129
|
+
- You need private registry support with existing auth infrastructure
|
|
130
|
+
- You want version resolution and access control handled by npm
|
|
131
|
+
|
|
132
|
+
### Package requirements
|
|
133
|
+
|
|
134
|
+
Your npm package must include a `qwen-extension.json` file at the package root. This is the same config file used by all Qwen Code extensions — the npm tarball is simply another delivery mechanism.
|
|
135
|
+
|
|
136
|
+
A minimal package structure looks like:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
my-extension/
|
|
140
|
+
├── package.json
|
|
141
|
+
├── qwen-extension.json
|
|
142
|
+
├── QWEN.md # optional context file
|
|
143
|
+
├── commands/ # optional custom commands
|
|
144
|
+
├── skills/ # optional custom skills
|
|
145
|
+
└── agents/ # optional custom subagents
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Make sure `qwen-extension.json` is included in your published package (i.e. not excluded by `.npmignore` or the `files` field in `package.json`).
|
|
149
|
+
|
|
150
|
+
### Publishing
|
|
151
|
+
|
|
152
|
+
Use standard npm publishing tools:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Publish to the default registry
|
|
156
|
+
npm publish
|
|
157
|
+
|
|
158
|
+
# Publish to a private/custom registry
|
|
159
|
+
npm publish --registry https://your-registry.com
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Installation
|
|
163
|
+
|
|
164
|
+
Users install your extension using the scoped package name:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Install latest version
|
|
168
|
+
qwen extensions install @your-org/my-extension
|
|
169
|
+
|
|
170
|
+
# Install a specific version
|
|
171
|
+
qwen extensions install @your-org/my-extension@1.2.0
|
|
172
|
+
|
|
173
|
+
# Install from a custom registry
|
|
174
|
+
qwen extensions install @your-org/my-extension --registry https://your-registry.com
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Update behavior
|
|
178
|
+
|
|
179
|
+
- Extensions installed without a version pin (e.g. `@scope/pkg`) track the `latest` dist-tag.
|
|
180
|
+
- Extensions installed with a dist-tag (e.g. `@scope/pkg@beta`) track that specific tag.
|
|
181
|
+
- Extensions pinned to an exact version (e.g. `@scope/pkg@1.2.0`) are always considered up-to-date and will not prompt for updates.
|
|
182
|
+
|
|
183
|
+
### Authentication for private registries
|
|
184
|
+
|
|
185
|
+
Qwen Code reads npm auth credentials automatically:
|
|
186
|
+
|
|
187
|
+
1. **`NPM_TOKEN` environment variable** — highest priority
|
|
188
|
+
2. **`.npmrc` file** — supports both host-level and path-scoped `_authToken` entries (e.g. `//your-registry.com/:_authToken=TOKEN` or `//pkgs.dev.azure.com/org/_packaging/feed/npm/registry/:_authToken=TOKEN`)
|
|
189
|
+
|
|
190
|
+
`.npmrc` files are read from the current directory and the user's home directory.
|
|
191
|
+
|
|
192
|
+
### Managing release channels
|
|
193
|
+
|
|
194
|
+
You can use npm dist-tags to manage release channels:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Publish a beta release
|
|
198
|
+
npm publish --tag beta
|
|
199
|
+
|
|
200
|
+
# Users install beta channel
|
|
201
|
+
qwen extensions install @your-org/my-extension@beta
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
This works similarly to git branch-based release channels but uses npm's native dist-tag mechanism.
|
|
@@ -12,11 +12,11 @@ We offer a suite of extension management tools using both `qwen extensions` CLI
|
|
|
12
12
|
|
|
13
13
|
You can manage extensions at runtime within the interactive CLI using `/extensions` slash commands. These commands support hot-reloading, meaning changes take effect immediately without restarting the application.
|
|
14
14
|
|
|
15
|
-
| Command | Description
|
|
16
|
-
| ------------------------------------- |
|
|
17
|
-
| `/extensions` or `/extensions manage` | Manage all installed extensions
|
|
18
|
-
| `/extensions install <source>` | Install an extension from a git URL, local path, or marketplace
|
|
19
|
-
| `/extensions explore [source]` | Open extensions source page(Gemini or ClaudeCode) in your browser
|
|
15
|
+
| Command | Description |
|
|
16
|
+
| ------------------------------------- | ---------------------------------------------------------------------------- |
|
|
17
|
+
| `/extensions` or `/extensions manage` | Manage all installed extensions |
|
|
18
|
+
| `/extensions install <source>` | Install an extension from a git URL, local path, npm package, or marketplace |
|
|
19
|
+
| `/extensions explore [source]` | Open extensions source page(Gemini or ClaudeCode) in your browser |
|
|
20
20
|
|
|
21
21
|
### CLI Extension Management
|
|
22
22
|
|
|
@@ -89,6 +89,34 @@ Gemini extensions are automatically converted to Qwen Code format during install
|
|
|
89
89
|
- TOML command files are automatically migrated to Markdown format
|
|
90
90
|
- MCP servers, context files, and settings are preserved
|
|
91
91
|
|
|
92
|
+
#### From npm Registry
|
|
93
|
+
|
|
94
|
+
Qwen Code supports installing extensions from npm registries using scoped package names. This is ideal for teams with private registries that already have auth, versioning, and publishing infrastructure in place.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Install the latest version
|
|
98
|
+
qwen extensions install @scope/my-extension
|
|
99
|
+
|
|
100
|
+
# Install a specific version
|
|
101
|
+
qwen extensions install @scope/my-extension@1.2.0
|
|
102
|
+
|
|
103
|
+
# Install from a custom registry
|
|
104
|
+
qwen extensions install @scope/my-extension --registry https://your-registry.com
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Only scoped packages (`@scope/package-name`) are supported to avoid ambiguity with the `owner/repo` GitHub shorthand format.
|
|
108
|
+
|
|
109
|
+
**Registry resolution** follows this priority:
|
|
110
|
+
|
|
111
|
+
1. `--registry` CLI flag (explicit override)
|
|
112
|
+
2. Scoped registry from `.npmrc` (e.g. `@scope:registry=https://...`)
|
|
113
|
+
3. Default registry from `.npmrc`
|
|
114
|
+
4. Fallback: `https://registry.npmjs.org/`
|
|
115
|
+
|
|
116
|
+
**Authentication** is handled automatically via the `NPM_TOKEN` environment variable or registry-specific `_authToken` entries in your `.npmrc` file.
|
|
117
|
+
|
|
118
|
+
> **Note:** npm extensions must include a `qwen-extension.json` file at the package root, following the same format as any other Qwen Code extension. See [Extension Releasing](./extension-releasing.md#releasing-through-npm-registry) for packaging details.
|
|
119
|
+
|
|
92
120
|
#### From Git Repository
|
|
93
121
|
|
|
94
122
|
```bash
|
|
@@ -127,7 +155,7 @@ This is useful if you have an extension disabled at the top-level and only enabl
|
|
|
127
155
|
|
|
128
156
|
### Updating an extension
|
|
129
157
|
|
|
130
|
-
For extensions installed from a local path
|
|
158
|
+
For extensions installed from a local path, a git repository, or an npm registry, you can explicitly update to the latest version with `qwen extensions update extension-name`. For npm extensions installed without a version pin (e.g. `@scope/pkg`), updates check the `latest` dist-tag. For those installed with a specific dist-tag (e.g. `@scope/pkg@beta`), updates track that tag. Extensions pinned to an exact version (e.g. `@scope/pkg@1.2.0`) are always considered up-to-date.
|
|
131
159
|
|
|
132
160
|
You can update all extensions with:
|
|
133
161
|
|
|
@@ -156,6 +184,12 @@ The `qwen-extension.json` file contains the configuration for the extension. The
|
|
|
156
184
|
"command": "node my-server.js"
|
|
157
185
|
}
|
|
158
186
|
},
|
|
187
|
+
"channels": {
|
|
188
|
+
"my-platform": {
|
|
189
|
+
"entry": "dist/index.js",
|
|
190
|
+
"displayName": "My Platform Channel"
|
|
191
|
+
}
|
|
192
|
+
},
|
|
159
193
|
"contextFileName": "QWEN.md",
|
|
160
194
|
"commands": "commands",
|
|
161
195
|
"skills": "skills",
|
|
@@ -175,6 +209,7 @@ The `qwen-extension.json` file contains the configuration for the extension. The
|
|
|
175
209
|
- `version`: The version of the extension.
|
|
176
210
|
- `mcpServers`: A map of MCP servers to configure. The key is the name of the server, and the value is the server configuration. These servers will be loaded on startup just like MCP servers configured in a [`settings.json` file](./cli/configuration.md). If both an extension and a `settings.json` file configure an MCP server with the same name, the server defined in the `settings.json` file takes precedence.
|
|
177
211
|
- Note that all MCP server configuration options are supported except for `trust`.
|
|
212
|
+
- `channels`: A map of custom channel adapters. The key is the channel type name, and the value has an `entry` (path to compiled JS entry point) and optional `displayName`. The entry point must export a `plugin` object conforming to the `ChannelPlugin` interface. See [Channel Plugins](../features/channels/plugins) for a full guide.
|
|
178
213
|
- `contextFileName`: The name of the file that contains the context for the extension. This will be used to load the context from the extension directory. If this property is not used but a `QWEN.md` file is present in your extension directory, then that file will be loaded.
|
|
179
214
|
- `commands`: The directory containing custom commands (default: `commands`). Commands are `.md` files that define prompts.
|
|
180
215
|
- `skills`: The directory containing custom skills (default: `skills`). Skills are discovered automatically and become available via the `/skills` command.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# DingTalk (Dingtalk)
|
|
2
|
+
|
|
3
|
+
This guide covers setting up a Qwen Code channel on DingTalk (钉钉).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- A DingTalk organization account
|
|
8
|
+
- A DingTalk bot application with AppKey and AppSecret (see below)
|
|
9
|
+
|
|
10
|
+
## Creating a Bot
|
|
11
|
+
|
|
12
|
+
1. Go to the [DingTalk Developer Portal](https://open-dev.dingtalk.com)
|
|
13
|
+
2. Create a new application (or use an existing one)
|
|
14
|
+
3. Under the application, enable the **Robot** capability
|
|
15
|
+
4. In Robot settings, enable **Stream Mode** (机器人协议 → Stream 模式)
|
|
16
|
+
5. Note the **AppKey** (Client ID) and **AppSecret** (Client Secret) from the application credentials page
|
|
17
|
+
|
|
18
|
+
### Stream Mode
|
|
19
|
+
|
|
20
|
+
DingTalk Stream mode uses an outbound WebSocket connection — no public URL or server is needed. The bot connects to DingTalk's servers, which push messages through the WebSocket. This is the simplest deployment model.
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
Add the channel to `~/.qwen/settings.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"channels": {
|
|
29
|
+
"my-dingtalk": {
|
|
30
|
+
"type": "dingtalk",
|
|
31
|
+
"clientId": "$DINGTALK_CLIENT_ID",
|
|
32
|
+
"clientSecret": "$DINGTALK_CLIENT_SECRET",
|
|
33
|
+
"senderPolicy": "open",
|
|
34
|
+
"sessionScope": "user",
|
|
35
|
+
"cwd": "/path/to/your/project",
|
|
36
|
+
"instructions": "You are a concise coding assistant responding via DingTalk.",
|
|
37
|
+
"groupPolicy": "open",
|
|
38
|
+
"groups": {
|
|
39
|
+
"*": { "requireMention": true }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Set the credentials as environment variables:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export DINGTALK_CLIENT_ID=<your-app-key>
|
|
50
|
+
export DINGTALK_CLIENT_SECRET=<your-app-secret>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or define them in the `env` section of `settings.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"env": {
|
|
58
|
+
"DINGTALK_CLIENT_ID": "your-app-key",
|
|
59
|
+
"DINGTALK_CLIENT_SECRET": "your-app-secret"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Running
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Start only the DingTalk channel
|
|
68
|
+
qwen channel start my-dingtalk
|
|
69
|
+
|
|
70
|
+
# Or start all configured channels together
|
|
71
|
+
qwen channel start
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Open DingTalk and send a message to the bot. You should see a 👀 emoji reaction appear while the agent processes, followed by the response.
|
|
75
|
+
|
|
76
|
+
## Group Chats
|
|
77
|
+
|
|
78
|
+
DingTalk bots work in both DM and group conversations. To enable group support:
|
|
79
|
+
|
|
80
|
+
1. Set `groupPolicy` to `"allowlist"` or `"open"` in your channel config
|
|
81
|
+
2. Add the bot to a DingTalk group
|
|
82
|
+
3. @mention the bot in the group to trigger a response
|
|
83
|
+
|
|
84
|
+
By default, the bot requires an @mention in group chats (`requireMention: true`). Set `"requireMention": false` for a specific group to make it respond to all messages. See [Group Chats](./overview#group-chats) for full details.
|
|
85
|
+
|
|
86
|
+
### Finding a Group's Conversation ID
|
|
87
|
+
|
|
88
|
+
DingTalk uses `conversationId` to identify groups. You can find it in the channel service logs when someone sends a message in the group — look for the `conversationId` field in the log output.
|
|
89
|
+
|
|
90
|
+
## Images and Files
|
|
91
|
+
|
|
92
|
+
You can send photos and documents to the bot, not just text.
|
|
93
|
+
|
|
94
|
+
**Photos:** Send an image (screenshot, diagram, etc.) and the agent will analyze it using its vision capabilities. This requires a multimodal model — add `"model": "qwen3.5-plus"` (or another vision-capable model) to your channel config. DingTalk supports sending images directly or as part of rich text messages (mixed text + images).
|
|
95
|
+
|
|
96
|
+
**Files:** Send a PDF, code file, or any document. The bot downloads it from DingTalk's servers and saves it locally so the agent can read it with its file tools. Audio and video files are also supported. This works with any model.
|
|
97
|
+
|
|
98
|
+
## Key Differences from Telegram
|
|
99
|
+
|
|
100
|
+
- **Authentication:** AppKey + AppSecret instead of a static bot token. The SDK manages access token refresh automatically.
|
|
101
|
+
- **Connection:** WebSocket stream instead of polling — no public IP or webhook URL needed.
|
|
102
|
+
- **Formatting:** Responses use DingTalk's markdown dialect (a limited subset). Tables are automatically converted to plain text since DingTalk doesn't render them. Long messages are split into chunks at ~3800 characters.
|
|
103
|
+
- **Working indicator:** A 👀 emoji reaction is added to the user's message while processing, then removed when the response is sent.
|
|
104
|
+
- **Media download:** Two-step process — a `downloadCode` from the message is exchanged for a temporary download URL via DingTalk's API.
|
|
105
|
+
- **Groups:** DingTalk uses `isInAtList` for @mention detection instead of parsing message entities.
|
|
106
|
+
|
|
107
|
+
## Tips
|
|
108
|
+
|
|
109
|
+
- **Use DingTalk markdown-aware instructions** — DingTalk supports a limited markdown subset (headers, bold, links, code blocks, but not tables). Adding instructions like "Use DingTalk markdown. Avoid tables." helps the agent format responses correctly.
|
|
110
|
+
- **Restrict access** — In an organization context, `senderPolicy: "open"` may be acceptable. For tighter control, use `"allowlist"` or `"pairing"`. See [DM Pairing](./overview#dm-pairing) for details.
|
|
111
|
+
- **Referenced messages** — Quoting (replying to) a user message includes the quoted text as context for the agent. Quoting bot responses is not yet supported.
|
|
112
|
+
|
|
113
|
+
## Troubleshooting
|
|
114
|
+
|
|
115
|
+
### Bot doesn't connect
|
|
116
|
+
|
|
117
|
+
- Verify your AppKey and AppSecret are correct
|
|
118
|
+
- Check that the environment variables are set before running `qwen channel start`
|
|
119
|
+
- Make sure **Stream Mode** is enabled in the bot's settings on the DingTalk Developer Portal
|
|
120
|
+
- Check the terminal output for connection errors
|
|
121
|
+
|
|
122
|
+
### Bot doesn't respond in groups
|
|
123
|
+
|
|
124
|
+
- Check that `groupPolicy` is set to `"allowlist"` or `"open"` (default is `"disabled"`)
|
|
125
|
+
- Make sure you @mention the bot in the group message
|
|
126
|
+
- Verify the bot has been added to the group
|
|
127
|
+
|
|
128
|
+
### "No sessionWebhook in message"
|
|
129
|
+
|
|
130
|
+
This means DingTalk didn't include a reply endpoint in the message callback. This can happen if the bot's permissions are misconfigured. Check the bot's settings in the Developer Portal.
|
|
131
|
+
|
|
132
|
+
### "Sorry, something went wrong processing your message"
|
|
133
|
+
|
|
134
|
+
This usually means the agent encountered an error. Check the terminal output for details.
|