Private BetaProposeFlow is currently in private beta.Join the waitlist

Decisions

Decisions capture user judgment on proposals. Users approve when satisfied, or reject with feedback to trigger regeneration. This iterative loop continues until the output meets their needs.

Making a Decision

Call decide() to record the user's decision on a proposal.

decide.ts
// Approve a proposal
const decision = await pf.proposals.decide(proposalId, {
  action: 'approve',
});

// Reject a proposal with a reason
const decision = await pf.proposals.decide(proposalId, {
  action: 'reject',
  reason: 'Content does not match brand voice',
});

Approve with Modifications

Sometimes users want to make small edits before approving. You can pass modified data with the approval.

modify.ts
// Get the proposal
const proposal = await pf.proposals.get(proposalId);

// Let user edit the data
const edits = {
  title: 'Updated Title by User',  // User's modification
};

// Approve with modifications
const decision = await pf.proposals.decide(proposalId, {
  action: 'approve',
  edits,  // Partial edits to apply
});

// decision.finalObject contains the merged result

Note: Modified data is validated against the original schema before being accepted. Invalid modifications will throw an error.

Decision Result

The decide() method returns the updated proposal with its final state.

result.ts
const decision = await pf.proposals.decide(proposalId, {
  action: 'approve',
});

// Decision contains the result
console.log(decision.id);          // Decision ID
console.log(decision.action);      // 'approve'
console.log(decision.finalObject); // The final data with edits applied
console.log(decision.createdAt);   // Timestamp of the decision

Iterative Refinement

The core workflow in ProposeFlow is iterative: users review AI output and provide feedback until they're satisfied. When a user rejects a proposal, you call regenerate() with their feedback to create a new, improved proposal.

retry.ts
async function handleReviewFlow(input: string) {
  let currentProposalId: string | null = null;

  for (let attempt = 0; attempt < 3; attempt++) {
    // Generate or regenerate
    const { proposal } = currentProposalId
      ? await pf.proposals.regenerate(currentProposalId, { feedback: input })
      : await pf.generate('blogPost', { input });

    currentProposalId = proposal.id;

    // Present to user and get decision
    const userDecision = await presentToUser(proposal);

    if (userDecision.approved) {
      return await pf.proposals.decide(proposal.id, {
        action: 'approve',
        edits: userDecision.edits,
      });
    }

    // Use rejection reason as feedback for regeneration
    input = userDecision.reason;
  }

  throw new Error('Max attempts reached');
}

Webhooks

Configure webhooks to receive real-time notifications when decisions are made. This is useful for triggering downstream workflows.

Learn more about setting up webhooks in the Webhooks guide.