> ## 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.

# Stop conditions

Stop conditions control when agent execution terminates. Use them to prevent runaway agents, control costs, or stop after specific criteria are met.

## What are stop conditions?

Stop conditions are functions that run after each agent step and return `True` to stop execution or `False` to continue. They're essential for:

* **Cost control** - Limit token usage
* **Preventing infinite loops** - Cap the number of reasoning steps
* **Goal-based termination** - Stop after specific tools are called or text is generated
* **Safety** - Halt execution when thresholds are exceeded

They run after the LLM step and tool execution.

## Built-in stop conditions

* **Max tokens**: Stop when total token usage exceeds a limit.
* **Max steps**: Stop when the number of reasoning steps reaches a threshold. Here, an LLM call along with any tool executions suggested by the LLM is considered a single step.
* **Executed tool**: Stop when specific tools have been called.
* **Has text**: Stop when specific text appears in the response.

<CodeGroup>
  ```python Python theme={null}
  from polos import (
      Agent,
      max_tokens,
      MaxTokensConfig,
      max_steps,
      MaxStepsConfig,
      executed_tool,
      ExecutedToolConfig,
      PolosClient
  )

  research_agent = Agent(
      id="research-agent",
      provider="openai",
      model="gpt-4o",
      system_prompt="Research the topic thoroughly.",
      tools=[search_web, read_article],
      stop_conditions=[
          max_tokens(MaxTokensConfig(limit=10000)),  # Stop at 10k tokens
          max_steps(MaxStepsConfig(count=5)),  # Stop after 5 steps
          executed_tool(ExecutedToolConfig(    # Stop after both get_weather and search_news are executed
              tool_names=["get_weather", "search_news"]
          )),
          has_text(HasTextConfig(texts=["DONE"])) # Stop when the LLM response contains DONE
      ]
  )

  client = PolosClient()
  response = await research_agent.run(
      client,
      "Research AI agents and write a comprehensive report"
  )
  ```

  ```typescript TypeScript theme={null}
  import { defineAgent, maxTokens, maxSteps, executedTool, hasText } from '@polos/sdk';
  import { openai } from '@polos/sdk/models';

  const researchAgent = defineAgent({
    id: 'research-agent',
    model: openai('gpt-4o'),
    systemPrompt: 'Research the topic thoroughly.',
    tools: [searchWeb, readArticle],
    stopConditions: [
      maxTokens({ limit: 10000 }),  // Stop at 10k tokens
      maxSteps({ count: 5 }),  // Stop after 5 steps
      executedTool({    // Stop after both getWeather and searchNews are executed
        toolNames: ['get_weather', 'search_news'],
      }),
      hasText({ texts: ['DONE'] }),  // Stop when the LLM response contains DONE
    ],
  });

  const response = await researchAgent.run(
    'Research AI agents and write a comprehensive report'
  );
  ```
</CodeGroup>

Agent stops when **any of the stop conditions** are met.

**Execution order:** Stop conditions are run in the order in which they are specified after each step. First condition that returns True stops the agent.

## Custom stop conditions

Define your own stop conditions for specific use cases:

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

  class MaxInputTokensConfig(BaseModel):
      """Configuration for max_input_tokens stop condition."""
      limit: int

  @stop_condition
  async def max_input_tokens(
      ctx: StopConditionContext,
      config: MaxInputTokensConfig
  ) -> bool:
      """Stop when input tokens exceed limit."""
      input_tokens = 0
      for step in ctx.steps:
          if step.usage:
              input_tokens += step.usage.input_tokens

      return input_tokens >= config.limit

  # Use the custom stop condition
  context_aware_agent = Agent(
      id="context-agent",
      provider="openai",
      model="gpt-4o",
      tools=[search, analyze],
      stop_conditions=[
          max_input_tokens(MaxInputTokensConfig(limit=5000))
      ]
  )
  ```

  ```typescript TypeScript theme={null}
  import { defineAgent, defineStopCondition } from '@polos/sdk';
  import { openai } from '@polos/sdk/models';

  interface MaxInputTokensConfig {
    limit: number;
  }

  const maxInputTokens = defineStopCondition(
    async (ctx, config: MaxInputTokensConfig) => {
      let inputTokens = 0;
      for (const step of ctx.steps) {
        if (step.usage) {
          inputTokens += step.usage.inputTokens;
        }
      }
      return inputTokens >= config.limit;
    },
    { name: 'maxInputTokens' }
  );

  // Use the custom stop condition
  const contextAwareAgent = defineAgent({
    id: 'context-agent',
    model: openai('gpt-4o'),
    tools: [search, analyze],
    stopConditions: [
      maxInputTokens({ limit: 5000 }),
    ],
  });
  ```
</CodeGroup>

## Stop condition context

Stop conditions receive a `StopConditionContext` with execution history:

<CodeGroup>
  ```python Python theme={null}
  @stop_condition
  async def custom_condition(
      ctx: StopConditionContext,
      config: YourConfig
  ) -> bool:
      # Access all steps executed so far
      for step in ctx.steps:
          # Check content
          content = step.content

          # Check token usage
          if step.usage:
              tokens = step.usage.total_tokens
              input_tokens = step.usage.input_tokens
              output_tokens = step.usage.output_tokens

          # Check tool calls
          for tool_call in step.tool_calls:
              tool_name = tool_call.function.name
              tool_args = tool_call.function.arguments

      # Return True to stop, False to continue
      return some_condition
  ```

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

  interface YourConfig {
    // your config fields
  }

  const customCondition = defineStopCondition(
    async (ctx, config: YourConfig) => {
      // Access all steps executed so far
      for (const step of ctx.steps) {
        // Check content
        const content = step.content;

        // Check token usage
        if (step.usage) {
          const tokens = step.usage.totalTokens;
          const inputTokens = step.usage.inputTokens;
          const outputTokens = step.usage.outputTokens;
        }

        // Check tool calls
        for (const toolCall of step.toolCalls) {
          const toolName = toolCall.function.name;
          const toolArgs = toolCall.function.arguments;
        }
      }

      // Return true to stop, false to continue
      return someCondition;
    },
    { name: 'customCondition' }
  );
  ```
</CodeGroup>

## Key takeaways

* **Stop conditions terminate agent execution** when criteria are met. Useful for cost control and safety.
* **Built-in conditions:** `max_tokens`, `max_steps`, `executed_tool`, `has_text`
* **Custom conditions** defined with `@stop_condition` decorator
* **Multiple conditions** - agent stops when any returns `True`
* **Access full execution history** via `StopConditionContext`
