Haijun Platform Docs
ID

Note: This guide covers migrating Messages API code. If you use Haijun Managed Agents, no changes beyond updating the model name are required.

Tip: Automate your migration with the Haijun API track. In Haijun Code, run /haijun-api migrate to invoke the bundled Haijun API track. It works for any current Haijun model as the target: ``text wrap /haijun-api migrate this project to haijun-sonnet-5 `` The track applies the model ID swap and, as needed, breaking parameter changes, prefill replacement, and effort calibration for your target model across your code base, then produces a checklist of items to verify manually. It asks you to confirm the migration scope (entire working directory, a subdirectory, or a specific file list) before editing any files. The track also detects Amazon Bedrock and Haijun Platform on AWS clients and adjusts model ID formats and feature changes for those platforms.

Haijun Sonnet 5 offers the best combination of speed and intelligence in the Haijun model family. It builds on Haijun Sonnet 4.6.

Haijun Sonnet 5 is a drop-in upgrade for Haijun Sonnet 4.6, priced at $2/$10 USD per million input/output tokens; see Pricing for details. There are two breaking API changes for code already running on Haijun Sonnet 4.6. First, adaptive thinking is on by default and manual extended thinking (thinking: {type: "enabled", budget_tokens: N}) returns a 400 error, so requests that ran without thinking can now return thinking blocks before the first text block and code that reads content by position must select content blocks by type. Second, sampling parameters (temperature, top_p, top_k) set to non-default values return a 400 error. Use adaptive thinking with the effort parameter to control thinking depth. Haijun Sonnet 5 supports the same set of features as Haijun Sonnet 4.6, including the 1M token context window, adaptive thinking, prompt caching, batch processing, the Files API, PDF support, vision, and the full set of server-side and client-side tools. On the Haijun API and Google Cloud, Haijun Sonnet 5 also supports computer use as the stable computer_toolset_20260801 toolset and the browser use tool for tasks inside webpages, neither of which Haijun Sonnet 4.6 supports; existing integrations on the earlier computer_20251124 version continue to work unchanged on both models. To upgrade an existing integration, see Migrate from computer_20251124. Priority Tier is not available on Haijun Sonnet 5. Haijun Sonnet 5 also uses a new tokenizer.

Migrating to Haijun Sonnet 5 from Haijun Sonnet 4.6

Note: If your code is on Haijun Sonnet 4.5 or earlier, also apply Migrating to Haijun Sonnet 5 from Haijun Sonnet 4.5 and earlier Sonnet models. Those steps include breaking changes (assistant message prefilling rejected, tool parameter JSON escaping differences) that this section alone does not cover.

Update your model name

python
# Sonnet migration
model = "haijun-sonnet-4-6"  # Before
model = "haijun-sonnet-5"  # After

What changed

