Files
RedditBot/packages/api-contracts/src/outreach.ts
T

113 lines
3.8 KiB
TypeScript

import { z } from 'zod';
import { RedditAccountOwnerSchema } from './session.js';
export const OutreachCandidateStatusSchema = z.enum([
'discovered',
'screening',
'ready',
'sending',
'retryable',
]);
export const OutreachStageCountsSchema = z.strictObject({
discovered: z.number().int().nonnegative(),
screening: z.number().int().nonnegative(),
ready: z.number().int().nonnegative(),
sending: z.number().int().nonnegative(),
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(),
operatorEdited: z.boolean().default(false),
});
export const OutreachCandidateSchema = z.strictObject({
postId: z.string(),
subreddit: z.string(),
author: z.string(),
title: z.string(),
postUrl: z.string(),
targetComment: z.strictObject({
body: z.string(),
permalink: z.string(),
}).nullable().default(null),
sourceType: z.enum(['image', 'chat']),
status: OutreachCandidateStatusSchema,
priority: z.number(),
postCreatedAt: z.number(),
discoveredAt: z.number(),
updatedAt: z.number(),
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(),
});
export const OutreachFunnelResponseSchema = z.strictObject({
generatedAt: z.number(),
activeCount: z.number().int().nonnegative(),
stages: OutreachStageCountsSchema,
outcomes: z.strictObject({
sent: z.number().int().nonnegative(),
rejected: z.number().int().nonnegative(),
}),
oldestActiveAt: z.number().nullable(),
candidates: z.array(OutreachCandidateSchema),
});
export const OutreachClearResponseSchema = z.strictObject({
success: z.literal(true),
cleared: z.strictObject({
discovered: z.number().int().nonnegative(),
screening: z.number().int().nonnegative(),
ready: z.number().int().nonnegative(),
retryable: z.number().int().nonnegative(),
total: z.number().int().nonnegative(),
}),
retainedSending: z.number().int().nonnegative(),
});
export const OutreachMessageUpdateRequestSchema = z.strictObject({
message: z.string().trim().min(1).max(2000),
});
export const OutreachMessageUpdateResponseSchema = z.strictObject({
success: z.literal(true),
postId: z.string(),
message: z.string(),
});
export const OutreachCandidateDeleteResponseSchema = z.strictObject({
success: z.literal(true),
postId: z.string(),
});
export type OutreachCandidateStatus = z.infer<typeof OutreachCandidateStatusSchema>;
export type OutreachCandidate = z.infer<typeof OutreachCandidateSchema>;
export type OutreachFunnelResponse = z.infer<typeof OutreachFunnelResponseSchema>;
export type OutreachClearResponse = z.infer<typeof OutreachClearResponseSchema>;
export type OutreachMessageUpdateRequest = z.infer<typeof OutreachMessageUpdateRequestSchema>;
export type OutreachMessageUpdateResponse = z.infer<typeof OutreachMessageUpdateResponseSchema>;
export type OutreachCandidateDeleteResponse = z.infer<typeof OutreachCandidateDeleteResponseSchema>;