> ## Documentation Index
> Fetch the complete documentation index at: https://polos.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Order Processing

> Order processing agent with structured output and fraud review

A complete order processing workflow combining structured output, conditional logic, and human-in-the-loop approval.

## Define structured output schema

<CodeGroup>
  ```python Python theme={null}
  from pydantic import BaseModel, Field

  class ActionDetails(BaseModel):
      charge_id: str | None = None
      amount: float | None = None
      email_sent_to: str | None = None

  class OrderAgentOutput(BaseModel):
      action: str = Field(description="Action taken: 'charge' or 'email'")
      action_details: ActionDetails
      action_requested: str | None = Field(
          default=None,
          description="'fraud_review' for amounts over $1000, or None"
      )
      status_message: str
  ```

  ```typescript TypeScript theme={null}
  import { z } from 'zod';

  const actionDetailsSchema = z.object({
    charge_id: z.string().nullable().default(null),
    amount: z.number().nullable().default(null),
    email_sent_to: z.string().nullable().default(null),
    message_id: z.string().nullable().default(null),
  });

  const orderAgentOutputSchema = z.object({
    action: z.string().describe("Action taken: 'charge', 'email', or 'complete'"),
    action_details: actionDetailsSchema,
    action_requested: z.string().nullable().default(null).describe(
      "'fraud_review' for amounts over $1000, or null",
    ),
    status_message: z.string(),
  });

  type OrderAgentOutput = z.infer<typeof orderAgentOutputSchema>;
  ```
</CodeGroup>

## Create the order agent

<CodeGroup>
  ```python Python theme={null}
  from polos import Agent, tool, WorkflowContext

  @tool(description="Charge a customer using Stripe")
  async def charge_stripe(ctx: WorkflowContext, input: ChargeInput) -> ChargeOutput:
      # Process payment
      return ChargeOutput(charge_id="ch_123", status="succeeded", amount=input.amount)

  @tool(description="Send order confirmation email")
  async def send_confirmation_email(ctx: WorkflowContext, input: EmailInput) -> EmailOutput:
      return EmailOutput(sent=True, message_id="msg_123")

  order_agent = Agent(
      id="order_agent",
      provider="openai",
      model="gpt-4o-mini",
      system_prompt="""You are an order processing assistant.

  RULES:
  1. When asked to process a payment, use charge_stripe first
  2. After charging:
     - If amount > $1000: Set action_requested='fraud_review' (DO NOT send email)
     - If amount <= $1000: Immediately send confirmation email
  3. After fraud approval: Send the confirmation email""",
      tools=[charge_stripe, send_confirmation_email],
      output_schema=OrderAgentOutput,
  )
  ```

  ```typescript TypeScript theme={null}
  import { defineAgent, maxSteps } from '@polos/sdk';
  import { openai } from '@ai-sdk/openai';
  import { chargeStripe, sendConfirmationEmail } from './tools.js';

  const orderAgent = defineAgent({
    id: 'order_agent',
    model: openai('gpt-4o-mini'),
    systemPrompt: `You are an order processing assistant.

  RULES:
  1. When asked to process a payment, use charge_stripe first
  2. After charging:
     - If amount > $1000: Set action_requested='fraud_review' (DO NOT send email)
     - If amount <= $1000: Immediately send confirmation email
  3. After fraud approval: Send the confirmation email`,
    tools: [chargeStripe, sendConfirmationEmail],
    outputSchema: orderAgentOutputSchema,
    stopConditions: [maxSteps({ count: 10 })],
  });
  ```
</CodeGroup>

## Build the workflow