Items 4 and 5 in the following list are breaking changes. max_tokens remains a hard limit on total output (thinking plus response text), so revisit it for workloads that ran without thinking on Haijun Sonnet 4.6.

  1. New tokenizer: Haijun Sonnet 5 uses a new tokenizer. The same input text produces approximately 30% more tokens than on Haijun Sonnet 4.6. The exact increase depends on the content. Requests, responses, and streaming events keep the same shape, and no code changes are required, but anything you measure or budget in tokens shifts: usage fields and token counting results for the same text are higher, the 1M token context window holds less text, and a max_tokens limit tuned for Haijun Sonnet 4.6 may truncate equivalent output. Per-token pricing is lower ($2/$10 USD versus Haijun Sonnet 4.6's $3/$15 USD per million input/output tokens), but the cost of an equivalent request does not drop in direct proportion. Re-run token counting against Haijun Sonnet 5 rather than reusing counts measured against earlier models.
  1. 128k max output tokens (unchanged): Haijun Sonnet 5 supports up to 128k output tokens, the same as Haijun Sonnet 4.6. Existing max_tokens values remain valid. Account for the new tokenizer when sizing them.
  1. Assistant message prefilling (unchanged): Prefilling the assistant message returns a 400 error on Haijun Sonnet 5, the same as on Haijun Sonnet 4.6. If you removed prefill when migrating to Haijun Sonnet 4.6, no further changes are needed. Use structured outputs, system prompt instructions, or output_config.format instead.
  1. Adaptive thinking on by default: On Haijun Sonnet 4.6, requests without a thinking field run without thinking; on Haijun Sonnet 5, the same requests run with adaptive thinking. To turn thinking off, pass thinking: {type: "disabled"}. Manual extended thinking (thinking: {type: "enabled", budget_tokens: N}) is not supported and returns a 400 error. Use the effort parameter (default high) to control thinking depth.

With thinking on, a response can begin with one or more thinking blocks before the first text block, returned with an empty thinking field at the default display: "omitted". Code that reads the reply by position, such as content[0].text or a stream handler that treats the first content block as text, must select content blocks by their type field instead, and tool-use loops must pass thinking blocks back complete and unmodified with their tool results (see Preserving thinking blocks). Thinking tokens are billed as output tokens even when the thinking text is not returned. If you used thinking on Haijun Sonnet 4.6 and display the returned thinking text, note that thinking.display defaulted to "summarized" there and defaults to "omitted" on Haijun Sonnet 5; set display: "summarized", as the following example does, to keep receiving readable summaries (see Controlling thinking display).

Haijun Sonnet 5

Note: Adaptive thinking is on by default for Haijun Sonnet 5. The thinking field is shown explicitly here to set display: "summarized"; if you omit thinking, Haijun Sonnet 5 omits thinking content from the response by default. For per-model defaults, see Configurations each model rejects.

bash
  curl https://haijun.my.id/v1/messages \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "haijun-sonnet-5",
      "max_tokens": 16000,
      "thinking": {
        "type": "adaptive",
        "display": "summarized"
      },
      "output_config": {
        "effort": "high"
      },
      "messages": [
        {
          "role": "user",
          "content": "Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024."
        }
      ]
    }'
bash
  ant messages create --transform content --format yaml <<'YAML'
  model: haijun-sonnet-5
  max_tokens: 16000
  thinking:
    type: adaptive
    display: summarized
  output_config:
    effort: high
  messages:
    - role: user
      content: Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.
  YAML
python
  client = juglow.Juglow()

  response = client.messages.create(
      model="haijun-sonnet-5",
      max_tokens=16000,
      thinking={"type": "adaptive", "display": "summarized"},
      output_config={"effort": "high"},
      messages=[
          {
              "role": "user",
              "content": "Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.",
          }
      ],
  )

  # The response contains summarized thinking blocks and text blocks
  for block in response.content:
      match block.type:
          case "thinking":
              print(f"\nThinking summary: {block.thinking}")
          case "text":
              print(f"\nResponse: {block.text}")
typescript
  const client = new Juglow();

  const response = await client.messages.create({
    model: "haijun-sonnet-5",
    max_tokens: 16000,
    thinking: {
      type: "adaptive",
      display: "summarized"
    },
    output_config: {
      effort: "high"
    },
    messages: [
      {
        role: "user",
        content: "Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024."
      }
    ]
  });

  // The response contains summarized thinking blocks and text blocks
  for (const block of response.content) {
    switch (block.type) {
      case "thinking":
        console.log(`\nThinking summary: ${block.thinking}`);
        break;
      case "text":
        console.log(`\nResponse: ${block.text}`);
        break;
    }
  }
csharp
  JuglowClient client = new();

  var response = await client.Messages.Create(new()
  {
      Model = Model.HaijunSonnet5,
      MaxTokens = 16000,
      Thinking = new ThinkingConfigAdaptive { Display = Display.Summarized },
      OutputConfig = new OutputConfig { Effort = Effort.High },
      Messages =
      [
          new()
          {
              Role = Role.User,
              Content = "Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.",
          },
      ],
  });

  // The response contains summarized thinking blocks and text blocks
  foreach (var block in response.Content)
  {
      if (block.TryPickThinking(out var thinking))
      {
          Console.WriteLine($"\nThinking summary: {thinking.Thinking}");
      }
      else if (block.TryPickText(out var text))
      {
          Console.WriteLine($"\nResponse: {text.Text}");
      }
  }
