@agifyai/leadify-mcp 9.0.0 → 9.1.1
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/README.md +3 -3
- package/dist/tools/campaigns.js +4 -1
- package/dist/tools/personas.js +65 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,9 +312,9 @@ Leadify et ne doit jamais être envoyée par un agent MCP.
|
|
|
312
312
|
| `apply_canonical_identity_backfill` | Appliquer exactement un backfill d'identité relu par digest, sans outreach ni activation. |
|
|
313
313
|
| `update_company_brain_sections` | Modifier uniquement les sections globales encore actives (`identity`, `positioning`, `allowedVocabulary`, `prohibitedVocabulary`, `legalConstraints`). Les anciennes sections Offre/Verticale sont filtrées et refusées. |
|
|
314
314
|
| `publish_context_workspace` | Publier une révision prête du Company Brain après confirmation explicite (`confirm_publish: true`). Admin de l'organisation requis ; les raisons de non-readiness sont renvoyées par le serveur. |
|
|
315
|
-
| `list_persona_contracts` / `get_persona_contract` | Lister ou lire les contrats Persona canoniques v2 d’une organisation explicitement sélectionnée. `intelligence` ne contient que `painPoints`, `
|
|
316
|
-
| `create_persona_contract` | Créer un Persona tenant-scoped et lié à une Verticale depuis un contrat canonique v2 complet et strict. `tool_pack_id
|
|
317
|
-
| `replace_persona_contract` / `patch_persona_contract` | Remplacer ou modifier un contrat canonique v2 avec verrou optimiste. `name` / `description` sont acceptés sur replace. `tool_pack_id` est
|
|
315
|
+
| `list_persona_contracts` / `get_persona_contract` | Lister ou lire les contrats Persona canoniques v2 d’une organisation explicitement sélectionnée. Le contrat suit celui de Leadify : `intelligence` ne contient que `painPoints`, `outreach` que `outreachTemplates`, et les blocs retirés par PRD-1816 (`agentDomain`, `signalTierRules`, `enableSignals`, `icpStrategy`, `cardAnalysisSections`, `outreachSignalRouting`, `toneInstructions`, `outreachFields`) sont refusés à l’écriture et retirés à la lecture des anciens contrats ; `activeTools` n’appartient pas au contrat. |
|
|
316
|
+
| `create_persona_contract` | Créer un Persona tenant-scoped et lié à une Verticale depuis un contrat canonique v2 complet et strict. Aucun pack d’outils n’est demandé : `tool_pack_id`, s’il est encore envoyé, est ignoré et n’est jamais transmis à Leadify. Toute clé inconnue du contrat est refusée. |
|
|
317
|
+
| `replace_persona_contract` / `patch_persona_contract` | Remplacer ou modifier un contrat canonique v2 avec verrou optimiste. `name` / `description` sont acceptés sur replace. `tool_pack_id` est ignoré, comme à la création. Une Persona ACTIVE mutée repasse en DRAFT. |
|
|
318
318
|
| `change_persona_status` | Passer un Persona entre `DRAFT`, `ACTIVE` et `ARCHIVED` avec le même verrou `updated_at`, readiness et protection des références. Après un replace/patch, rappeler ce tool vers `ACTIVE` pour que les groupes résolvent à nouveau la Persona. |
|
|
319
319
|
| `list_data_sources` | Lister toutes les sources de données configurées (par pays puis nom). |
|
|
320
320
|
| `create_data_source` | Créer une nouvelle source de données (admin uniquement). |
|
package/dist/tools/campaigns.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getClient } from "../client.js";
|
|
3
3
|
import { toolResult, handleToolError } from "../types.js";
|
|
4
|
-
|
|
4
|
+
// PILOT (Leadify PRD-2353) : entre le backlog et le lancement, la campagne rédige des
|
|
5
|
+
// messages d'essai sans rien envoyer. Il s'entre et se quitte par les routes du pilote.
|
|
6
|
+
const CAMPAIGN_STATUSES = ["DRAFT", "PILOT", "ACTIVE", "PAUSED", "COMPLETED"];
|
|
5
7
|
const CAMPAIGN_EFFECTIVE_STATES = [
|
|
6
8
|
"DRAFT",
|
|
9
|
+
"PILOT",
|
|
7
10
|
"SCHEDULED",
|
|
8
11
|
"ACTIVE",
|
|
9
12
|
"PAUSED_MANUAL",
|
package/dist/tools/personas.js
CHANGED
|
@@ -6,15 +6,28 @@ import { LeadifyApiError, handleToolError, toolResult } from "../types.js";
|
|
|
6
6
|
* versioned `personaContract`. These tools deliberately do not expose any
|
|
7
7
|
* historical Persona field or field-specific patch operation.
|
|
8
8
|
*
|
|
9
|
-
* The published MCP contract must match the server `personaContractSchema
|
|
10
|
-
* `intelligence.activeTools`
|
|
11
|
-
*
|
|
9
|
+
* The published MCP contract must match the server `personaContractSchema`
|
|
10
|
+
* (Leadify `apps/server/src/lib/persona-contract.ts`). `intelligence.activeTools`
|
|
11
|
+
* is not part of that document, and the blocks removed by PRD-1816 are refused
|
|
12
|
+
* on write and stripped from older stored contracts on read.
|
|
13
|
+
*
|
|
14
|
+
* PRD-2295: since PRD-2238 Leadify no longer requires or reads a tool pack.
|
|
15
|
+
* `tool_pack_id` stays accepted on writes so older callers keep working, but it
|
|
16
|
+
* is ignored and never sent to the API.
|
|
12
17
|
*/
|
|
13
18
|
const tierSchema = z.object({
|
|
14
19
|
rule: z.string(),
|
|
15
20
|
expectedEvidence: z.string(),
|
|
16
21
|
examples: z.array(z.string()).max(20),
|
|
17
22
|
}).strict();
|
|
23
|
+
// PRD-1816: blocks Leadify removed from the contract.
|
|
24
|
+
const REMOVED_CONTRACT_KEYS = {
|
|
25
|
+
targeting: ["agentDomain"],
|
|
26
|
+
qualification: ["signalTierRules", "enableSignals"],
|
|
27
|
+
intelligence: ["icpStrategy", "cardAnalysisSections"],
|
|
28
|
+
outreach: ["outreachSignalRouting", "toneInstructions", "outreachFields"],
|
|
29
|
+
};
|
|
30
|
+
const REMOVED_TARGET_PROFILE_KEYS = ["buyerTypes", "coreDefinition", "productFamilies", "notTheDefinition"];
|
|
18
31
|
const commonContractSchema = z.object({
|
|
19
32
|
schemaVersion: z.literal(2),
|
|
20
33
|
kind: z.enum(["PERSON", "COMPANY"]),
|
|
@@ -22,9 +35,21 @@ const commonContractSchema = z.object({
|
|
|
22
35
|
targetProfile: z.unknown().nullable(),
|
|
23
36
|
disqualificationCriteria: z.unknown().nullable(),
|
|
24
37
|
schemaPacks: z.array(z.string()).max(2),
|
|
25
|
-
agentDomain: z.string().nullable(),
|
|
26
38
|
outputLanguage: z.string().nullable(),
|
|
27
|
-
}).strict(),
|
|
39
|
+
}).strict().superRefine((targeting, ctx) => {
|
|
40
|
+
const profile = targeting.targetProfile;
|
|
41
|
+
if (!profile || typeof profile !== "object" || Array.isArray(profile))
|
|
42
|
+
return;
|
|
43
|
+
for (const key of REMOVED_TARGET_PROFILE_KEYS) {
|
|
44
|
+
if (profile[key] !== undefined) {
|
|
45
|
+
ctx.addIssue({
|
|
46
|
+
code: z.ZodIssueCode.custom,
|
|
47
|
+
path: ["targetProfile", key],
|
|
48
|
+
message: `targeting.targetProfile.${key} was removed (PRD-1816)`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}),
|
|
28
53
|
qualification: z.object({
|
|
29
54
|
tiers: z.object({
|
|
30
55
|
hot: tierSchema,
|
|
@@ -38,19 +63,12 @@ const commonContractSchema = z.object({
|
|
|
38
63
|
level: z.enum(["GOLDEN", "CRITICAL", "STRONG", "INFO"]),
|
|
39
64
|
justification: z.string().min(1),
|
|
40
65
|
}).strict()).max(100),
|
|
41
|
-
signalTierRules: z.unknown().nullable(),
|
|
42
|
-
enableSignals: z.boolean(),
|
|
43
66
|
}).strict(),
|
|
44
67
|
intelligence: z.object({
|
|
45
68
|
painPoints: z.unknown().nullable(),
|
|
46
|
-
icpStrategy: z.unknown().nullable(),
|
|
47
|
-
cardAnalysisSections: z.unknown().nullable(),
|
|
48
69
|
}).strict(),
|
|
49
70
|
outreach: z.object({
|
|
50
|
-
outreachSignalRouting: z.unknown().nullable(),
|
|
51
71
|
outreachTemplates: z.unknown().nullable(),
|
|
52
|
-
toneInstructions: z.string().nullable(),
|
|
53
|
-
outreachFields: z.unknown().nullable(),
|
|
54
72
|
}).strict(),
|
|
55
73
|
}).strict();
|
|
56
74
|
const personExtensionSchema = z.object({
|
|
@@ -81,13 +99,38 @@ function withoutOutOfContractKeys(value) {
|
|
|
81
99
|
}
|
|
82
100
|
return contract;
|
|
83
101
|
}
|
|
102
|
+
/** Older stored contracts may still carry the PRD-1816 blocks: read them without those blocks. */
|
|
103
|
+
function withoutRemovedContractKeys(value) {
|
|
104
|
+
const contract = withoutOutOfContractKeys(value);
|
|
105
|
+
if (!contract || typeof contract !== "object" || Array.isArray(contract))
|
|
106
|
+
return contract;
|
|
107
|
+
const record = contract;
|
|
108
|
+
for (const [section, keys] of Object.entries(REMOVED_CONTRACT_KEYS)) {
|
|
109
|
+
const block = record[section];
|
|
110
|
+
if (!block || typeof block !== "object" || Array.isArray(block))
|
|
111
|
+
continue;
|
|
112
|
+
for (const key of keys)
|
|
113
|
+
delete block[key];
|
|
114
|
+
}
|
|
115
|
+
const targeting = record.targeting;
|
|
116
|
+
const profile = targeting?.targetProfile;
|
|
117
|
+
if (profile && typeof profile === "object" && !Array.isArray(profile)) {
|
|
118
|
+
for (const key of REMOVED_TARGET_PROFILE_KEYS)
|
|
119
|
+
delete profile[key];
|
|
120
|
+
}
|
|
121
|
+
return record;
|
|
122
|
+
}
|
|
84
123
|
function parsePersistedContract(value) {
|
|
85
|
-
return contractSchema.parse(
|
|
124
|
+
return contractSchema.parse(withoutRemovedContractKeys(value));
|
|
86
125
|
}
|
|
87
126
|
function parseWrittenContract(value) {
|
|
88
|
-
return
|
|
127
|
+
return contractSchema.parse(withoutOutOfContractKeys(value));
|
|
89
128
|
}
|
|
90
129
|
const contractInputSchema = z.preprocess(withoutOutOfContractKeys, contractSchema).describe("Complete strict Persona contract, schemaVersion 2. intelligence.activeTools is not a contract field and is stripped if sent.");
|
|
130
|
+
const ignoredToolPackId = z
|
|
131
|
+
.string()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Deprecated and ignored: Leadify no longer uses tool packs. Never sent to the API; omit it.");
|
|
91
134
|
const tenantScope = {
|
|
92
135
|
organization_id: z
|
|
93
136
|
.string()
|
|
@@ -102,12 +145,6 @@ const optimisticScope = {
|
|
|
102
145
|
.datetime({ offset: true })
|
|
103
146
|
.describe("Exact updatedAt obtained from a preceding read."),
|
|
104
147
|
};
|
|
105
|
-
function requireToolPackId(persona, override) {
|
|
106
|
-
const toolPackId = override?.trim() || persona.toolPackId?.trim();
|
|
107
|
-
if (!toolPackId)
|
|
108
|
-
throw new Error("PERSONA_TOOL_PACK_REQUIRED");
|
|
109
|
-
return toolPackId;
|
|
110
|
-
}
|
|
111
148
|
function canonicalPersona(persona) {
|
|
112
149
|
if (!persona.personaContract || typeof persona.personaContract !== "object") {
|
|
113
150
|
throw new Error("PERSONA_CONTRACT_REQUIRED: run the audited Persona migration before using this MCP.");
|
|
@@ -118,7 +155,6 @@ function canonicalPersona(persona) {
|
|
|
118
155
|
name: persona.name,
|
|
119
156
|
description: persona.description ?? null,
|
|
120
157
|
verticalId: persona.verticalId,
|
|
121
|
-
toolPackId: persona.toolPackId ?? null,
|
|
122
158
|
updatedAt: persona.updatedAt,
|
|
123
159
|
revision: persona.revision ?? 0,
|
|
124
160
|
status: persona.status,
|
|
@@ -171,7 +207,6 @@ async function replaceContract(input) {
|
|
|
171
207
|
organizationId: input.organizationId,
|
|
172
208
|
verticalId: persona.verticalId,
|
|
173
209
|
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
174
|
-
toolPackId: requireToolPackId(persona, input.toolPackId),
|
|
175
210
|
...(input.description !== undefined ? { description: input.description } : {}),
|
|
176
211
|
personaContract: parseWrittenContract(input.contract),
|
|
177
212
|
});
|
|
@@ -198,24 +233,19 @@ export function registerPersonaTools(server, injectedClient) {
|
|
|
198
233
|
return handleToolError(error);
|
|
199
234
|
}
|
|
200
235
|
});
|
|
201
|
-
server.tool("create_persona_contract", "Create a Persona from one complete canonical contract v2. intelligence.activeTools is not part of the contract.
|
|
236
|
+
server.tool("create_persona_contract", "Create a Persona from one complete canonical contract v2. intelligence.activeTools is not part of the contract. No tool pack is needed.", {
|
|
202
237
|
...tenantScope,
|
|
203
238
|
vertical_id: z.string().trim().min(1),
|
|
204
239
|
name: z.string().trim().min(1),
|
|
205
240
|
description: z.string().optional(),
|
|
206
|
-
tool_pack_id:
|
|
207
|
-
.string()
|
|
208
|
-
.trim()
|
|
209
|
-
.min(1)
|
|
210
|
-
.describe("Tenant-scoped tool pack. Not part of personaContract."),
|
|
241
|
+
tool_pack_id: ignoredToolPackId,
|
|
211
242
|
contract: contractInputSchema,
|
|
212
|
-
}, async ({ organization_id, vertical_id, name, description,
|
|
243
|
+
}, async ({ organization_id, vertical_id, name, description, contract }) => {
|
|
213
244
|
try {
|
|
214
245
|
return toolResult(await client.post("/api/persona", {
|
|
215
246
|
organizationId: organization_id,
|
|
216
247
|
verticalId: vertical_id,
|
|
217
248
|
name,
|
|
218
|
-
toolPackId: tool_pack_id,
|
|
219
249
|
...(description !== undefined ? { description } : {}),
|
|
220
250
|
personaContract: parseWrittenContract(contract),
|
|
221
251
|
}));
|
|
@@ -224,19 +254,14 @@ export function registerPersonaTools(server, injectedClient) {
|
|
|
224
254
|
return handleToolError(error);
|
|
225
255
|
}
|
|
226
256
|
});
|
|
227
|
-
server.tool("replace_persona_contract", "Replace the complete canonical contract using optimistic concurrency.
|
|
257
|
+
server.tool("replace_persona_contract", "Replace the complete canonical contract using optimistic concurrency. Mutating an ACTIVE Persona returns it to DRAFT; call change_persona_status to reactivate.", {
|
|
228
258
|
...optimisticScope,
|
|
229
259
|
id: z.string().min(1),
|
|
230
260
|
name: z.string().trim().min(1).optional(),
|
|
231
261
|
description: z.string().optional(),
|
|
232
|
-
tool_pack_id:
|
|
233
|
-
.string()
|
|
234
|
-
.trim()
|
|
235
|
-
.min(1)
|
|
236
|
-
.optional()
|
|
237
|
-
.describe("Optional pack change. When omitted, the persisted toolPackId is reused."),
|
|
262
|
+
tool_pack_id: ignoredToolPackId,
|
|
238
263
|
contract: contractInputSchema,
|
|
239
|
-
}, async ({ organization_id, id, expected_updated_at, name, description,
|
|
264
|
+
}, async ({ organization_id, id, expected_updated_at, name, description, contract }) => {
|
|
240
265
|
try {
|
|
241
266
|
return toolResult(await replaceContract({
|
|
242
267
|
organizationId: organization_id,
|
|
@@ -244,7 +269,6 @@ export function registerPersonaTools(server, injectedClient) {
|
|
|
244
269
|
expectedUpdatedAt: expected_updated_at,
|
|
245
270
|
name,
|
|
246
271
|
description,
|
|
247
|
-
toolPackId: tool_pack_id,
|
|
248
272
|
contract: parseWrittenContract(contract),
|
|
249
273
|
client,
|
|
250
274
|
}));
|
|
@@ -258,13 +282,8 @@ export function registerPersonaTools(server, injectedClient) {
|
|
|
258
282
|
id: z.string().min(1),
|
|
259
283
|
path: z.string().trim().min(1),
|
|
260
284
|
value: z.unknown(),
|
|
261
|
-
tool_pack_id:
|
|
262
|
-
|
|
263
|
-
.trim()
|
|
264
|
-
.min(1)
|
|
265
|
-
.optional()
|
|
266
|
-
.describe("Optional pack change. When omitted, the persisted toolPackId is reused."),
|
|
267
|
-
}, async ({ organization_id, id, expected_updated_at, path, value, tool_pack_id }) => {
|
|
285
|
+
tool_pack_id: ignoredToolPackId,
|
|
286
|
+
}, async ({ organization_id, id, expected_updated_at, path, value }) => {
|
|
268
287
|
try {
|
|
269
288
|
const persona = await fetchPersona(id, organization_id, client);
|
|
270
289
|
const contract = canonicalPersona(persona).contract;
|
|
@@ -272,7 +291,6 @@ export function registerPersonaTools(server, injectedClient) {
|
|
|
272
291
|
organizationId: organization_id,
|
|
273
292
|
id,
|
|
274
293
|
expectedUpdatedAt: expected_updated_at,
|
|
275
|
-
toolPackId: tool_pack_id,
|
|
276
294
|
contract: contractSchema.parse(setContractPath(contract, path, value)),
|
|
277
295
|
client,
|
|
278
296
|
}));
|