<CodeGroup>
  ```python Python theme={null}
  from polos import workflow, WorkflowContext

  @workflow(id="order_processing")
  async def order_processing(ctx: WorkflowContext, payload: OrderPayload) -> OrderResult:
      # Step 1: Process payment
      result = await ctx.step.agent_invoke_and_wait(
          "start_order",
          order_agent.with_input(
              f"Process payment for order {payload.order_id}. "
              f"Charge customer {payload.customer_id} for ${payload.amount:.2f}."
          )
      )

      output: OrderAgentOutput = result.result
      charge_id = output.action_details.charge_id

      # Step 2: Check if fraud review is requested
      if output.action_requested == "fraud_review":
          # Suspend for human review (up to 24 hours)
          resume_data = await ctx.step.suspend(
              "fraud_review",
              data={
                  "order_id": payload.order_id,
                  "amount": payload.amount,
                  "charge_id": charge_id,
                  "message": "Please review this order for fraud",
              },
              timeout=86400,
          )

          if not resume_data.get("data", {}).get("approved", False):
              return OrderResult(status="rejected", charge_id=charge_id)

          # Fraud approved - send confirmation
          await ctx.step.agent_invoke_and_wait(
              "send_confirmation",
              order_agent.with_input(
                  f"Fraud review APPROVED for order {payload.order_id}. "
                  f"Send confirmation email to {payload.customer_email}."
              )
          )

          return OrderResult(
              status="completed",
              charge_id=charge_id,
              fraud_review_required=True,
              fraud_approved=True,
          )

      # No fraud review needed - agent already sent confirmation
      return OrderResult(status="completed", charge_id=charge_id)
  ```

  ```typescript TypeScript theme={null}
  import { defineWorkflow } from '@polos/sdk';

  const orderProcessingWorkflow = defineWorkflow<OrderPayload, unknown, OrderResult>(
    { id: 'order_processing_workflow' },
    async (ctx, payload) => {
      // Step 1: Process payment
      const result = (await ctx.step.agentInvokeAndWait(
        'start_order',
        orderAgent.withInput(
          `Process payment for order ${payload.orderId}. ` +
          `Charge customer ${payload.customerId} for $${payload.amount.toFixed(2)} USD.`,
        ),
      )) as Record<string, unknown>;

      const output = result['result'] as OrderAgentOutput;
      const chargeId = output.action_details.charge_id;

      // Step 2: Check if fraud review is requested
      if (output.action_requested === 'fraud_review') {
        // Suspend for human review (up to 24 hours)
        const resumeData = await ctx.step.suspend<Record<string, unknown>, Record<string, unknown>>(
          'fraud_review',
          {
            data: {
              order_id: payload.orderId,
              amount: payload.amount,
              charge_id: chargeId,
              message: 'Please review this order for fraud',
            },
            timeout: 86400,
          },
        );

        const fraudApproved = Boolean(
          (resumeData?.['data'] as Record<string, unknown> | undefined)?.['approved'] ?? false,
        );

        if (!fraudApproved) {
          return { orderId: payload.orderId, status: 'rejected', chargeId, fraudReviewRequired: true, fraudApproved: false, emailSent: false };
        }

        // Fraud approved - send confirmation
        await ctx.step.agentInvokeAndWait(
          'send_confirmation',
          orderAgent.withInput(
            `Fraud review APPROVED for order ${payload.orderId}. ` +
            `Send confirmation email to ${payload.customerEmail}.`,
          ),
        );

        return { orderId: payload.orderId, status: 'completed', chargeId, fraudReviewRequired: true, fraudApproved: true, emailSent: true };
      }

      // No fraud review needed - agent already sent confirmation
      return { orderId: payload.orderId, status: 'completed', chargeId, fraudReviewRequired: false, fraudApproved: null, emailSent: true };
    },
  );
  ```
</CodeGroup>

## Flow summary

**Amount \$1000 or less:**

1. Agent charges customer via Stripe
2. Agent immediately sends confirmation email
3. Workflow completes

**Amount over \$1000:**

1. Agent charges customer via Stripe
2. Agent returns `action_requested: "fraud_review"`
3. Workflow suspends for human review
4. If approved: Agent sends confirmation email
5. If rejected: Order cancelled

## Run it

<CodeGroup>
  ```bash Python theme={null}
  git clone https://github.com/polos-dev/polos.git
  cd polos/python-examples/17-order-processing
  cp .env.example .env  # Add your POLOS_PROJECT_ID and API key
  uv sync
  python main.py
  ```

  ```bash TypeScript theme={null}
  git clone https://github.com/polos-dev/polos.git
  cd polos/typescript-examples/17-order-processing
  cp .env.example .env  # Add your POLOS_PROJECT_ID and API key
  npm install
  npx tsx main.ts
  ```
</CodeGroup>

Open [http://localhost:5173](http://localhost:5173) to view your agents and workflows, run them from the UI, and see execution traces.

[Python example on GitHub](https://github.com/polos-dev/polos/tree/main/python-examples/17-order-processing) | [TypeScript example on GitHub](https://github.com/polos-dev/polos/tree/main/typescript-examples/17-order-processing)
