Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions docs/runtime-routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -74726,6 +74726,39 @@
}
}
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
}
}
}
Expand Down Expand Up @@ -75235,6 +75268,39 @@
}
}
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
}
}
}
Expand Down Expand Up @@ -76112,6 +76178,39 @@
}
}
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
}
}
}
Expand Down Expand Up @@ -76624,6 +76723,39 @@
}
}
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
}
}
}
Expand Down Expand Up @@ -77874,6 +78006,39 @@
"maximum": 2592000
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
},
"automationSafety": {
"type": [
"object",
Expand Down Expand Up @@ -78449,6 +78614,39 @@
"maximum": 2592000
}
},
"mistakesGenerator": {
"type": [
"object",
"null"
],
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"minLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"maxLetters": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"probability": {
"type": "integer",
"minimum": 0,
"maximum": 100
}
},
"required": [
"enabled",
"minLetters",
"maxLetters",
"probability"
]
},
"automationSafety": {
"type": [
"object",
Expand Down
4 changes: 4 additions & 0 deletions docs/settings-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ Example:
}
}
```

### Mistakes generator

Templates may include `mistakesGenerator` with `enabled`, `minLetters`, `maxLetters`, and `probability` (0-100). When present, it overrides the instance Mistakes Generator for sends resolved through that template. Protected URL/domain, email, mention, and phone-like tokens are never changed. See [instance settings](./settings.md#mistakes-generator).
21 changes: 21 additions & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,24 @@ The local-read precedence order is method override for this instance, instance d
Archive capture and purge settings are separate because they require `ARCHIVE_API_KEY`. They appear lower on the same manager page and are fully documented in [the archive reference](./archive.md).

The Manager exposes every `automationSafety` field under **Instance → Settings → Automation safety & pacing**, including the separate unique new/dormant-recipient quota and its inactivity window. See the [full policy reference](./outbound-automation-safety.md), including defaults, relationship semantics, bounds, response behavior, and examples.

## Mistakes generator

`mistakesGenerator` is an optional outbound-text transformation. It is disabled by default.

```json
{
"mistakesGenerator": {
"enabled": true,
"minLetters": 1,
"maxLetters": 2,
"probability": 35
}
}
```

For each eligible send, `probability` is the integer percentage (0-100) that the transformation runs. It changes a random count between `minLetters` and `maxLetters`, capped by the safe eligible letters in the message. Replacements come from adjacent keys in the detected Latin, Hebrew, Cyrillic, or Arabic keyboard row and preserve uppercase letters.

URLs, bare domains such as `wikipedia.com`, email addresses, mentions, and phone-like identifiers are protected as whole tokens. Quoted keys, mentions, link-preview options, and other message metadata are not changed. Messages with no safe eligible letters are sent unchanged.

Settings Templates may provide the same object. Explicit request template, contact/group binding, and instance binding follow the normal template hierarchy; without a template value, the instance setting is used.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion manager/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="icon" type="image/png" href="https://evolution-api.com/files/evo/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Evolution Manager</title>
<script type="module" crossorigin src="/assets/index-DojtwdUs.js"></script>
<script type="module" crossorigin src="/assets/index-BO6uiHOD.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CSeJbyWk.css">
</head>
<body>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"db:migrate:dev:win": "node runWithProvider.js \"xcopy /E /I prisma\\DATABASE_PROVIDER-migrations prisma\\migrations && npx prisma migrate dev --schema prisma\\DATABASE_PROVIDER-schema.prisma\"",
"prepare": "husky",
"test:settings-templates": "tsx ./test/settings-template-hierarchy.test.ts",
"test:review-surfaces": "tsx ./test/review-surfaces.test.ts"
"test:review-surfaces": "tsx ./test/review-surfaces.test.ts",
"test:mistakes-generator": "tsx ./test/mistakes-generator.test.ts"
},
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `Setting` ADD COLUMN `mistakesGenerator` JSON NULL;
1 change: 1 addition & 0 deletions prisma/mysql-schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ model Setting {
localReadTtlSeconds Int?
localReadTtlOverrides Json?
automationSafety Json?
mistakesGenerator Json?
createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "Setting" ADD COLUMN "mistakesGenerator" JSONB;
1 change: 1 addition & 0 deletions prisma/postgresql-schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ model Setting {
localReadTtlSeconds Int? @db.Integer
localReadTtlOverrides Json? @db.JsonB
automationSafety Json? @db.JsonB
mistakesGenerator Json? @db.JsonB
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
Expand Down
1 change: 1 addition & 0 deletions prisma/psql_bouncer-schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ model Setting {
localReadTtlSeconds Int? @db.Integer
localReadTtlOverrides Json? @db.JsonB
automationSafety Json? @db.JsonB
mistakesGenerator Json? @db.JsonB
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
Expand Down
9 changes: 9 additions & 0 deletions src/api/dto/settings.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export class SettingsDto {
localReadTtlOverrides?: Record<string, number> | null;
/** Per-instance outbound automation safeguards and user-experience pacing. */
automationSafety?: AutomationSafetySettings | null;
/** Optional natural typo generation for outbound human-readable text. */
mistakesGenerator?: MistakesGeneratorSettings | null;
}

export type AutomationSafetySettings = {
Expand Down Expand Up @@ -66,3 +68,10 @@ export type AutomationSafetySettings = {
retentionDays?: number;
};
};

export type MistakesGeneratorSettings = {
enabled: boolean;
minLetters: number;
maxLetters: number;
probability: number;
};
3 changes: 2 additions & 1 deletion src/api/dto/settingsTemplate.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { AutomationSafetySettings } from './settings.dto';
import { AutomationSafetySettings, MistakesGeneratorSettings } from './settings.dto';

export type TemplateSettings = {
localReadTtlSeconds?: number | null;
localReadTtlOverrides?: Record<string, number> | null;
automationSafety?: AutomationSafetySettings | null;
mistakesGenerator?: MistakesGeneratorSettings | null;
};

export class SettingsTemplateCreateDto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
messageUpdateIdentity,
} from '@api/services/message-archive.service';
import { preserveMessageKey } from '@api/services/message-key.service';
import { applyMistakesToMessage } from '@api/services/mistakes-generator.service';
import { OutboundSafetyService } from '@api/services/outbound-safety.service';
import { SettingsTemplateService } from '@api/services/settings-template.service';
import { Events, MessageSubtype, TypeMediaMessage, wa } from '@api/types/wa.types';
Expand Down Expand Up @@ -2600,6 +2601,7 @@ export class BaileysStartupService extends ChannelStartupService {
settingsTemplateId,
);
const effectiveSafety = templateSettings?.automationSafety ?? this.localSettings.automationSafety;
const effectiveMistakes = templateSettings?.mistakesGenerator ?? this.localSettings.mistakesGenerator;
const preflightBlockCode = this.outboundSafety.preflightBlockCode(requestedRecipient, effectiveSafety);
if (preflightBlockCode) {
const preflight = await this.outboundSafety.begin(this.instanceId, requestedRecipient, message, effectiveSafety);
Expand Down Expand Up @@ -2628,6 +2630,7 @@ export class BaileysStartupService extends ChannelStartupService {
message: 'Outbound message blocked by the instance automation safety policy.',
});
}
message = applyMistakesToMessage(message, effectiveMistakes);
const pacingDelay = Math.max(options?.delay ?? 0, safety.delayMs);
const pacingPresence = options?.presence ?? safety.presence;
let deliveryRecorded = false;
Expand Down
Loading
Loading