feat: expand outreach targeting and messaging

This commit is contained in:
jjbrunton committed 2026-08-10 17:31:05 +01:00
1 parent 7defff422d
commit d0a8bd0e2f
40 files changed
+890 -82

No files matched your search

+8
View File
@@ -22,6 +22,14 @@ export const RuntimeRedditConfigSchema = z.strictObject({
prioritizeRecentPosts: z.boolean(),
recentWindowMinutes: z.number(),
maxReadyCandidates: z.number().int().min(1).max(500),
physiqueTargeting: z.strictObject({
enabled: z.boolean(),
minScore: z.number().int().min(1).max(10),
maxScore: z.number().int().min(1).max(10),
}).refine((targeting) => targeting.minScore <= targeting.maxScore, {
message: 'Minimum physique score cannot exceed maximum physique score.',
path: ['minScore'],
}).default({ enabled: false, minScore: 1, maxScore: 10 }),
});
export const RuntimeConfigSchema = z.strictObject({
rateLimit: RateLimitConfigSchema,
+23
View File
@@ -17,6 +17,27 @@ export const OutreachStageCountsSchema = z.strictObject({
retryable: z.number().int().nonnegative(),
});
export const OutreachPreparationSchema = z.strictObject({
message: z.string(),
imageAnalysis: z.string(),
detectedGender: z.enum(['male', 'female', 'other', 'unknown']),
attractivenessScore: z.number().int().min(1).max(100).nullable(),
physiqueScore: z.number().int().min(1).max(10).nullable(),
physiqueTargeting: z.strictObject({
enabled: z.boolean(),
minScore: z.number().int().min(1).max(10),
maxScore: z.number().int().min(1).max(10),
}).nullable(),
sourceImageUrl: z.string().nullable(),
strategyId: z.string().nullable(),
experimentId: z.string().nullable(),
promptVersion: z.string().nullable(),
selectionReason: z.enum(['explore', 'exploit']).nullable(),
modelId: z.string(),
toneId: z.string(),
scripted: z.boolean(),
});
export const OutreachCandidateSchema = z.strictObject({
postId: z.string(),
subreddit: z.string(),
@@ -32,6 +53,8 @@ export const OutreachCandidateSchema = z.strictObject({
availableAt: z.number(),
attemptCount: z.number().int().nonnegative(),
hasPreparedMessage: z.boolean(),
physiqueScore: z.number().int().min(1).max(10).nullable().default(null),
preparation: OutreachPreparationSchema.nullable().default(null),
note: z.string().nullable(),
owner: RedditAccountOwnerSchema.nullable(),
});
@@ -149,7 +149,12 @@ describe('dashboard endpoint contracts', () => {
const payload = {
rateLimit: { minDelayBetweenMessagesMs: 300_000, maxMessagesPerHour: 8, jitterMs: 60_000 },
browser: { dryRun: false },
reddit: { prioritizeRecentPosts: true, recentWindowMinutes: 60, maxReadyCandidates: 25 },
reddit: {
prioritizeRecentPosts: true,
recentWindowMinutes: 60,
maxReadyCandidates: 25,
physiqueTargeting: { enabled: false, minScore: 1, maxScore: 10 },
},
subreddits: [{ name: 'example', enabled: true, type: 'chat', weight: 2, tone: 'direct' }],
tones: ['default', 'direct'],
};