Table of Contents
Configuration
Config is a Schemastery schema plus a same-named interface. It is validated when the plugin loads; invalid config fails the load with an actionable error. A config edit hot-replaces the plugin.
Full schema
import Schema from '@deepseek-ai/schemastery'
export interface Config {
accessToken: string
userAccessToken?: string
groupId: number
apiVersion: string
language: 'ru' | 'en' | 'uk'
rateLimit: { rps: number; burst: number; maxConcurrent: number }
retry: { maxAttempts: number; baseDelayMs: number; maxDelayMs: number; retryOn: number[] }
captcha: { policy: 'fail' | 'ask'; solverTool?: string }
longpoll: { enabled: boolean; mode: 0 | 1 | 2; timeoutSec: number; batchMs: number }
callback: { enabled: boolean; serverUrl?: string; confirmToken?: string; secret?: string }
moderation: { enabled: boolean; autoApprove: boolean; warnThreshold: number; exemptUserIds: number[] }
safety: { requireConfirmForDestructive: boolean; dryRunDefault: boolean; rawApiEnabled: boolean }
notifications: { onMessage: boolean; onComment: boolean; onJoin: boolean; onLeave: boolean }
ui: { settingsTab: boolean; moderationQueue: boolean }
}
Field reference
accessToken (required)
The community token. Never logged, never placed in tool arguments, never returned by any tool. Read once in apply, held in a closure, redacted in the audit log as <redacted>.
userAccessToken (optional)
The admin's user token. Unlocks vk_members_list, vk_stats_get, and the complete vk_ban_list. Without it those tools return VK_SCOPE_MISSING naming the exact scope.
groupId
The community id. Accepts either sign; normalized internally to a negative number for owner_id purposes.
apiVersion
Default '5.199'. Sent on every request. Do not leave it unset — VK's behaviour without v is unpredictable.
language
'ru' | 'en' | 'uk'. Passed as lang on requests that accept it and used for VK-generated error text.
rateLimit
| Field | Default | Meaning |
|---|---|---|
rps |
3 | sustained requests per second for the community token |
burst |
5 | token-bucket depth |
maxConcurrent |
2 | in-flight request cap |
Raise rps only if you use a user token (limit ~20/s). Exceeding it yields error 6.
retry
| Field | Default | Meaning |
|---|---|---|
maxAttempts |
4 | total attempts including the first |
baseDelayMs |
400 | first backoff delay |
maxDelayMs |
8000 | backoff ceiling |
retryOn |
[1, 6, 9, 10] |
VK error codes treated as transient |
Everything not in retryOn fails fast. 5 (auth), 15 (access), 100 (bad param) must never be retried.
captcha
policy: 'fail' (default) — return VK_CAPTCHA_REQUIRED with the captcha_sid and stop. policy: 'ask' — the pre-execute gate returns ask so a human can solve it and the call resumes with captcha_key.
solverTool names an external tool that can solve the captcha; it is not built in. Automated captcha solving is out of scope (see Non-Goals).
longpoll
| Field | Default | Meaning |
|---|---|---|
enabled |
false | start the background job on load |
mode |
2 | 0 = no typing/online, 1 = messages only, 2 = messages + typing |
timeoutSec |
25 | wait parameter |
batchMs |
1500 | window over which events are coalesced into one agent message |
callback
Off by default — needs a public HTTPS endpoint. When enabled, serverUrl, confirmToken and secret are required (validated by the schema).
moderation
| Field | Default | Meaning |
|---|---|---|
enabled |
false | run the rule engine |
autoApprove |
false | auto-approve join requests (dangerous; opt-in only) |
warnThreshold |
3 | warnings before an automatic ban |
exemptUserIds |
[] |
users the engine never touches |
safety
| Field | Default | Meaning |
|---|---|---|
requireConfirmForDestructive |
true | destructive tools return ask from pre-execute |
dryRunDefault |
true | vk_community_update defaults to dryRun: true |
rawApiEnabled |
false | enables vk_api_raw |
notifications
Per-event-type switches for the LongPoll → agent bridge. onJoin/onLeave are off by default because a busy community generates a lot of noise.
ui
settingsTab adds a settings panel; moderationQueue adds the moderation queue view. Both require the client half of the plugin to be installed in a Web profile.
Example: production profile
- insert:
- id: vk-group
name: dsh-vk-group
config:
groupId: -123456789
accessToken: !!js process.env.VK_COMMUNITY_TOKEN
userAccessToken: !!js process.env.VK_USER_TOKEN
apiVersion: '5.199'
language: ru
rateLimit: { rps: 3, burst: 5, maxConcurrent: 2 }
longpoll: { enabled: true, mode: 2, timeoutSec: 25, batchMs: 1500 }
moderation: { enabled: true, autoApprove: false, warnThreshold: 3, exemptUserIds: [1] }
safety: { requireConfirmForDestructive: true, dryRunDefault: true, rawApiEnabled: false }
notifications: { onMessage: true, onComment: true, onJoin: false, onLeave: false }
Example: read-only audit profile
- insert:
- id: vk-group
name: dsh-vk-group
config:
groupId: -123456789
accessToken: !!js process.env.VK_COMMUNITY_TOKEN
longpoll: { enabled: false }
safety: { requireConfirmForDestructive: true, dryRunDefault: true, rawApiEnabled: false }
ui: { settingsTab: false, moderationQueue: false }
Secrets
Tokens come from the environment, never from the patch file. Use !!js process.env.X — DSH evaluates the expression against the injected context after the row's dependencies are ready.
Never commit a .env with real tokens. The audit log redacts tokens as <redacted>; if you add a new log line, redact there too.
Validation failures
| Symptom | Cause |
|---|---|
accessToken: required |
missing token |
groupId: expected number |
id passed as a string |
callback.serverUrl: required |
callback.enabled: true without a URL |
rateLimit.rps: must be > 0 |
zero or negative |
Failures are loud by design — the plugin refuses to load rather than degrading silently.