Reviewers were asked to include or exclude learning trajectories while only seeing metadata — credit class, confidence, status. The decisions and their redacted context turns were already captured and stored, but no endpoint returned them, so the evidence was unreachable from the UI. Add GET /api/learning/trajectories/:id and an expandable row on the learning page that fetches on demand. Also widen SentMessageSchema to accept matrixEventId, imageOutcomeCredit and imageOutcomeAt. The learning loop added these to SentMessageRecord and they flow out of /api/messages, but the strict contract rejected them, breaking the dashboard. Enable generation with shadow mode off so eligible examples reach reply prompts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import { z } from 'zod';
|
|
import { RedditAccountOwnerSchema } from './session.js';
|
|
|
|
export const SentMessageSchema = z.strictObject({
|
|
id: z.number(),
|
|
postId: z.string().nullable(),
|
|
recipient: z.string(),
|
|
subject: z.string(),
|
|
message: z.string(),
|
|
sentAt: z.number(),
|
|
gotResponse: z.boolean(),
|
|
gotImage: z.boolean(),
|
|
responseCheckedAt: z.number().nullable(),
|
|
strategyId: z.string().nullable(),
|
|
chatRoomId: z.string().nullable(),
|
|
experimentId: z.string().nullable().optional(),
|
|
promptVersion: z.string().nullable().optional(),
|
|
modelId: z.string().nullable().optional(),
|
|
selectionReason: z.enum(['explore', 'exploit']).nullable().optional(),
|
|
sourceType: z.enum(['image', 'chat']).nullable().optional(),
|
|
subreddit: z.string().optional(),
|
|
postTitle: z.string().optional(),
|
|
postUrl: z.string().optional(),
|
|
postImageUrl: z.string().optional(),
|
|
postImageAnalysis: z.string().optional(),
|
|
postCreatedAt: z.number().optional(),
|
|
owner: RedditAccountOwnerSchema.optional(),
|
|
// Attribution/learning fields added by the conversation learning loop.
|
|
matrixEventId: z.string().nullable().optional(),
|
|
imageOutcomeCredit: z.string().nullable().optional(),
|
|
imageOutcomeAt: z.number().nullable().optional(),
|
|
});
|
|
export const MessagesResponseSchema = z.array(SentMessageSchema);
|
|
|
|
export const ProcessedPostSchema = z.strictObject({
|
|
id: z.string(),
|
|
subreddit: z.string(),
|
|
author: z.string(),
|
|
title: z.string(),
|
|
postUrl: z.string().nullable().optional(),
|
|
imageUrl: z.string().nullable(),
|
|
imageAnalysis: z.string().nullable(),
|
|
generatedMessage: z.string().nullable(),
|
|
processedAt: z.number(),
|
|
messageSent: z.boolean(),
|
|
error: z.string().nullable(),
|
|
owner: RedditAccountOwnerSchema.optional(),
|
|
});
|
|
export const ProcessedPostsResponseSchema = z.array(ProcessedPostSchema);
|
|
|
|
export const SuccessfulExampleSchema = z.strictObject({
|
|
id: z.number(),
|
|
sentMessageId: z.number().nullable(),
|
|
originalMessage: z.string(),
|
|
imageAnalysis: z.string().nullable(),
|
|
postTitle: z.string().nullable(),
|
|
responseSnippet: z.string().nullable(),
|
|
subreddit: z.string().nullable(),
|
|
createdAt: z.number(),
|
|
gotImage: z.boolean().optional(),
|
|
});
|
|
export const SuccessfulExamplesResponseSchema = z.array(SuccessfulExampleSchema);
|
|
|
|
export type SentMessage = z.infer<typeof SentMessageSchema>;
|
|
export type ProcessedPost = z.infer<typeof ProcessedPostSchema>;
|
|
export type SuccessfulExample = z.infer<typeof SuccessfulExampleSchema>;
|