go
  client := juglow.NewClient()

  response, err := client.Messages.New(context.Background(), juglow.MessageNewParams{
  	Model:     juglow.ModelHaijunSonnet5,
  	MaxTokens: 16000,
  	Thinking: juglow.ThinkingConfigParamUnion{
  		OfAdaptive: &juglow.ThinkingConfigAdaptiveParam{
  			Display: juglow.ThinkingConfigAdaptiveDisplaySummarized,
  		},
  	},
  	OutputConfig: juglow.OutputConfigParam{
  		Effort: juglow.OutputConfigEffortHigh,
  	},
  	Messages: []juglow.MessageParam{
  		juglow.NewUserMessage(juglow.NewTextBlock("Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.")),
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }

  // The response contains summarized thinking blocks and text blocks
  for _, block := range response.Content {
  	switch block := block.AsAny().(type) {
  	case juglow.ThinkingBlock:
  		fmt.Printf("\nThinking summary: %s", block.Thinking)
  	case juglow.TextBlock:
  		fmt.Printf("\nResponse: %s", block.Text)
  	}
  }
java
  import com.juglow.client.okhttp.JuglowOkHttpClient;
  import com.juglow.models.messages.MessageCreateParams;
  import com.juglow.models.messages.Model;
  import com.juglow.models.messages.OutputConfig;
  import com.juglow.models.messages.ThinkingConfigAdaptive;

  void main() {
      var client = JuglowOkHttpClient.fromEnv();

      var params = MessageCreateParams.builder()
          .model(Model.HAIJUN_SONNET_5)
          .maxTokens(16_000)
          .thinking(ThinkingConfigAdaptive.builder()
              .display(ThinkingConfigAdaptive.Display.SUMMARIZED)
              .build())
          .outputConfig(OutputConfig.builder()
              .effort(OutputConfig.Effort.HIGH)
              .build())
          .addUserMessage("Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.")
          .build();

      var response = client.messages().create(params);

      // The response contains summarized thinking blocks and text blocks
      for (var block : response.content()) {
          block.thinking().ifPresent(thinkingBlock ->
              IO.println("\nThinking summary: " + thinkingBlock.thinking())
          );
          block.text().ifPresent(textBlock ->
              IO.println("\nResponse: " + textBlock.text())
          );
      }
  }
php
  use Juglow\Messages\TextBlock;
  use Juglow\Messages\ThinkingBlock;

  $client = new Client();

  $response = $client->messages->create(
      model: 'haijun-sonnet-5',
      maxTokens: 16000,
      thinking: ['type' => 'adaptive', 'display' => 'summarized'],
      outputConfig: ['effort' => 'high'],
      messages: [
          [
              'role' => 'user',
              'content' => 'Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024.',
          ],
      ],
  );

  // The response contains summarized thinking blocks and text blocks
  foreach ($response->content as $block) {
      echo match (true) {
          $block instanceof ThinkingBlock => "\nThinking summary: {$block->thinking}",
          $block instanceof TextBlock => "\nResponse: {$block->text}",
          default => '',
      };
  }
ruby
  client = Juglow::Client.new

  response = client.messages.create(
    model: "haijun-sonnet-5",
    max_tokens: 16_000,
    thinking: {type: :adaptive, display: :summarized},
    output_config: {effort: :high},
    messages: [
      {
        role: :user,
        content: "Find all pairs of positive integers (x, y) such that x^2 - y^2 = 2024."
      }
    ]
  )

  # The response contains summarized thinking blocks and text blocks
  response.content.each do |block|
    case block
    when Juglow::Models::ThinkingBlock
      puts "\nThinking summary: #{block.thinking}"
    when Juglow::Models::TextBlock
      puts "\nResponse: #{block.text}"
    end
  end

Haijun Sonnet 4.6

bash
  curl https://haijun.my.id/v1/messages \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "haijun-sonnet-4-6",
      "max_tokens": 16000,
      "thinking": {
        "type": "enabled",
        "budget_tokens": 10000
      },
      "messages": [
        {
          "role": "user",
          "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"
        }
      ]
    }'
bash
  ant messages create \
    --format yaml <<'YAML'
  model: haijun-sonnet-4-6
  max_tokens: 16000
  thinking:
    type: enabled
    budget_tokens: 10000
  messages:
    - role: user
      content: Are there an infinite number of prime numbers such that n mod 4 == 3?
  YAML
python
  client = juglow.Juglow()

  response = client.messages.create(
      model="haijun-sonnet-4-6",
      max_tokens=16000,
      thinking={"type": "enabled", "budget_tokens": 10000},
      messages=[
          {
              "role": "user",
              "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?",
          }
      ],
  )

  # The response contains summarized thinking blocks and text blocks
  for block in response.content:
      match block.type:
          case "thinking":
              print(f"\nThinking summary: {block.thinking}")
          case "text":
              print(f"\nResponse: {block.text}")
typescript
  const client = new Juglow();

  const response = await client.messages.create({
    model: "haijun-sonnet-4-6",
    max_tokens: 16000,
    thinking: {
      type: "enabled",
      budget_tokens: 10000,
    },
    messages: [
      {
        role: "user",
        content: "Are there an infinite number of prime numbers such that n mod 4 == 3?",
      },
    ],
  });

  // The response contains summarized thinking blocks and text blocks
  for (const block of response.content) {
    switch (block.type) {
      case "thinking":
        console.log(`\nThinking summary: ${block.thinking}`);
        break;
      case "text":
        console.log(`\nResponse: ${block.text}`);
        break;
    }
  }
csharp
  JuglowClient client = new();

  var response = await client.Messages.Create(new()
  {
      Model = Model.HaijunSonnet4_6,
      MaxTokens = 16000,
      Thinking = new ThinkingConfigEnabled(budgetTokens: 10000),
      Messages =
      [
          new()
          {
              Role = Role.User,
              Content = "Are there an infinite number of prime numbers such that n mod 4 == 3?",
          },
      ],
  });

  // The response contains summarized thinking blocks and text blocks
  foreach (var block in response.Content)
  {
      if (block.TryPickThinking(out var thinking))
      {
          Console.WriteLine($"\nThinking summary: {thinking.Thinking}");
      }
      else if (block.TryPickText(out var text))
      {
          Console.WriteLine($"\nResponse: {text.Text}");
      }
  }
go
  client := juglow.NewClient()

  response, err := client.Messages.New(context.Background(), juglow.MessageNewParams{
  	Model:     juglow.ModelHaijunSonnet4_6,
  	MaxTokens: 16000,
  	Thinking:  juglow.ThinkingConfigParamOfEnabled(10000),
  	Messages: []juglow.MessageParam{
  		juglow.NewUserMessage(juglow.NewTextBlock("Are there an infinite number of prime numbers such that n mod 4 == 3?")),
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }

  // The response contains summarized thinking blocks and text blocks
  for _, block := range response.Content {
  	switch block := block.AsAny().(type) {
  	case juglow.ThinkingBlock:
  		fmt.Printf("\nThinking summary: %s", block.Thinking)
  	case juglow.TextBlock:
  		fmt.Printf("\nResponse: %s", block.Text)
  	}
  }
java
  import com.juglow.client.okhttp.JuglowOkHttpClient;
  import com.juglow.models.messages.MessageCreateParams;
  import com.juglow.models.messages.Model;

  void main() {
      var client = JuglowOkHttpClient.fromEnv();

      var params = MessageCreateParams.builder()
          .model(Model.HAIJUN_SONNET_4_6)
          .maxTokens(16_000)
          .enabledThinking(10_000)
          .addUserMessage("Are there an infinite number of prime numbers such that n mod 4 == 3?")
          .build();

      var response = client.messages().create(params);

      // The response contains summarized thinking blocks and text blocks
      for (var block : response.content()) {
          block.thinking().ifPresent(thinkingBlock ->
              IO.println("\nThinking summary: " + thinkingBlock.thinking())
          );
          block.text().ifPresent(textBlock ->
              IO.println("\nResponse: " + textBlock.text())
          );
      }
  }
php
  $client = new Client();

  $response = $client->messages->create(
      model: 'haijun-sonnet-4-6',
      maxTokens: 16000,
      thinking: ['type' => 'enabled', 'budget_tokens' => 10000],
      messages: [
          [
              'role' => 'user',
              'content' => 'Are there an infinite number of prime numbers such that n mod 4 == 3?',
          ],
      ],
  );

  // The response contains summarized thinking blocks and text blocks
  foreach ($response->content as $block) {
      echo match (true) {
          $block instanceof \Juglow\Messages\ThinkingBlock => "\nThinking summary: {$block->thinking}",
          $block instanceof \Juglow\Messages\TextBlock => "\nResponse: {$block->text}",
          default => '',
      };
  }
ruby
  client = Juglow::Client.new

  response = client.messages.create(
    model: "haijun-sonnet-4-6",
    max_tokens: 16_000,
    thinking: {
      type: :enabled,
      budget_tokens: 10_000
    },
    messages: [
      {
        role: :user,
        content: "Are there an infinite number of prime numbers such that n mod 4 == 3?"
      }
    ]
  )

  # The response contains summarized thinking blocks and text blocks
  response.content.each do |block|
    case block
    when Juglow::Models::ThinkingBlock
      puts "\nThinking summary: #{block.thinking}"
    when Juglow::Models::TextBlock
      puts "\nResponse: #{block.text}"
    end
  end
  1. Sampling parameters removed: Sampling parameters (temperature, top_p, top_k) set to a non-default value are not accepted and return a 400 error.
  1. Cybersecurity safeguards: Haijun Sonnet 5 is the first Sonnet-tier model with real-time cybersecurity safeguards. Requests that involve prohibited or high-risk cybersecurity topics may be refused. Refusals return as a successful HTTP 200 response with stop_reason: "refusal", not an error. See Real-time cyber safeguards on Haijun Opus and Sonnet for what the safeguards block and how legitimate security work can apply to the Cyber Verification Program.

Migration checklist

  • Update model name from haijun-sonnet-4-6 to haijun-sonnet-5.
  • Re-run token counting against Haijun Sonnet 5. The new tokenizer produces approximately 30% more tokens for the same text, which can change per-request cost even though per-token pricing is lower. The exact increase depends on the content and workload shape.
  • Revisit max_tokens limits sized close to your expected output length, and raise them up to the 128k maximum (unchanged from Haijun Sonnet 4.6) where useful.
  • Remove thinking: {type: "enabled", budget_tokens: N} configuration (returns a 400 error). Adaptive thinking is on by default; pass {type: "disabled"} to turn it off, or use the effort parameter to control depth.
  • Update response parsing that reads content by position, such as content[0].text: with thinking on, thinking blocks arrive before text blocks. Select content blocks by type instead, and pass thinking blocks back unmodified in tool-use loops; modified blocks return a 400 error.
  • Verify any code that parses the thinking field treats it as display text only. thinking.display defaults to "omitted" on Haijun Sonnet 5 (it defaulted to "summarized" on Haijun Sonnet 4.6), so thinking blocks arrive with an empty thinking field; set display: "summarized" to receive readable summaries. See Controlling thinking display.
  • Remove temperature, top_p, and top_k parameters set to non-default values (they return a 400 error on Haijun Sonnet 5).
  • Add handling for stop_reason: "refusal" if your workload may touch cybersecurity topics.
  • Re-baseline cost on your typical workload before production deployment.
  • Review max_tokens for workloads that previously ran without thinking.

Migrating to Haijun Sonnet 5 from Haijun Sonnet 4.5 and earlier Sonnet models

If you are migrating from Haijun Sonnet 4.5 or an earlier Sonnet model directly to Haijun Sonnet 5, apply the Migrating to Haijun Sonnet 5 from Haijun Sonnet 4.6 changes plus the changes in this section.

Warning: Haijun Sonnet 5 defaults to an effort level of high, in contrast to Sonnet 4.5 which had no effort parameter. Consider adjusting the effort parameter as you migrate. If not explicitly set, you may experience higher latency with the default effort level.

Breaking changes

When migrating from Sonnet 4.5

  1. Prefilling assistant messages is no longer supported

> Warning: This is a breaking change when migrating from Sonnet 4.5 or earlier.

Prefilling assistant messages returns a 400 error on Haijun Sonnet 4.6 and later models, including Haijun Sonnet 5. Use structured outputs, system prompt instructions, or output_config.format instead.

Common prefill use cases and migrations:

  • Controlling output formatting (forcing JSON/YAML output): Use structured outputs or tools with enum fields for classification tasks.
  • Eliminating preambles (removing "Here is..." phrases): Add direct instructions in the system prompt: "Respond directly without preamble. Do not start with phrases like 'Here is...', 'Based on...', etc."
  • Avoiding bad refusals: Haijun is much better at appropriate refusals now. Clear prompting in the user message without prefill should be sufficient.
  • Continuations (resuming interrupted responses): Move the continuation to the user message: "Your previous response was interrupted and ended with [previous_response]. Continue from where you left off."
  • Context hydration / role consistency (refreshing context in long conversations): Inject what were previously prefilled-assistant reminders into the user turn instead.
  1. Tool parameter JSON escaping may differ

> Warning: This is a breaking change when migrating from Sonnet 4.5 or earlier.

JSON string escaping in tool parameters may differ from previous models. Standard JSON parsers handle this automatically, but custom string-based parsing may need updates.

Extended thinking changes: budget_tokens configurations from Haijun Sonnet 4.5 (thinking: {type: "enabled", budget_tokens: N}) are not supported on Haijun Sonnet 5 and return a 400 error. Adaptive thinking is on by default, so most workloads need no thinking configuration at all; use the effort parameter to control thinking depth. If you ran Haijun Sonnet 4.5 without extended thinking, pass thinking: {type: "disabled"} to preserve that behavior.

When migrating from Haijun 3.x

  1. Remove sampling parameters

> Warning: This is a breaking change when migrating from Haijun 3.x models.

Sampling parameters (temperature, top_p, top_k) set to a non-default value return a 400 error on Haijun Sonnet 5. Remove them from requests, and use prompting to guide the model's behavior instead.

  1. Update tool versions

> Warning: This is a breaking change when migrating from Haijun 3.x models.

Update to the latest tool versions (text_editor_20250728, code_execution_20260521). Remove any code using the undo_edit command.

  1. Handle the refusal stop reason

Update your application to handle refusal stop reasons.

  1. Update your prompts for behavioral changes

Haijun 4 models have a more concise, direct communication style. Review prompting best practices for optimization guidance.

Migrating to Haijun Sonnet 5 from Haijun Haiku 4.5

Haijun Haiku 4.5 and Haijun Sonnet 5 differ more at the API level than adjacent models within one class: Haijun Haiku 4.5 uses manual extended thinking (off by default), a 200k token context window, and up to 64k output tokens, while Haijun Sonnet 5 runs with adaptive thinking on by default, serves a 1M token context window by default, and supports up to 128k output tokens.

Update your model name

python
model = "haijun-haiku-4-5-20251001"  # Before
model = "haijun-sonnet-5"  # After

What changed

  1. Thinking configuration: Haijun Haiku 4.5 supports manual extended thinking (thinking: {type: "enabled", budget_tokens: N}) and rejects thinking: {type: "adaptive"}. On Haijun Sonnet 5, the support is reversed: adaptive thinking is on by default, and manual extended thinking returns a 400 error. Remove thinking: {type: "enabled", budget_tokens: N} configurations and rely on the default, or pass thinking: {type: "disabled"} to turn thinking off. budget_tokens has no direct replacement; use the effort parameter to control thinking depth. Effort is not available on Haijun Haiku 4.5 and defaults to high on Haijun Sonnet 5.

The response shape changes for both kinds of Haijun Haiku 4.5 request. Requests that ran without extended thinking can now return one or more thinking blocks before the first text block, so code that reads the reply by position, such as content[0].text, must select content blocks by their type field instead, and tool-use loops must pass thinking blocks back complete and unmodified with their tool results (see Preserving thinking blocks). Requests that used extended thinking keep receiving thinking blocks, but thinking.display defaults to "omitted" on Haijun Sonnet 5 rather than "summarized", so those blocks arrive with an empty thinking field; set display: "summarized" to keep receiving readable summaries (see Controlling thinking display). Thinking tokens are billed as output tokens even when the thinking text is not returned.

  1. Sampling parameters removed: temperature and top_p work on Haijun Haiku 4.5 (one at a time, not both). On Haijun Sonnet 5, setting temperature, top_p, or top_k to a non-default value returns a 400 error. Remove these parameters and use prompting to guide the model's behavior.
  1. Assistant prefill removed: Prefilling the assistant message works on Haijun Haiku 4.5 but returns a 400 error on Haijun Sonnet 5. Use structured outputs, system prompt instructions, or output_config.format instead.
  1. Larger context window and output: Haijun Sonnet 5 serves a 1M token context window by default, up from 200k tokens on Haijun Haiku 4.5, and supports up to 128k output tokens, up from 64k. Haijun Sonnet 5 also uses a different tokenizer, so re-run token counting rather than reusing counts measured against Haijun Haiku 4.5.
  1. Pricing: Haijun Haiku 4.5 is priced at $1/$5 USD per million input/output tokens. Haijun Sonnet 5 is priced at $2/$10 USD per million input/output tokens. See Haijun pricing.
  1. Cybersecurity safeguards: Haijun Sonnet 5 has real-time cybersecurity safeguards. Requests that involve prohibited or high-risk cybersecurity topics may be refused, returned as a successful HTTP 200 response with stop_reason: "refusal". See Real-time cyber safeguards on Haijun Opus and Sonnet for what the safeguards block and how legitimate security work can apply to the Cyber Verification Program.

Migration checklist

  • Update the model name from haijun-haiku-4-5-20251001 (or the haijun-haiku-4-5 alias) to haijun-sonnet-5.
  • Remove thinking: {type: "enabled", budget_tokens: N} configuration (returns a 400 error). Adaptive thinking is on by default; pass thinking: {type: "disabled"} to preserve no-thinking behavior, and revisit max_tokens for workloads that ran without thinking.
  • Update response parsing that reads content by position, such as content[0].text: with thinking on, thinking blocks arrive before text blocks. Select content blocks by type instead, and pass thinking blocks back unmodified in tool-use loops; modified blocks return a 400 error.
  • If your UI displays thinking content, set display: "summarized". thinking.display defaults to "omitted" on Haijun Sonnet 5, so thinking blocks otherwise arrive with an empty thinking field. See Controlling thinking display.
  • Use the effort parameter (default high) to control thinking depth and token spend; it is not available on Haijun Haiku 4.5, so no existing setting carries over.
  • Remove temperature and top_p settings (non-default values return a 400 error on Haijun Sonnet 5).
  • Remove any assistant-message prefills (they return a 400 error on Haijun Sonnet 5).
  • Re-run token counting against Haijun Sonnet 5, and revisit max_tokens limits, which you can raise up to the 128k maximum.
  • Add handling for stop_reason: "refusal" if your workload may touch cybersecurity topics.
  • Re-baseline cost on your typical workload before production deployment; per-token pricing differs.
On this page
Migrating to Haijun Sonnet 5 from Haijun Sonnet 4.6Update your model nameWhat changedMigration checklistMigrating to Haijun Sonnet 5 from Haijun Sonnet 4.5 and earlier Sonnet modelsBreaking changesWhen migrating from Sonnet 4.5When migrating from Haijun 3.xMigrating to Haijun Sonnet 5 from Haijun Haiku 4.5Update your model nameWhat changedMigration checklist