Skip to content
Merged
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
46 changes: 26 additions & 20 deletions apps/app/src/jobs/tasks/onboarding/update-policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai';
import { db } from '@db';
import type { JSONContent } from '@tiptap/react';
import { logger, schemaTask } from '@trigger.dev/sdk/v3';
import { generateObject, generateText, NoObjectGeneratedError } from 'ai';
import { generateObject, NoObjectGeneratedError } from 'ai';
import { z } from 'zod';
import { generatePrompt } from '../../lib/prompts';

Expand Down Expand Up @@ -51,26 +51,32 @@ export const updatePolicies = schemaTask({
});

try {
const { text } = await generateText({
model: openai('o4-mini'),
system: 'You are an expert at writing security policies in TipTap JSON.',
prompt: `Update the following policy to be strictly aligned with SOC 2 standards and controls. Only include JSON content as your output.
// Generate TipTap JSON directly in one step to avoid malformed JSON issues
const { object } = await generateObject({
model: openai('gpt-4o-mini'),
mode: 'json',
system: `You are an expert at writing security policies. Generate content directly as TipTap JSON format.

${prompt.replace(/\\n/g, '\n')}`,
});
TipTap JSON structure:
- Root: {"type": "document", "content": [array of nodes]}
- Paragraphs: {"type": "paragraph", "content": [text nodes]}
- Headings: {"type": "heading", "attrs": {"level": 1-6}, "content": [text nodes]}
- Lists: {"type": "orderedList"/"bulletList", "content": [listItem nodes]}
- List items: {"type": "listItem", "content": [paragraph nodes]}
- Text: {"type": "text", "text": "content", "marks": [formatting]}
- Bold: {"type": "bold"} in marks array
- Italic: {"type": "italic"} in marks array

if (!text) {
logger.error(`Failed generating policy for ${policyId}`);
return;
}
IMPORTANT: Follow ALL formatting instructions in the prompt, implementing them as proper TipTap JSON structures.`,
prompt: `Generate a SOC 2 compliant security policy as a complete TipTap JSON document.

const { object } = await generateObject({
model: openai('gpt-4.1-mini'),
mode: 'json',
system: 'You are an expert at writing security policies in TipTap JSON.',
prompt: `Convert the following text into TipTap JSON. Do not include any other text in your output: ${JSON.stringify(text)}`,
INSTRUCTIONS TO IMPLEMENT IN TIPTAP JSON:
${prompt.replace(/\\n/g, '\n')}

Return the complete TipTap document following ALL the above requirements using proper TipTap JSON structure.`,
schema: z.object({
json: z.array(z.any()),
type: z.literal('document'),
content: z.array(z.record(z.unknown())),
}),
});

Expand All @@ -80,15 +86,15 @@ export const updatePolicies = schemaTask({
id: policyId,
},
data: {
content: object.json as JSONContent[],
content: object.content as JSONContent[],
},
});

return {
policyId,
contextHub,
policy,
updatedContent: text,
updatedContent: object,
};
} catch (dbError) {
logger.error(`Failed to update policy in database: ${dbError}`);
Expand All @@ -110,7 +116,7 @@ export const updatePolicies = schemaTask({
throw aiError;
}
} catch (error) {
logger.error(`Unexpected error in populatePolicyWithAI: ${error}`);
logger.error(`Unexpected error in updatePolicies: ${error}`);
throw error;
}
},
Expand Down
Loading