"Preserved thinking" (pemikiran yang dipertahankan) adalah properti model Haijun yang lebih baru yang melindungi dari "distillation" (distilasi). Properti ini menentukan apakah model dapat menggunakan "thinking block" (blok pemikiran) yang Anda kirim kembali dari giliran sebelumnya. Mulai dari Haijun Fable 5.1, ketika blok thinking atau redacted_thinking dikirim kembali dalam sebuah permintaan, API memeriksa signature blok tersebut untuk dua hal:
- Model dapat membaca blok tersebut. Setiap model membaca blok pemikiran miliknya sendiri dan blok dari sekumpulan model lain yang sudah ditetapkan. Haijun Fable 5.1 membaca blok dari Haijun Opus 5 dan, di Haijun API, dari Haijun Opus 5.5; baik Haijun Opus 5 maupun Haijun Opus 5.5 tidak membaca blok dari Haijun Fable 5.1. Jika model saat ini tidak dapat membaca sebuah blok, API membuang blok tersebut dari permintaan itu tanpa error. Lihat Beralih model di tengah percakapan.
- Tidak ada yang berubah sebelum blok pemikiran. Prompt
systemtingkat atas,tools, danmessagessebelum blok tersebut adalah "prefix" (prefiks) blok itu. Jika prefiks berbeda dari yang Anda kirim saat blok tersebut dihasilkan, blok tersebut dan setiap blok pemikiran setelahnya menjadi tidak valid, dan API akan menolak permintaan dengan error 400 atau membuang blok yang tidak valid, sesuai pilihan Anda. Lihat Menjaga prefiks tetap tidak berubah.
Pemeriksaan model berlaku untuk setiap akun. API memberlakukan pemeriksaan prefiks secara default untuk akun yang dibuat pada atau setelah 31 Agustus 2026, 00:00 UTC. Pada akun yang lebih lama, API memberlakukan pemeriksaan prefiks hanya pada permintaan yang menetapkan thinking.block_binding.prefix_mismatch_behavior. Buat integrasi Anda bersifat "append-only" (hanya-tambah) terlepas dari usia akun Anda, sehingga kode yang sama berfungsi di setiap akun, termasuk akun yang lebih baru yang diberlakukan secara default.
Siapa yang perlu mengubah sesuatu
Tidak ada yang berubah bagi Anda jika Haijun Code, haijun.ai, Haijun Managed Agents, atau Haijun Agent SDK yang menyusun permintaan Anda, atau jika kode Anda menjaga system dan tools tetap selama satu sesi dan hanya pernah menambahkan ke messages. Haijun Mythos 5.1 dan model sebelum Haijun Fable 5.1 tidak menjalankan pemeriksaan prefiks. Jika Anda tidak pernah mengirim kembali blok pemikiran, pemeriksaan prefiks tidak memiliki apa pun untuk ditolak, dan model tidak mendapatkan penalaran sebelumnya sama sekali.
Periksa integrasi Anda jika, di antara dua permintaan dalam satu percakapan, integrasi tersebut melakukan salah satu hal berikut. Setiap item menautkan ke apa yang harus dilakukan sebagai gantinya:
- Menyusun ulang prompt
system: tanggal, flag mode, instruksi proyek yang dibaca ulang, atau plugin atau server "Model Context Protocol", atau MCP, yang terhubung setelah giliran pertama
- Meringkas atau membuang giliran lama di klien dan mempertahankan giliran terbaru beserta pemikirannya
- Menambahkan pengingat ke giliran pengguna lalu menghapus atau menulis ulangnya nanti
- Membuang beberapa blok
thinkingdan mempertahankan blok yang lebih baru, atau menghapusnya lalu mengembalikannya nanti
- Menyusun ulang sesi tersimpan dari template alih-alih memutar ulang apa yang telah dikirimnya
Pada akun yang lebih lama, tidak satu pun dari hal ini menghasilkan error kecuali permintaan menetapkan prefix_mismatch_behavior, sehingga proses yang berjalan tanpa error dengan kunci Anda sendiri tidak menunjukkan apakah kode Anda terdampak. Jika orang lain menjalankan alat Anda dengan kunci API mereka sendiri, mereka yang menggunakan akun lebih baru akan mendapatkan error 400 lebih dulu daripada Anda. Untuk melihat apa yang mereka lihat tanpa mengubah perilaku permintaan Anda, kirim header beta thinking-binding-controls-2026-08-01. Pada akun yang lebih lama, setiap respons kemudian menandai blok yang gagal dalam pemeriksaan, dan model tetap membacanya (lihat Tetapkan perilaku ketidakcocokan dan baca input_transformations).
Beralih model di tengah percakapan
Haijun Fable 5.1 dan Haijun Mythos 5.1 membaca blok pemikiran yang dihasilkan oleh satu sama lain dan oleh model Haijun sebelumnya. Tidak ada model sebelumnya yang membaca blok pemikiran dari Haijun Fable 5.1 atau Haijun Mythos 5.1.
Haijun Opus 5.5 membaca blok pemikiran dari Haijun Opus 5 dan model Opus, Sonnet, serta Haiku sebelumnya, tetapi tidak dari model Haijun Fable atau Haijun Mythos. Di Haijun API, Haijun Fable 5.1 dan Haijun Mythos 5.1 membaca blok pemikiran dari Haijun Opus 5.5; tidak ada model lain yang melakukannya. Jadi, percakapan yang berpindah dari Haijun Opus 5 ke Haijun Opus 5.5 tetap mempertahankan penalarannya, begitu pula percakapan yang berpindah dari Haijun Opus 5.5 naik ke Haijun Fable 5.1 atau Haijun Mythos 5.1 di Haijun API. Percakapan yang berpindah dari Haijun Fable 5.1 atau Haijun Mythos 5.1 ke Haijun Opus 5.5, atau dari Haijun Opus 5.5 ke model apa pun selain kedua model tersebut, menjalankan giliran setelah peralihan tanpa penalaran model sebelumnya. Blok-blok tersebut dibuang, bukan ditolak, seperti yang dijelaskan di bawah.
- Percakapan yang berpindah ke Haijun Fable 5.1 dari model sebelumnya, atau dari Haijun Opus 5.5 di Haijun API, tetap mempertahankan penalarannya. Blok pemikiran dari model sebelumnya tetap dapat dibaca, sehingga model berpikir seperti biasa sejak giliran pertama setelah peralihan.
- Percakapan yang berpindah turun ke model sebelumnya kehilangan penalaran Haijun Fable 5.1 untuk permintaan tersebut. Hal ini terjadi ketika router mengirim sebuah giliran ke model yang lebih murah, setelah fallback penolakan classifier, atau selama fallback sisi server. API menghapus blok yang tidak dapat dibaca sebelum prompt mencapai model. Blok tersebut tidak ditagih dan tidak dihitung dalam
input_tokens.
Tetap kirim riwayat lengkap pada setiap permintaan, termasuk blok pemikiran, dan biarkan API membuang apa yang tidak dapat dibaca oleh model saat ini. API tidak pernah mengedit array messages Anda, sehingga blok yang dibuang tetap ada dalam riwayat Anda. Ketika riwayat yang sama kembali ke Haijun Fable 5.1, bloknya dapat dibaca lagi, bersama dengan pemikiran model sebelumnya. Penalaran hilang selamanya hanya jika klien Anda sendiri yang menghapus blok tersebut, misalnya harness yang menghapus pemikiran saat peralihan model atau menyusun ulang riwayat dari apa yang digunakan setiap model.

Dengan beta header (header beta) thinking-binding-controls-2026-08-01, respons mencantumkan setiap blok yang dibuang dalam array input_transformations tingkat atas dengan reason: "model_binding_mismatch":
{
"input_transformations": [
{
"type": "thinking_dropped",
"path": "messages.3.content.0",
"reason": "model_binding_mismatch"
}
]
}Tanpa header tersebut, pembuangan terjadi secara diam-diam. Entri ini bukan bug dalam integrasi Anda, dan prefix_mismatch_behavior tidak berpengaruh padanya: blok yang tidak dapat dibaca oleh model saat ini selalu dibuang.
Menjaga prefiks tetap tidak berubah
Pada Haijun Fable 5.1 dan Haijun Opus 5.5, sebuah blok pemikiran tetap valid hanya selama semua yang Anda kirim sebelumnya tidak berubah pada permintaan berikutnya. Prefiks yang diperiksa memiliki tiga bagian:
- Prompt
systemtingkat atas
- Kumpulan
tools
- Setiap
messagesebelum blok tersebut
Catatan: Dengan compaction (pemadatan) sisi server, prefiks yang diperiksa dimulai dari blok compaction terbaru.
Parameter permintaan di luar ketiga field tersebut, seperti effort, max_tokens, output_config, tool_choice, dan metadata, bukan bagian dari pemeriksaan prefiks, begitu pula penanda cache_control. Apa yang dihitung sebagai edit memuat daftar lengkapnya.
Blok pemikiran sebelumnya tidak termasuk dalam prefiks, tetapi setiap blok pemikiran mencatat blok pemikiran mana yang mendahuluinya, lintas giliran. Anda dapat menghapus blok pemikiran dari awal riwayat (yang terlama terlebih dahulu), dari akhir, atau semuanya. Yang gagal adalah celah: blok pemikiran yang Anda pertahankan harus berupa rangkaian tak terputus dari urutan aslinya, sehingga menghapus satu blok dari tengah membuat blok pemikiran setelahnya tidak valid. Setelah Anda menghapus sebuah blok, biarkan tetap dihapus. Mengembalikannya membuat blok pemikiran yang dihasilkan selama blok itu tidak ada menjadi tidak valid.
Jaga system dan tools tetap selama sesi dan perlakukan messages sebagai append-only. Disiplin yang sama menjaga prefiks tetap stabil untuk "prompt caching" (caching prompt): edit yang membuat pemikiran tidak valid adalah edit yang sama yang memulai ulang cache.
Apa yang dilakukan API dengan blok yang tidak valid
Anda memilihnya dengan thinking.block_binding.prefix_mismatch_behavior:
"error"(default): API menolak permintaan dengan 400invalid_request_erroryang menyebutkan blok pertama yang gagal.
"drop_block": API membuang setiap blok yang gagal dan setiap blok pemikiran setelahnya, dan permintaan berhasil. Blok yang dibuang tidak ditagih. Model menjawab giliran tersebut tanpa menggunakan penalaran dari blok yang dibuang, dan cache prompt dimulai ulang pada titik edit. Respons mencantumkan setiap blok yang dibuang dalaminput_transformations(pada eventmessage_startsaat streaming) denganreason: "prefix_binding_mismatch".
Warning:
"drop_block"menyembunyikan error tetapi tidak memperbaiki edit yang menyebabkannya. Blok yang dibuang tidak ditagih, tetapi penggunaan token sesi mungkin tetap meningkat karena Haijun terkadang berpikir lebih banyak untuk membuat ulang pemikiran yang dibuang. Peningkatan ini cenderung lebih besar ketika lebih banyak blok pemikiran dibuang, atau ketika blok dibuang pada lebih banyak giliran dalam sesi yang panjang.
Hitung respons dalam setiap sesi yang input_transformations-nya memiliki entri prefix_binding_mismatch, buat peringatan untuk respons tersebut, dan ganti setiap edit dengan pola yang sesuai di Melakukan perubahan tanpa mengedit prefiks. Di Message Batches API, item yang tidak menetapkan field tersebut tidak gagal. Jika API memberlakukan pemeriksaan secara default, API akan membuang blok yang gagal sebagai gantinya. Tetapkan "error" secara eksplisit jika Anda ingin item batch gagal dalam kasus tersebut.
Field tersebut dan array input_transformations sama-sama memerlukan header beta thinking-binding-controls-2026-08-01. Tetapkan perilaku ketidakcocokan dan baca input_transformations menunjukkan permintaan tersebut di setiap "software development kit" (kit pengembangan perangkat lunak), atau SDK.
Pesan 400 dimulai dengan:
messages.1.content.0: Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to "drop_block".Jika permintaan tidak mengirim header beta, pesan berlanjut:
That setting requires the `thinking-binding-controls-2026-08-01` value in the `juglow-beta` header.Pesan tersebut biasanya diakhiri dengan kalimat yang menyebutkan apa yang berubah, misalnya bahwa prompt system atau daftar tools berbeda dari saat blok dibuat. Pemecahan masalah pemikiran menjelaskan apa saja yang dapat disebutkan oleh kalimat tersebut.
Signature yang dirusak atau tidak dapat didekripsi adalah kegagalan yang berbeda. Kegagalan ini selalu mengembalikan 400 (`Invalid signature in thinking block tanpa kalimat tentang percakapan), dan prefix_mismatch_behavior` tidak berlaku untuknya.
Menangani error dalam kode
Ini adalah 400 invalid_request_error yang ditunjukkan sebelumnya di bagian ini. Jangan mengirim ulang body yang sama: body tersebut akan gagal dengan cara yang sama setiap kali. Coba ulang sekali dengan header beta dan prefix_mismatch_behavior: "drop_block", dan simpan pilihan tersebut bersama sesi sehingga setiap permintaan berikutnya juga mengirimkannya, termasuk setelah restart. Jika Anda tidak dapat mengirim header beta, hapus setiap blok thinking dan redacted_thinking dari riwayat sekali, biarkan tetap dihapus, dan lanjutkan. Kemudian perbaiki edit yang menyebabkan ketidakcocokan tersebut.
Tetapkan perilaku ketidakcocokan dan baca input_transformations
Header beta thinking-binding-controls-2026-08-01 menambahkan:
- Array
input_transformationstingkat atas pada setiap respons
- Objek
block_bindingpada konfigurasithinking, yang satu-satunya field-nya adalahprefix_mismatch_behavior
block_binding diterima bersama thinking.type: "adaptive" dan thinking.type: "enabled". Mengirimkannya tanpa header beta mengembalikan error 400 yang pesannya diakhiri dengan block_binding: Extra inputs are not permitted. Model yang tidak menjalankan pemeriksaan prefiks menerima objek tersebut dan hanya melaporkan pembuangan dari pemeriksaan model, sehingga satu body permintaan berfungsi di berbagai model. Referensi API menyebut pemeriksaan prefiks sebagai pemeriksaan percakapan.
Permintaan berikut memilih untuk membuang alih-alih menolak. Pada giliran pertama tidak ada yang perlu diputar ulang, sehingga input_transformations dikembalikan kosong:
curl https://haijun.my.id/v1/messages \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-H "content-type: application/json" \
-d '{
"model": "haijun-fable-5-1",
"max_tokens": 16000,
"thinking": {
"type": "adaptive",
"block_binding": {
"prefix_mismatch_behavior": "drop_block"
}
},
"messages": [
{
"role": "user",
"content": "What is the greatest common divisor of 1071 and 462?"
}
]
}' ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format yaml <<'YAML'
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
block_binding:
prefix_mismatch_behavior: drop_block
messages:
- role: user
content: What is the greatest common divisor of 1071 and 462?
YAML client = juglow.Juglow()
response = client.beta.messages.create(
model="haijun-fable-5-1",
max_tokens=16000,
thinking={
"type": "adaptive",
"block_binding": {"prefix_mismatch_behavior": "drop_block"},
},
messages=[
{
"role": "user",
"content": "What is the greatest common divisor of 1071 and 462?",
}
],
betas=["thinking-binding-controls-2026-08-01"],
)
for block in response.content:
if block.type == "text":
print(block.text)
print(f"Input transformations: {len(response.input_transformations or [])}") const client = new Juglow();
const response = await client.beta.messages.create({
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: {
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" }
},
messages: [
{ role: "user", content: "What is the greatest common divisor of 1071 and 462?" }
],
betas: ["thinking-binding-controls-2026-08-01"]
});
for (const block of response.content) {
if (block.type === "text") {
console.log(block.text);
}
}
console.log(`Input transformations: ${response.input_transformations?.length ?? 0}`); JuglowClient client = new();
var response = await client.Beta.Messages.Create(
new()
{
Model = "haijun-fable-5-1",
MaxTokens = 16000,
Thinking = new BetaThinkingConfigAdaptive
{
BlockBinding = new()
{
PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
},
},
Messages =
[
new()
{
Role = Role.User,
Content = "What is the greatest common divisor of 1071 and 462?",
},
],
Betas = [JuglowBeta.ThinkingBindingControls2026_08_01],
}
);
foreach (var block in response.Content)
{
if (block.TryPickText(out var textBlock))
{
Console.WriteLine(textBlock.Text);
}
}
Console.WriteLine($"Input transformations: {response.InputTransformations?.Count ?? 0}"); client := juglow.NewClient()
response, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
Model: "haijun-fable-5-1",
MaxTokens: 16000,
Thinking: juglow.BetaThinkingConfigParamUnion{
OfAdaptive: &juglow.BetaThinkingConfigAdaptiveParam{
BlockBinding: juglow.BetaThinkingBlockBindingParam{
PrefixMismatchBehavior: juglow.BetaThinkingPrefixMismatchBehaviorDropBlock,
},
},
},
Messages: []juglow.BetaMessageParam{
juglow.NewBetaUserMessage(juglow.NewBetaTextBlock("What is the greatest common divisor of 1071 and 462?")),
},
Betas: []juglow.JuglowBeta{juglow.JuglowBetaThinkingBindingControls2026_08_01},
})
if err != nil {
log.Fatal(err)
}
for _, block := range response.Content {
if textBlock, ok := block.AsAny().(juglow.BetaTextBlock); ok {
fmt.Println(textBlock.Text)
}
}
fmt.Printf("Input transformations: %d\n", len(response.InputTransformations)) import com.juglow.models.beta.JuglowBeta;
import com.juglow.models.beta.messages.BetaMessage;
import com.juglow.models.beta.messages.BetaThinkingBlockBinding;
import com.juglow.models.beta.messages.BetaThinkingConfigAdaptive;
import com.juglow.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
import com.juglow.models.beta.messages.MessageCreateParams;
void main() {
JuglowClient client = JuglowOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model("haijun-fable-5-1")
.maxTokens(16000L)
.addBeta(JuglowBeta.THINKING_BINDING_CONTROLS_2026_08_01)
.thinking(BetaThinkingConfigAdaptive.builder()
.blockBinding(BetaThinkingBlockBinding.builder()
.prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
.build())
.build())
.addUserMessage("What is the greatest common divisor of 1071 and 462?")
.build();
BetaMessage response = client.beta().messages().create(params);
response.content().stream()
.flatMap(block -> block.text().stream())
.forEach(textBlock -> IO.println(textBlock.text()));
IO.println("Input transformations: "
+ response.inputTransformations().map(List::size).orElse(0));
} use Juglow\Beta\JuglowBeta;
use Juglow\Beta\Messages\BetaThinkingBlockBinding;
use Juglow\Beta\Messages\BetaThinkingConfigAdaptive;
use Juglow\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
use Juglow\Client;
$client = new Client();
$response = $client->beta->messages->create(
model: 'haijun-fable-5-1',
maxTokens: 16000,
thinking: BetaThinkingConfigAdaptive::with(
blockBinding: BetaThinkingBlockBinding::with(
prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
),
),
messages: [
['role' => 'user', 'content' => 'What is the greatest common divisor of 1071 and 462?'],
],
betas: [JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01],
);
foreach ($response->content as $block) {
if ($block->type === 'text') {
echo $block->text, PHP_EOL;
}
}
echo 'Input transformations: ', count($response->inputTransformations ?? []), PHP_EOL; client = Juglow::Client.new
response = client.beta.messages.create(
model: "haijun-fable-5-1",
max_tokens: 16_000,
thinking: {
type: "adaptive",
block_binding: {prefix_mismatch_behavior: "drop_block"}
},
messages: [
{role: "user", content: "What is the greatest common divisor of 1071 and 462?"}
],
betas: [Juglow::JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01]
)
response.content.each do |block|
puts block.text if block.type == :text
end
puts "Input transformations: #{response.input_transformations&.length || 0}"The greatest common divisor of 1071 and 462 is 21.
Input transformations: 0Dengan header beta, setiap respons dari model yang mendukung pemikiran membawa input_transformations. Setiap entri menyebutkan satu blok pemikiran berdasarkan path-nya (misalnya messages.1.content.0) dan memberikan reason. Ada dua jenis entri:
thinking_dropped: API membuang blok sebelum model membacanya, dan blok tersebut tidak ditagih.reason-nya adalahprefix_binding_mismatchataumodel_binding_mismatch(lihat Beralih model di tengah percakapan).
thinking_mismatch_allowed: blok gagal dalam pemeriksaan prefiks, tetapi API tidak memberlakukan pemeriksaan tersebut untuk permintaan ini, sehingga blok mencapai model tanpa perubahan dan ditagih.reason-nya selaluprefix_binding_mismatch. Entri ini hanya muncul pada permintaan di mana API tidak memberlakukan pemeriksaan secara default, seperti permintaan dari akun yang lebih lama (lihat Kapan API memberlakukan pemeriksaan). Menetapkanprefix_mismatch_behaviorke salah satu nilai akan mengikutsertakan permintaan dalam pemberlakuan, sehingga permintaan yang menetapkannya tidak pernah mendapatkan entri ini.
Array kosong ketika tidak ada blok yang dibuang dan tidak ada yang gagal dalam pemeriksaan prefiks. Abaikan entri yang type atau reason-nya tidak Anda kenali, karena pemeriksaan di masa mendatang akan menambahkan nilai baru.
Saat streaming, array tiba pada objek message dalam event message_start. Setelah fallback sisi server di tengah stream, event message_delta terakhir membawanya lagi dengan entri dari model yang melayani. Dalam message batch, item yang bloknya gagal dalam pemeriksaan prefiks dengan "error" eksplisit akan berstatus errored. Item yang tidak menetapkan field ini tidak gagal. Jika API memberlakukan pemeriksaan secara default, API akan membuang blok yang gagal sebagai gantinya. Endpoint penghitungan token menjalankan pemeriksaan prefiks yang sama dan mengembalikan 400 yang sama.
Kapan API memberlakukan pemeriksaan
API memberlakukan pemeriksaan prefiks pada Haijun Fable 5.1 dan Haijun Opus 5.5 untuk akun baru.
- Akun yang dibuat pada atau setelah 31 Agustus 2026, 00:00 UTC: API memeriksa permintaan Haijun Fable 5.1 dan Haijun Opus 5.5 dan menerapkan
"error"kecuali Anda menetapkan"drop_block". Definisi akun baru yang sama berlaku untuk Haijun API dan platform cloud.
- Akun yang lebih lama: API memberlakukan pemeriksaan hanya pada permintaan yang menetapkan
prefix_mismatch_behavior. Menetapkan field tersebut mengikutsertakan permintaan, sehingga Anda dapat melihat apa yang dilihat akun baru tanpa membuatnya. Pada permintaan yang tidak menetapkannya, API tetap menjalankan pemeriksaan tetapi meneruskan blok yang gagal ke model. Dengan header beta, respons mencantumkan masing-masing blok tersebut dalaminput_transformationssebagaithinking_mismatch_allowed, sehingga Anda dapat menemukan edit prefiks tanpa mengubah apa yang diterima model.
Untuk mengetahui kelompok mana akun Anda berada, ambil percakapan Haijun Fable 5.1 yang berisi blok pemikiran, ubah sesuatu sebelum blok tersebut, lalu kirimkan ke Haijun Fable 5.1 tanpa header beta atau field block_binding. Respons 400 yang menyebutkan header tersebut berarti akun Anda diberlakukan secara default. Respons 200 berarti tidak. Untuk memastikan, kirim permintaan yang sama lagi dengan header beta, tetap tanpa block_binding: respons mencantumkan setiap blok pemikiran setelah edit Anda dalam input_transformations sebagai thinking_mismatch_allowed.
Apa yang dihitung sebagai edit
Setiap baris membandingkan dua permintaan yang berurutan:
| Perubahan di antara permintaan | Blok pemikiran berikutnya |
|---|---|
| Menambahkan pesan di akhir | Valid |
Menambahkan alat dengan defer_loading: true yang belum direferensikan oleh apa pun | Valid |
Menghapus blok thinking dari awal riwayat, dari akhir, atau semuanya | Valid (model kehilangan penalaran tersebut) |
Mengubah parameter permintaan apa pun di luar system, tools, dan messages (effort, max_tokens, output_config, tool_choice, metadata, thinking.display, dan sebagainya) | Valid |
Menambahkan, memindahkan, atau menghapus penanda cache_control | Valid |
| URL bertanda tangan yang berotasi dan mengembalikan byte yang sama | Valid |
| Compaction atau "context editing" (pengeditan konteks) sisi server menghapus atau mengganti konten | Valid (pemeriksaan membandingkan apa yang Anda kirim, bukan salinan yang diedit server) |
| Pesan sistem berlingkup giliran yang sudah dibersihkan dan dibiarkan di tempatnya | Valid |
Mengedit, mengurutkan ulang, atau menghapus pesan user, assistant, atau system sebelumnya | Tidak valid, kecuali ketika blok bertanda tangan dari compaction sesuai permintaan menggantikan pesan yang diringkasnya, dengan syarat agar pemikiran yang disimpan tetap valid |
| Merender ulang konteks yang Anda masukkan dalam pesan pengguna pertama dengan nilai yang berubah | Tidak valid untuk setiap blok pemikiran |
Menghapus atau memperpendek tool_result sebelumnya, meng-encode ulang gambar sebelumnya, atau mengubah input tool_use sebelumnya | Tidak valid untuk setiap blok pemikiran berikutnya |
| Menambahkan blok teks ke giliran pengguna sebelumnya, atau menghapus blok yang Anda tambahkan sebelumnya | Tidak valid |
Mengubah string atau blok system tingkat atas | Tidak valid |
Menambahkan, menghapus, mengganti nama, atau mengedit alat di tools | Tidak valid |
Menghapus blok thinking dari tengah riwayat dan mempertahankan blok setelahnya | Tidak valid untuk setiap blok pemikiran berikutnya |
Memasukkan kembali blok thinking yang Anda hapus pada permintaan sebelumnya | Tidak valid untuk blok pemikiran yang dihasilkan selama blok itu tidak ada |
| URL gambar atau dokumen yang mengembalikan byte berbeda pada permintaan berikutnya | Tidak valid |
| Pesan berlingkup giliran yang sama dihapus atau diubah kata-katanya pada permintaan berikutnya | Tidak valid |
Periksa apakah kode Anda mengedit prefiks
Pertama, bandingkan (diff) apa yang Anda kirim. Tangkap body permintaan yang dikirim integrasi Anda selama beberapa giliran normal, termasuk compaction atau perubahan alat. Untuk setiap pasangan permintaan yang berurutan, bandingkan system, tools, dan messages yang sama-sama dimiliki keduanya. Semuanya harus identik hingga giliran yang baru ditambahkan.
Kemudian konfirmasikan terhadap API. Tambahkan header beta thinking-binding-controls-2026-08-01, tetapkan prefix_mismatch_behavior ke "drop_block", dan jalankan sesi multi-giliran normal melalui integrasi Anda pada haijun-fable-5-1. Contoh berikut menjalankan dua giliran sebagaimana seharusnya integrasi Anda bekerja: messages hanya bertambah, setiap giliran asisten dikirim kembali persis seperti yang dikembalikan API, termasuk blok thinking, dan block_binding ditetapkan pada setiap permintaan. Setelah setiap giliran, contoh ini mencetak jumlah blok thinking dalam respons dan jumlah blok yang dibuang:
# Menghitung blok thinking dalam respons dan blok yang dihapus oleh API
COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
"dropped: \(.input_transformations | length)"'
FIRST=$(curl -s https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d '{
"model": "haijun-fable-5-1",
"max_tokens": 16000,
"thinking": {
"type": "adaptive",
"block_binding": { "prefix_mismatch_behavior": "drop_block" }
},
"messages": [
{
"role": "user",
"content": "How many positive integers below 500 have exactly 6 positive divisors?"
}
]
}')
echo "$FIRST" | jq -r "$COUNTS"
# Giliran 2: giliran asisten dikirim kembali persis seperti yang dikembalikan, lalu pesan pengguna berikutnya
MESSAGES=$(jq -n --argjson first "$FIRST" '[
{
role: "user",
content: "How many positive integers below 500 have exactly 6 positive divisors?"
},
{ role: "assistant", content: $first.content },
{ role: "user", content: "How many of those are odd?" }
]')
jq -n --argjson messages "$MESSAGES" '{
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: {
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" }
},
messages: $messages
}' | curl -s https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d @- | jq -r "$COUNTS" # Menghitung blok thinking dalam respons dan blok yang dibuang oleh API
COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
"dropped: \(.input_transformations | length)"'
FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format json <<'YAML'
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
block_binding:
prefix_mismatch_behavior: drop_block
messages:
- role: user
content: How many positive integers below 500 have exactly 6 positive divisors?
YAML
)
echo "$FIRST" | jq -r "$COUNTS"
# Giliran 2: giliran asisten dikirim kembali persis seperti yang dikembalikan, lalu pesan pengguna berikutnya
ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format json <<YAML | jq -r "$COUNTS"
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
block_binding:
prefix_mismatch_behavior: drop_block
messages:
- role: user
content: How many positive integers below 500 have exactly 6 positive divisors?
- role: assistant
content: $(echo "$FIRST" | jq -c .content)
- role: user
content: How many of those are odd?
YAML client = juglow.Juglow()
user_turns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
]
# messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
messages = []
for user_turn in user_turns:
messages.append({"role": "user", "content": user_turn})
response = client.beta.messages.create(
model="haijun-fable-5-1",
max_tokens=16000,
thinking={
"type": "adaptive",
"block_binding": {"prefix_mismatch_behavior": "drop_block"},
},
messages=messages,
betas=["thinking-binding-controls-2026-08-01"],
)
messages.append({"role": "assistant", "content": response.content})
thinking_blocks = sum(block.type == "thinking" for block in response.content)
dropped = len(response.input_transformations or [])
print(f"thinking blocks: {thinking_blocks}, dropped: {dropped}") const client = new Juglow();
const userTurns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?"
];
// messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
const messages: Juglow.Beta.BetaMessageParam[] = [];
for (const userTurn of userTurns) {
messages.push({ role: "user", content: userTurn });
const response = await client.beta.messages.create({
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: {
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" }
},
messages,
betas: ["thinking-binding-controls-2026-08-01"]
});
messages.push({ role: "assistant", content: response.content });
const thinkingBlocks = response.content.filter((block) => block.type === "thinking");
const dropped = response.input_transformations ?? [];
console.log(`thinking blocks: ${thinkingBlocks.length}, dropped: ${dropped.length}`);
} JuglowClient client = new();
string[] userTurns =
[
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
];
// messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
List<BetaMessageParam> messages = [];
foreach (var userTurn in userTurns)
{
messages.Add(new() { Role = Role.User, Content = userTurn });
var response = await client.Beta.Messages.Create(
new()
{
Model = "haijun-fable-5-1",
MaxTokens = 16000,
Thinking = new BetaThinkingConfigAdaptive
{
BlockBinding = new()
{
PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
},
},
Messages = messages,
Betas = [JuglowBeta.ThinkingBindingControls2026_08_01],
}
);
messages.Add(new()
{
Role = Role.Assistant,
Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
});
var thinkingBlocks = response.Content.Count(block => block.TryPickThinking(out _));
var dropped = response.InputTransformations?.Count ?? 0;
Console.WriteLine($"thinking blocks: {thinkingBlocks}, dropped: {dropped}");
} client := juglow.NewClient()
userTurns := []string{
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
}
// messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
messages := []juglow.BetaMessageParam{}
for _, userTurn := range userTurns {
messages = append(messages, juglow.NewBetaUserMessage(juglow.NewBetaTextBlock(userTurn)))
response, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
Model: "haijun-fable-5-1",
MaxTokens: 16000,
Thinking: juglow.BetaThinkingConfigParamUnion{
OfAdaptive: &juglow.BetaThinkingConfigAdaptiveParam{
BlockBinding: juglow.BetaThinkingBlockBindingParam{
PrefixMismatchBehavior: juglow.BetaThinkingPrefixMismatchBehaviorDropBlock,
},
},
},
Messages: messages,
Betas: []juglow.JuglowBeta{juglow.JuglowBetaThinkingBindingControls2026_08_01},
})
if err != nil {
log.Fatal(err)
}
messages = append(messages, response.ToParam())
thinkingBlocks := 0
for _, block := range response.Content {
if block.Type == "thinking" {
thinkingBlocks++
}
}
fmt.Printf("thinking blocks: %d, dropped: %d\n", thinkingBlocks, len(response.InputTransformations))
} import com.juglow.models.beta.JuglowBeta;
import com.juglow.models.beta.messages.BetaContentBlock;
import com.juglow.models.beta.messages.BetaMessage;
import com.juglow.models.beta.messages.BetaThinkingBlockBinding;
import com.juglow.models.beta.messages.BetaThinkingConfigAdaptive;
import com.juglow.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
import com.juglow.models.beta.messages.MessageCreateParams;
void main() {
JuglowClient client = JuglowOkHttpClient.fromEnv();
List<String> userTurns = List.of(
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?");
// Daftar pesan builder bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
MessageCreateParams.Builder conversation = MessageCreateParams.builder()
.model("haijun-fable-5-1")
.maxTokens(16000L)
.thinking(BetaThinkingConfigAdaptive.builder()
.blockBinding(BetaThinkingBlockBinding.builder()
.prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
.build())
.build())
.addBeta(JuglowBeta.THINKING_BINDING_CONTROLS_2026_08_01);
for (String userTurn : userTurns) {
conversation.addUserMessage(userTurn);
BetaMessage response = client.beta().messages().create(conversation.build());
conversation.addMessage(response);
long thinkingBlocks = response.content().stream()
.filter(BetaContentBlock::isThinking)
.count();
int dropped = response.inputTransformations().map(List::size).orElse(0);
IO.println("thinking blocks: " + thinkingBlocks + ", dropped: " + dropped);
}
} use Juglow\Beta\JuglowBeta;
use Juglow\Beta\Messages\BetaThinkingBlockBinding;
use Juglow\Beta\Messages\BetaThinkingConfigAdaptive;
use Juglow\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
use Juglow\Client;
$client = new Client();
$userTurns = [
'How many positive integers below 500 have exactly 6 positive divisors?',
'How many of those are odd?',
];
// $messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
$messages = [];
foreach ($userTurns as $userTurn) {
$messages[] = ['role' => 'user', 'content' => $userTurn];
$response = $client->beta->messages->create(
model: 'haijun-fable-5-1',
maxTokens: 16000,
thinking: BetaThinkingConfigAdaptive::with(
blockBinding: BetaThinkingBlockBinding::with(
prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
),
),
messages: $messages,
betas: [JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01],
);
$messages[] = ['role' => 'assistant', 'content' => $response->content];
$thinkingBlocks = array_filter($response->content, fn ($block) => $block->type === 'thinking');
$dropped = $response->inputTransformations ?? [];
echo 'thinking blocks: ', count($thinkingBlocks), ', dropped: ', count($dropped), PHP_EOL;
} client = Juglow::Client.new
user_turns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?"
]
# messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
messages = []
user_turns.each do |user_turn|
messages << {role: "user", content: user_turn}
response = client.beta.messages.create(
model: "haijun-fable-5-1",
max_tokens: 16_000,
thinking: {
type: "adaptive",
block_binding: {prefix_mismatch_behavior: "drop_block"}
},
messages: messages,
betas: [Juglow::JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01]
)
messages << {role: "assistant", content: response.content}
thinking_blocks = response.content.count { |block| block.type == :thinking }
dropped = (response.input_transformations || []).length
puts "thinking blocks: #{thinking_blocks}, dropped: #{dropped}"
endthinking blocks: 1, dropped: 0
thinking blocks: 1, dropped: 0Tidak ada giliran yang membuang blok karena tidak ada yang berubah sebelumnya. Periksa bahwa respons pertama berisi blok thinking. Dengan "adaptive thinking" (pemikiran adaptif), beberapa respons tidak memilikinya. Jika tidak ada respons dalam sesi yang memilikinya, tidak ada yang perlu diperiksa dan jumlah yang dibuang adalah 0 apa pun yang Anda ubah, jadi jalankan contoh tersebut lagi.
Catat input_transformations pada setiap giliran integrasi Anda sendiri. Ketika API membuang sebuah blok, entrinya terlihat seperti berikut:
{
"input_transformations": [
{
"type": "thinking_dropped",
"path": "messages.1.content.0",
"reason": "prefix_binding_mismatch"
}
]
}- Kosong pada setiap giliran dalam sesi yang berisi blok
thinking: integrasi Anda menjaga prefiks tetap utuh.
reason: "prefix_binding_mismatch": sesuatu sebelum blok dipathberubah sejak permintaan sebelumnya. Bandingkansystem,tools, danmessageshingga giliran tersebut untuk menemukannya, atau kirim ulang permintaan dengan"error": 400 biasanya diakhiri dengan kalimat yang menyebutkan apa yang berubah. Kemudian temukan pengganti yang sesuai di Melakukan perubahan tanpa mengedit prefiks.
reason: "model_binding_mismatch": percakapan berpindah ke model yang tidak dapat membaca blok model sebelumnya. Ini bukan edit prefiks. Lihat Beralih model di tengah percakapan.
Untuk melihat kegagalan secara sengaja, kirim giliran ketiga dari contoh sebelumnya dan tambahkan prompt system hanya pada permintaan tersebut, sehingga berbeda dari dua permintaan pertama, yang tidak memilikinya. Dengan "drop_block", jumlah yang dibuang tidak lagi 0: respons memiliki satu entri untuk setiap blok pemikiran dalam riwayat, masing-masing dengan reason: "prefix_binding_mismatch". Dengan "error", permintaan mengembalikan 400 yang dijelaskan di Apa yang dilakukan API dengan blok yang tidak valid, dan kalimat terakhirnya menyebutkan prompt system. Di tab cURL dan "command-line interface" (antarmuka baris perintah), atau CLI, hapus filter jq untuk melihat body error. Jika jumlahnya masih 0, tidak ada yang perlu diperiksa: pastikan bahwa modelnya adalah haijun-fable-5-1, bahwa permintaan menetapkan block_binding, bahwa riwayat yang Anda kirim berisi blok thinking, dan bahwa dua permintaan pertama tidak memiliki prompt system.
Dua giliran biasa jarang menunjukkan masalah. Jalankan sesi melalui setiap skenario berikut, dengan "error" ditetapkan sehingga regresi menggagalkan "continuous integration" (integrasi berkelanjutan), atau CI, Anda:
- Compaction atau pemangkasan sisi klien yang pertama
- Alat, plugin, atau server MCP yang terhubung setelah giliran pertama
- Perubahan mode atau instruksi
- Loop alat yang panjang, jika Anda menambahkan pengingat atau memperpendek hasil alat lama
- Peralihan ke model lain dan kembali lagi
- Penyimpanan, restart, dan melanjutkan sesi pada tanggal berikutnya
Pada akun yang lebih lama, Anda juga dapat memantau lalu lintas produksi tanpa ikut serta dalam pemberlakuan: kirim header beta, jangan sertakan block_binding, dan catat input_transformations. Mengirim header saja tidak mengubah apa yang diterima model. Setiap blok pemikiran yang muncul setelah konten yang Anda edit gagal dalam pemeriksaan dan mendapatkan entri thinking_mismatch_allowed sendiri, dengan field path dan reason yang sama seperti entri thinking_dropped. Blok sebelum edit tetap lolos. Edit pada system atau tools berada sebelum setiap blok, sehingga menggagalkan setiap blok pemikiran dalam permintaan. Satu entri terlihat seperti ini:
{
"input_transformations": [
{
"type": "thinking_mismatch_allowed",
"path": "messages.1.content.0",
"reason": "prefix_binding_mismatch"
}
]
}Jalankan contoh berikut dari akun yang lebih lama, karena akun yang lebih baru akan menolak permintaan ketiganya dengan 400. Contoh ini mengirim header tanpa block_binding dan memperluas sesi sebelumnya dengan permintaan ketiga yang menambahkan prompt sistem, yang secara sengaja mengubah prefiks. Setelah setiap giliran, contoh ini mencetak jumlah blok thinking dan blok yang ditandai:
# Menghitung blok thinking dalam respons dan blok yang gagal dalam pemeriksaan prefiks
COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
"flagged: \([.input_transformations[] |
select(.type == "thinking_mismatch_allowed")] | length)"'
FIRST=$(curl -s https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d '{
"model": "haijun-fable-5-1",
"max_tokens": 16000,
"thinking": { "type": "adaptive" },
"messages": [
{
"role": "user",
"content": "How many positive integers below 500 have exactly 6 positive divisors?"
}
]
}')
echo "$FIRST" | jq -r "$COUNTS"
# Giliran 2: giliran asisten dikirim kembali persis seperti yang dikembalikan, lalu pesan pengguna berikutnya
MESSAGES=$(jq -n --argjson first "$FIRST" '[
{
role: "user",
content: "How many positive integers below 500 have exactly 6 positive divisors?"
},
{ role: "assistant", content: $first.content },
{ role: "user", content: "How many of those are odd?" }
]')
SECOND=$(jq -n --argjson messages "$MESSAGES" '{
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: { type: "adaptive" },
messages: $messages
}' | curl -s https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d @-)
echo "$SECOND" | jq -r "$COUNTS"
# Giliran 3: hanya permintaan ini yang menambahkan prompt sistem, yang sengaja mengubah prefiks
jq -n --argjson messages "$MESSAGES" --argjson second "$SECOND" '{
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: { type: "adaptive" },
system: "Answer briefly.",
messages: ($messages + [
{ role: "assistant", content: $second.content },
{ role: "user", content: "And how many of the odd ones are below 100?" }
])
}' | curl -s https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d @- | jq -r "$COUNTS" # Menghitung blok thinking dalam respons dan blok yang gagal dalam pemeriksaan prefiks
COUNTS='"thinking blocks: \([.content[] | select(.type == "thinking")] | length), " +
"flagged: \([.input_transformations[] |
select(.type == "thinking_mismatch_allowed")] | length)"'
FIRST=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format json <<'YAML'
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
messages:
- role: user
content: How many positive integers below 500 have exactly 6 positive divisors?
YAML
)
echo "$FIRST" | jq -r "$COUNTS"
# Giliran 2: giliran asisten dikirim kembali persis seperti yang dikembalikan, lalu pesan pengguna berikutnya
SECOND=$(ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format json <<YAML
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
messages:
- role: user
content: How many positive integers below 500 have exactly 6 positive divisors?
- role: assistant
content: $(echo "$FIRST" | jq -c .content)
- role: user
content: How many of those are odd?
YAML
)
echo "$SECOND" | jq -r "$COUNTS"
# Giliran 3: hanya permintaan ini yang menambahkan prompt sistem, yang sengaja mengubah prefiks
ant beta:messages create --beta thinking-binding-controls-2026-08-01 \
--format json <<YAML | jq -r "$COUNTS"
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
system: Answer briefly.
messages:
- role: user
content: How many positive integers below 500 have exactly 6 positive divisors?
- role: assistant
content: $(echo "$FIRST" | jq -c .content)
- role: user
content: How many of those are odd?
- role: assistant
content: $(echo "$SECOND" | jq -c .content)
- role: user
content: And how many of the odd ones are below 100?
YAML client = juglow.Juglow()
user_turns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?",
]
# messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
messages = []
for turn, user_turn in enumerate(user_turns, start=1):
messages.append({"role": "user", "content": user_turn})
response = client.beta.messages.create(
model="haijun-fable-5-1",
max_tokens=16000,
thinking={"type": "adaptive"},
# Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
system="Answer briefly." if turn == len(user_turns) else juglow.omit,
messages=messages,
betas=["thinking-binding-controls-2026-08-01"],
)
messages.append({"role": "assistant", "content": response.content})
thinking_blocks = sum(block.type == "thinking" for block in response.content)
flagged = sum(
transformation.type == "thinking_mismatch_allowed"
for transformation in response.input_transformations or []
)
print(f"thinking blocks: {thinking_blocks}, flagged: {flagged}") const client = new Juglow();
const userTurns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?"
];
// messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
const messages: Juglow.Beta.BetaMessageParam[] = [];
for (const [turnIndex, userTurn] of userTurns.entries()) {
messages.push({ role: "user", content: userTurn });
const response = await client.beta.messages.create({
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: { type: "adaptive" },
// Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
system: turnIndex === userTurns.length - 1 ? "Answer briefly." : undefined,
messages,
betas: ["thinking-binding-controls-2026-08-01"]
});
messages.push({ role: "assistant", content: response.content });
const thinkingBlocks = response.content.filter((block) => block.type === "thinking");
const flagged = (response.input_transformations ?? []).filter(
(transformation) => transformation.type === "thinking_mismatch_allowed"
);
console.log(`thinking blocks: ${thinkingBlocks.length}, flagged: ${flagged.length}`);
} JuglowClient client = new();
string[] userTurns =
[
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?",
];
// messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
List<BetaMessageParam> messages = [];
for (var turnIndex = 0; turnIndex < userTurns.Length; turnIndex++)
{
messages.Add(new() { Role = Role.User, Content = userTurns[turnIndex] });
var response = await client.Beta.Messages.Create(
new()
{
Model = "haijun-fable-5-1",
MaxTokens = 16000,
Thinking = new BetaThinkingConfigAdaptive(),
// Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
System = turnIndex == userTurns.Length - 1 ? new("Answer briefly.") : null,
Messages = messages,
Betas = [JuglowBeta.ThinkingBindingControls2026_08_01],
}
);
messages.Add(new()
{
Role = Role.Assistant,
Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
});
var thinkingBlocks = response.Content.Count(block => block.TryPickThinking(out _));
var flagged = response.InputTransformations?.Count(transformation =>
transformation.TryPickThinkingMismatchAllowed(out _)
) ?? 0;
Console.WriteLine($"thinking blocks: {thinkingBlocks}, flagged: {flagged}");
} client := juglow.NewClient()
userTurns := []string{
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?",
}
// messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
messages := []juglow.BetaMessageParam{}
for i, userTurn := range userTurns {
messages = append(messages, juglow.NewBetaUserMessage(juglow.NewBetaTextBlock(userTurn)))
// Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
var system []juglow.BetaTextBlockParam
if i == len(userTurns)-1 {
system = []juglow.BetaTextBlockParam{{Text: "Answer briefly."}}
}
response, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
Model: "haijun-fable-5-1",
MaxTokens: 16000,
Thinking: juglow.BetaThinkingConfigParamUnion{
OfAdaptive: &juglow.BetaThinkingConfigAdaptiveParam{},
},
System: system,
Messages: messages,
Betas: []juglow.JuglowBeta{juglow.JuglowBetaThinkingBindingControls2026_08_01},
})
if err != nil {
log.Fatal(err)
}
messages = append(messages, response.ToParam())
thinkingBlocks := 0
for _, block := range response.Content {
if block.Type == "thinking" {
thinkingBlocks++
}
}
flagged := 0
for _, transformation := range response.InputTransformations {
if transformation.Type == "thinking_mismatch_allowed" {
flagged++
}
}
fmt.Printf("thinking blocks: %d, flagged: %d\n", thinkingBlocks, flagged)
} import com.juglow.models.beta.JuglowBeta;
import com.juglow.models.beta.messages.BetaContentBlock;
import com.juglow.models.beta.messages.BetaInputTransformation;
import com.juglow.models.beta.messages.BetaMessage;
import com.juglow.models.beta.messages.BetaThinkingConfigAdaptive;
import com.juglow.models.beta.messages.MessageCreateParams;
void main() {
JuglowClient client = JuglowOkHttpClient.fromEnv();
List<String> userTurns = List.of(
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?");
// Daftar pesan builder bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
MessageCreateParams.Builder conversation = MessageCreateParams.builder()
.model("haijun-fable-5-1")
.maxTokens(16000L)
.thinking(BetaThinkingConfigAdaptive.builder().build())
.addBeta(JuglowBeta.THINKING_BINDING_CONTROLS_2026_08_01);
for (int turnIndex = 0; turnIndex < userTurns.size(); turnIndex++) {
if (turnIndex == userTurns.size() - 1) {
// Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
conversation.system("Answer briefly.");
}
conversation.addUserMessage(userTurns.get(turnIndex));
BetaMessage response = client.beta().messages().create(conversation.build());
conversation.addMessage(response);
long thinkingBlocks = response.content().stream()
.filter(BetaContentBlock::isThinking)
.count();
long flagged = response.inputTransformations().stream()
.flatMap(List::stream)
.filter(BetaInputTransformation::isThinkingMismatchAllowed)
.count();
IO.println("thinking blocks: " + thinkingBlocks + ", flagged: " + flagged);
}
} use Juglow\Beta\JuglowBeta;
use Juglow\Beta\Messages\BetaThinkingConfigAdaptive;
use Juglow\Beta\Messages\BetaThinkingMismatchAllowedInputTransformation;
use Juglow\Client;
$client = new Client();
$userTurns = [
'How many positive integers below 500 have exactly 6 positive divisors?',
'How many of those are odd?',
'And how many of the odd ones are below 100?',
];
// $messages bertambah di setiap giliran: tiap giliran asisten dikirim kembali persis seperti yang dikembalikan
$messages = [];
foreach ($userTurns as $turnIndex => $userTurn) {
$messages[] = ['role' => 'user', 'content' => $userTurn];
$response = $client->beta->messages->create(
model: 'haijun-fable-5-1',
maxTokens: 16000,
thinking: BetaThinkingConfigAdaptive::with(),
// Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
system: $turnIndex === array_key_last($userTurns) ? 'Answer briefly.' : null,
messages: $messages,
betas: [JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01],
);
$messages[] = ['role' => 'assistant', 'content' => $response->content];
$thinkingBlocks = array_filter($response->content, fn ($block) => $block->type === 'thinking');
$flagged = array_filter(
$response->inputTransformations ?? [],
fn ($transformation) => $transformation instanceof BetaThinkingMismatchAllowedInputTransformation,
);
echo 'thinking blocks: ', count($thinkingBlocks), ', flagged: ', count($flagged), PHP_EOL;
} client = Juglow::Client.new
user_turns = [
"How many positive integers below 500 have exactly 6 positive divisors?",
"How many of those are odd?",
"And how many of the odd ones are below 100?"
]
# messages bertambah di setiap giliran: tiap giliran assistant dikirim kembali persis seperti yang dikembalikan
messages = []
user_turns.each_with_index do |user_turn, turn_index|
messages << {role: "user", content: user_turn}
# Hanya permintaan terakhir yang menambahkan prompt sistem, yang sengaja mengubah prefiks
system_param = (turn_index == user_turns.length - 1) ? {system_: "Answer briefly."} : {}
response = client.beta.messages.create(
model: "haijun-fable-5-1",
max_tokens: 16_000,
thinking: {type: "adaptive"},
messages: messages,
betas: [Juglow::JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01],
**system_param
)
messages << {role: "assistant", content: response.content}
thinking_blocks = response.content.count { |block| block.type == :thinking }
flagged = (response.input_transformations || []).count do |transformation|
transformation.type == :thinking_mismatch_allowed
end
puts "thinking blocks: #{thinking_blocks}, flagged: #{flagged}"
endthinking blocks: 1, flagged: 0
thinking blocks: 1, flagged: 0
thinking blocks: 1, flagged: 2Respons ketiga menandai setiap blok pemikiran dari giliran sebelumnya, satu per giliran dalam proses ini, karena prompt sistem yang baru berada sebelum semuanya. Model tetap membacanya.
Tangani entri ini seperti Anda menangani pembuangan prefix_binding_mismatch. Edit berada sebelum blok pertama yang tercantum: bandingkan system, tools, dan messages hingga path blok tersebut dengan permintaan sebelumnya untuk menemukannya, lalu ganti dengan pola yang sesuai di Melakukan perubahan tanpa mengedit prefiks. Pada akun baru, atau pada permintaan apa pun yang menetapkan prefix_mismatch_behavior, API justru menolak permintaan atau membuang blok yang gagal. Entri-entri ini adalah batas bawah dari apa yang akan dihapus oleh pemberlakuan: dengan "drop_block", blok yang gagal juga ikut membuang sisa blok pemikiran pada giliran tersebut, dan menghapus satu blok dapat membuat blok berikutnya ikut gagal. Ketika API hanya mencatat pemeriksaan, API menilai setiap blok secara terpisah dan hanya mencantumkan blok yang memang gagal.
Melakukan perubahan tanpa mengedit prefiks
Setiap edit prefiks yang umum memiliki pengganti yang memberikan informasi yang sama kepada model dan membiarkan byte sebelumnya tidak berubah, sehingga pemikiran berikutnya tetap valid. Temukan edit yang dilakukan kode Anda saat ini di kolom pertama:
| Alih-alih | Gunakan | Header beta |
|---|---|---|
Menyusun ulang prompt system tingkat atas | Pesan sistem di tengah percakapan | Tidak ada |
| Merender ulang konteks dalam pesan pengguna pertama Anda (lingkungan, tanggal, memori, instruksi proyek) pada setiap permintaan | Render sekali dan kirim ulang tanpa perubahan. Ketika sesuatu berubah, masukkan versi baru di giliran terbaru | Tidak ada |
Menghapus atau memperpendek konten tool_result lama, atau meng-encode ulang gambar lama, di tempatnya | Perpendek hasil alat atau perkecil resolusi gambar sebelum pertama kali Anda mengirimkannya, bukan setelahnya. Untuk menghapus hasil lama nanti, pangkas konteks di server dengan clear_tool_uses_20250919 | context-management-2025-06-27 |
| Menyisipkan pengingat dan menghapusnya pada permintaan berikutnya | Pesan sistem berlingkup giliran (clear_at: "next_user_message") | mid-conversation-system-clear-at-2026-08-21 |
Menambahkan atau menghapus entri di tools | Blok tool_addition dan tool_removal | inline-tools-2026-09-15 (tambahkan mcp-client-2026-09-15 ketika alat berasal dari server MCP yang terhubung melalui konektor MCP), atau mid-conversation-tool-changes-2026-07-01 yang lebih lama, yang berfungsi di Haijun API, Amazon Bedrock, dan Google Cloud |
Mengubah output_config.effort tingkat atas (memulai ulang cache, tidak memengaruhi pemikiran) | output_config per pesan | mid-conversation-output-config-2026-07-01 |
| Membuang atau meringkas giliran lama di sisi klien | Compaction sesuai permintaan untuk mempertahankan giliran terbaru beserta pemikirannya, compaction atau pengeditan konteks sisi server lainnya, atau compaction sisi klien yang tidak mempertahankan pemikiran usang | compact-2026-09-04 |
| URL gambar atau dokumen yang byte-nya berubah di antara permintaan | file_id dari Files API, atau base64 | Tidak ada |
Semua ini mengasumsikan Anda mengirim kembali giliran asisten persis seperti yang dikembalikan. Pesan sistem di tengah percakapan, pesan sistem cakupan giliran, dan perubahan alat tidak tersedia di setiap model: Pesan sistem dan perubahan alat di tengah percakapan mencantumkan model yang menerimanya. Jika kode Anda melayani beberapa model, tetap edit prompt system tingkat atas untuk model yang tidak menerimanya.
Untuk menggunakan beberapa beta dalam satu permintaan, gabungkan nilainya dalam satu header juglow-beta. Nama beta sama di Amazon Bedrock dan Google Cloud di mana pun beta tersebut tersedia di sana (lihat Header beta):
juglow-beta: thinking-binding-controls-2026-08-01,mid-conversation-system-clear-at-2026-08-21,inline-tools-2026-09-15Kirim kembali giliran asisten persis seperti yang dikembalikan
Simpan array content dari setiap respons dan kirim kembali tanpa perubahan sebagai giliran asisten: setiap jenis blok, dalam urutan saat diterima, termasuk blok thinking yang field thinking-nya kosong. Serializer yang membuang jenis blok yang tidak dikenal, membuang field kosong, atau mengurutkan ulang blok akan mengedit prefiks untuk setiap giliran berikutnya.
Pada Haijun Fable 5.1, field thinking kosong secara default dan signature membawa penalaran, sehingga serializer yang melewati blok kosong akan menghapus pemikiran. Jika serializer menghapus semuanya, tidak ada yang gagal dan model kehilangan penalaran sebelumnya pada setiap giliran. Jika Anda mem-parsing stream sendiri, pertahankan blok tersebut bahkan ketika tidak ada teks pemikiran yang tiba: blok dibuka, menerima signature-nya dalam event signature_delta, lalu ditutup. Blok yang dikirim kembali dengan signature kosong akan gagal.
Menambahkan instruksi dengan pesan sistem di tengah percakapan
Beberapa harness menyusun ulang prompt system tingkat atas pada setiap permintaan untuk membawa waktu saat ini, anggaran token, flag mode, atau konteks proyek yang baru ditemukan. Hal itu membuat setiap blok pemikiran dalam percakapan menjadi tidak valid. Sebagai gantinya, bekukan system di awal sesi. Ketika sesuatu berubah, tambahkan pesan role: "system" pada titik di messages tempat perubahan tersebut mulai berlaku:
{
"role": "system",
"content": "The user switched the workspace to read-only mode. Do not write files until told otherwise."
}Model memperlakukan pesan ini dengan otoritas prompt sistem, dan semua yang ada sebelumnya tetap tidak berubah. Dalam loop alat, tempatkan pesan setelah pesan pengguna tool_result, jangan pernah di antara tool_use asisten dan tool_result-nya (lihat Batasan). Setelah dikirim, pesan tersebut menjadi bagian dari prefiks untuk pemikiran berikutnya: biarkan di tempatnya pada permintaan berikutnya.
Menaruh konteks yang berubah di giliran terbaru
Beberapa harness menaruh blok lingkungan di pesan pengguna pertama (direktori kerja, branch, tanggal, memori, instruksi proyek) dan merendernya lagi pada setiap permintaan. Ketika nilai apa pun berubah, messages[0] berubah, dan setiap blok pemikiran dalam percakapan menjadi tidak valid. Render blok tersebut sekali dan kirim ulang apa adanya. Ketika sebuah nilai berubah, sampaikan di giliran terbaru: tambahkan blok teks ke pesan pengguna yang akan Anda kirim, atau tambahkan pesan sistem di tengah percakapan jika perubahan tersebut berasal dari Anda sebagai operator.
{
"role": "user",
"content": [
{
"type": "text",
"text": "Environment update: the current branch is now release-2."
},
{ "type": "text", "text": "Run the tests again." }
]
}Setelah dikirim, blok teks tersebut menjadi bagian dari prefiks untuk pemikiran berikutnya: biarkan di tempatnya pada permintaan berikutnya.
Kirim pengingat per giliran sebagai pesan sistem bercakupan giliran
Edit prefiks yang umum adalah dorongan per giliran: baris seperti "request independent reads together" atau "you haven't updated the user in a while" yang ditambahkan kode Anda setelah setiap batch hasil alat. Agar pengingat tidak menumpuk, kirim setiap dorongan sebagai pesan sistem di tengah percakapan dengan clear_at: "next_user_message", yang ditempatkan setelah pesan pengguna tool_result. clear_at memerlukan header beta mid-conversation-system-clear-at-2026-08-21. Array messages berikut adalah permintaan setelah dua panggilan alat beserta hasilnya. messages[3] adalah dorongan dari permintaan sebelumnya, yang dibiarkan di tempatnya, dan messages[6] adalah salinan untuk permintaan ini:
[
{ "role": "user", "content": "Fix the failing test." },
{
"role": "assistant",
"content": [
{ "type": "thinking", "thinking": "", "signature": "..." },
{
"type": "tool_use",
"id": "toolu_01",
"name": "read_file",
"input": { "path": "tests/test_auth.py" }
}
]
},
{
"role": "user",
"content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "..." }]
},
{
"role": "system",
"clear_at": "next_user_message",
"content": "Request every independent read in one turn."
},
{
"role": "assistant",
"content": [
{ "type": "thinking", "thinking": "", "signature": "..." },
{
"type": "tool_use",
"id": "toolu_02",
"name": "read_file",
"input": { "path": "src/auth.py" }
}
]
},
{
"role": "user",
"content": [{ "type": "tool_result", "tool_use_id": "toolu_02", "content": "..." }]
},
{
"role": "system",
"clear_at": "next_user_message",
"content": "Request every independent read in one turn."
}
]Pesan pengguna yang hanya berisi blok tool_result dihitung sebagai "next user message", sehingga messages[3] sudah dibersihkan. Pesan tersebut tidak menambahkan apa pun pada apa yang dilihat model dan tidak memakan token input, tetapi karena masih ada dalam array, pemikiran di messages[4] tetap valid. messages[6] adalah salinan yang dilihat model pada giliran ini. Pada permintaan berikutnya, pertahankan keduanya di tempatnya dan tambahkan salinan baru setelah pesan tool_result berikutnya.
Menambahkan atau menghapus alat dengan tool_addition dan tool_removal
Mengedit array tools di tengah sesi membuat blok pemikiran yang dipertahankan menjadi tidak valid. Biarkan array tersebut seperti saat pertama kali Anda mengirimkannya. Untuk mengubah alat yang dapat digunakan model, tambahkan pesan role: "system" yang membawa blok tool_addition atau tool_removal. Ini adalah perubahan alat di tengah percakapan dan memerlukan header beta inline-tools-2026-09-15, yang tersedia di Haijun API. Header lama mid-conversation-tool-changes-2026-07-01 masih berfungsi untuk perubahan yang menyebut alat berdasarkan referensi, di Haijun API, Amazon Bedrock, dan Google Cloud.
Anda memiliki dua cara untuk menggunakan blok-blok ini:
- Deklarasikan setiap alat di awal. Taruh setiap alat yang mungkin dibutuhkan sesi di
toolspada permintaan pertama, dengandefer_loading: truepada alat yang belum boleh dilihat model. Kemudian aktifkan dan nonaktifkan alat dengan bloktool_additiondantool_removalyang menyebutkan namanya.
- Mulai dengan snapshot dan tambahkan alat seiring berjalannya sesi. Taruh alat yang Anda ketahui di
toolspada permintaan pertama. Ketika alat baru muncul, definisikan alat tersebut di dalam bloktool_additionalih-alih mengedittools.
Dengan cara mana pun, tools tidak pernah berubah, sehingga pemikiran sebelumnya tetap valid dan cache prompt tetap hit, dengan satu pengecualian yang dicatat di bawah.
Misalnya, untuk menarik alat berbahaya setelah peralihan mode:
{
"role": "system",
"content": [
{ "type": "tool_removal", "tool": { "type": "tool_reference", "name": "delete_branch" } },
{ "type": "text", "text": "Branch deletion is disabled for the rest of this session." }
]
}Untuk mengaktifkan alat yang Anda deklarasikan dengan defer_loading: true, tambahkan blok tool_addition yang menyebutkan namanya:
{
"role": "system",
"content": [
{ "type": "tool_addition", "tool": { "type": "tool_reference", "name": "deploy" } },
{ "type": "text", "text": "Authentication succeeded. Deployment is now available." }
]
}Terkadang Anda tidak dapat mendeklarasikan alat di awal karena Anda belum mengetahui skemanya: alat yang ditemukan aplikasi Anda saat runtime, atau server MCP yang terhubung setelah giliran pertama. Definisikan alat tersebut di dalam blok tool_addition alih-alih menyentuh tools. Dengan inline-tools-2026-09-15, tool pada blok dapat berupa {"type": "tool_definition", "definition": {...}}, yang membawa entri yang sama dengan yang akan Anda taruh di tools:
{
"role": "system",
"content": [
{
"type": "tool_addition",
"tool": {
"type": "tool_definition",
"definition": {
"name": "db_query",
"description": "Run a read-only SQL query against the analytics database.",
"input_schema": {
"type": "object",
"properties": { "sql": { "type": "string" } },
"required": ["sql"]
}
}
}
}
]
}Alat baru tiba di messages, tools tidak pernah berubah, dan pemikiran sebelumnya tetap valid. Pertahankan setidaknya satu alat tanpa defer_loading: true di tools: jika setiap alat di sana ditangguhkan, alat pertama yang Anda definisikan dengan cara ini akan menyebabkan satu cache miss prompt penuh.
Jika API terhubung ke server MCP untuk Anda melalui konektor MCP, kirim juga mcp-client-2026-09-15. Header ini mencakup semua yang dilakukan mcp-client-2025-11-20, jadi kirimkan header ini sebagai pengganti header tersebut. definition pada blok kemudian dapat berupa mcp_toolset untuk server yang tercantum di mcp_servers. Ketika API harus mengambil daftar alat sebuah server, respons dimulai dengan blok mcp_tool_listing untuk server tersebut. Kirim kembali blok itu tanpa perubahan bersama sisa giliran asisten, dan tetap kirim mcp-client-2026-09-15 pada setiap permintaan berikutnya yang membawanya. Blok tersebut mengunci toolset ke daftar itu, sehingga API tidak menghubungi server lagi untuk toolset tersebut. Fitur konektor MCP ini tersedia di Haijun API.
Dengan hanya header yang lebih lama, Anda masih dapat menambahkan alat yang Anda ketahui di tengah sesi ke tools dengan defer_loading: true, lalu menawarkannya dengan blok tool_addition. Itu aman karena pemeriksaan prefiks mengabaikan alat yang ditangguhkan hingga blok tool_addition mereferensikannya. Menambahkan alat tanpa defer_loading: true mengubah prefiks dan membuat pemikiran sebelumnya tidak valid.
Pesan role: "system" yang membawa blok-blok ini menjadi bagian dari prefiks untuk pemikiran berikutnya. Biarkan pesan tersebut di tempatnya pada permintaan berikutnya.
Mengubah effort dengan output_config per pesan
Mengubah output_config.effort tingkat atas di antara permintaan tidak membuat pemikiran menjadi tidak valid, karena "effort" (tingkat upaya) bukan bagian dari prefiks. Namun, mengubah effort tingkat atas memang memulai ulang cache prompt. Pada Haijun Fable 5.1, gunakan effort per pesan sebagai gantinya: tambahkan pesan role: "system" dengan content kosong dan level yang baru. Ini memerlukan header beta mid-conversation-output-config-2026-07-01.
{ "role": "system", "content": [], "output_config": { "effort": "low" } }Level baru berlaku mulai giliran user berikutnya. Setelah dikirim, pesan tersebut menjadi bagian dari messages dan karenanya bagian dari prefiks untuk pemikiran berikutnya: biarkan di tempatnya pada permintaan berikutnya, dan tambahkan pesan lain untuk mengubah effort lagi.
Memangkas konteks di server
Edit prefiks umum lainnya adalah pemangkasan sisi klien: membuang atau meringkas giliran terlama dan mempertahankan giliran terbaru secara verbatim. Blok pemikiran dari giliran yang dipertahankan dihasilkan saat riwayat yang dihapus masih ada, sehingga blok tersebut gagal dalam pemeriksaan. Padanan sisi server tidak dihitung sebagai edit, karena pemeriksaan membandingkan percakapan sebagaimana yang Anda kirim:
- Compaction sesuai permintaan (beta) mengembalikan ringkasan dari permintaan terpisah, yang dapat berjalan di latar belakang. Anda lalu mengirim blok yang dikembalikan sebagai pengganti pesan-pesan yang diringkasnya. Pemeriksaan menerima penggantian tersebut, sehingga giliran yang Anda pertahankan dapat tetap valid beserta pemikirannya, selama memenuhi syarat agar pemikiran yang disimpan tetap valid. Meminta ringkasan menunjukkan permintaannya dan menyebutkan header beta yang diperlukan.
- Compaction pada ambang batas token meringkas giliran lama menjadi blok compaction saat konteks mendekati ambang yang Anda tetapkan. Prefiks yang diperiksa kemudian dimulai ulang dari blok tersebut. Parameter
instructionsmiliknya menerima prompt peringkasan Anda sendiri, seperti "pertahankan setiap ticker, ukuran posisi, dan asumsi yang dinyatakan".
- Pengeditan konteks menghapus hasil alat lama atau blok pemikiran lama berdasarkan aturan, dimulai dari yang paling lama. Strateginya adalah
clear_tool_uses_20250919danclear_thinking_20251015.
Lakukan compaction di sisi klien
Anda tetap dapat melakukan compaction di klien. Jika Anda menulis ringkasannya sendiri, jangan kirim kembali blok thinking yang dihasilkan sebelum penulisan ulang. Jika API yang menulisnya dengan compaction sesuai permintaan, Syarat agar pemikiran yang disimpan tetap valid menjelaskan kapan thinking yang dipertahankan tetap valid.
Compaction sederhana (direkomendasikan)
Ketika percakapan menjadi terlalu panjang, ringkas seluruh sesi menjadi satu pesan pengguna dan kirim hanya pesan tersebut beserta instruksi berikutnya. Tidak ada bagian sebelumnya yang diputar ulang, sehingga tidak ada thinking tersisa yang dapat gagal dalam pemeriksaan, dan model bernalar dari awal berdasarkan ringkasan.
[
{
"role": "user",
"content": "<summary of the session so far>\n\n<the next instruction>"
}
]Model Haijun dilatih pada tugas jangka panjang dengan skema ini, dan untuk sebagian besar beban kerja, skema ini berkinerja baik.
Compaction keep-tail
Compaction keep-tail meringkas giliran-giliran lama dan mempertahankan giliran terbaru secara verbatim, sehingga model tetap melihat beberapa pertukaran terakhir kata demi kata. Jika Anda menulis ringkasannya sendiri, cara ini melanggar aturan: giliran asisten yang dipertahankan masih membawa blok thinking yang dihasilkan ketika yang mendahuluinya adalah giliran asli, bukan ringkasan. Blok-blok tersebut gagal.
Untuk mempertahankan thinking tersebut, biarkan API menulis ringkasannya dengan compaction sesuai permintaan. Compaction yang mempertahankan giliran terbaru menunjukkan caranya. Syarat agar pemikiran yang disimpan tetap valid menjelaskan kapan thinking yang dipertahankan tetap valid.
Sisa bagian ini membahas ringkasan yang Anda tulis sendiri.
Perbaikan: pertahankan giliran persis seperti adanya dan kirim prefix_mismatch_behavior: "drop_block". API membuang blok thinking yang usang, model membaca blok text dan tool_use dari giliran yang dipertahankan, dan permintaan berhasil.
Teruskan riwayat yang telah dipadatkan sebagai messages dan atur block_binding pada konfigurasi thinking. Dalam contoh berikut, compacted_messages adalah array yang dihasilkan oleh langkah compaction Anda: pesan ringkasan diikuti oleh giliran yang dipertahankan persis seperti yang dikembalikan API, termasuk blok thinking:
curl https://haijun.my.id/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: thinking-binding-controls-2026-08-01" \
-d "{
\"model\": \"haijun-fable-5-1\",
\"max_tokens\": 16000,
\"thinking\": {
\"type\": \"adaptive\",
\"block_binding\": { \"prefix_mismatch_behavior\": \"drop_block\" }
},
\"messages\": $COMPACTED_MESSAGES
}" ant beta:messages create --beta thinking-binding-controls-2026-08-01 <<YAML
model: haijun-fable-5-1
max_tokens: 16000
thinking:
type: adaptive
block_binding:
prefix_mismatch_behavior: drop_block
messages: $COMPACTED_MESSAGES
YAML client = juglow.Juglow()
# compacted_messages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
response = client.beta.messages.create(
model="haijun-fable-5-1",
max_tokens=16000,
thinking={
"type": "adaptive",
"block_binding": {"prefix_mismatch_behavior": "drop_block"},
},
messages=compacted_messages,
betas=["thinking-binding-controls-2026-08-01"],
)
print(response.input_transformations) const client = new Juglow();
// compactedMessages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
const response = await client.beta.messages.create({
model: "haijun-fable-5-1",
max_tokens: 16000,
thinking: {
type: "adaptive",
block_binding: { prefix_mismatch_behavior: "drop_block" }
},
messages: compactedMessages,
betas: ["thinking-binding-controls-2026-08-01"]
});
console.log(response.input_transformations); JuglowClient client = new();
// compactedMessages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
var response = await client.Beta.Messages.Create(
new()
{
Model = "haijun-fable-5-1",
MaxTokens = 16000,
Thinking = new BetaThinkingConfigAdaptive
{
BlockBinding = new()
{
PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.DropBlock,
},
},
Messages = compactedMessages,
Betas = [JuglowBeta.ThinkingBindingControls2026_08_01],
}
);
Console.WriteLine(response.InputTransformations?.Count ?? 0); client := juglow.NewClient()
// compactedMessages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
response, err := client.Beta.Messages.New(context.TODO(), juglow.BetaMessageNewParams{
Model: "haijun-fable-5-1",
MaxTokens: 16000,
Thinking: juglow.BetaThinkingConfigParamUnion{
OfAdaptive: &juglow.BetaThinkingConfigAdaptiveParam{
BlockBinding: juglow.BetaThinkingBlockBindingParam{
PrefixMismatchBehavior: juglow.BetaThinkingPrefixMismatchBehaviorDropBlock,
},
},
},
Messages: compactedMessages,
Betas: []juglow.JuglowBeta{juglow.JuglowBetaThinkingBindingControls2026_08_01},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(len(response.InputTransformations)) import com.juglow.models.beta.JuglowBeta;
import com.juglow.models.beta.messages.BetaMessage;
import com.juglow.models.beta.messages.BetaThinkingBlockBinding;
import com.juglow.models.beta.messages.BetaThinkingConfigAdaptive;
import com.juglow.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
import com.juglow.models.beta.messages.MessageCreateParams;
void main() {
JuglowClient client = JuglowOkHttpClient.fromEnv();
// compactedMessages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
MessageCreateParams params = MessageCreateParams.builder()
.model("haijun-fable-5-1")
.maxTokens(16000L)
.thinking(BetaThinkingConfigAdaptive.builder()
.blockBinding(BetaThinkingBlockBinding.builder()
.prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.DROP_BLOCK)
.build())
.build())
.messages(compactedMessages)
.addBeta(JuglowBeta.THINKING_BINDING_CONTROLS_2026_08_01)
.build();
BetaMessage response = client.beta().messages().create(params);
IO.println(response.inputTransformations());
} use Juglow\Beta\JuglowBeta;
use Juglow\Beta\Messages\BetaThinkingBlockBinding;
use Juglow\Beta\Messages\BetaThinkingConfigAdaptive;
use Juglow\Beta\Messages\BetaThinkingPrefixMismatchBehavior;
use Juglow\Client;
$client = new Client();
// $compactedMessages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
$response = $client->beta->messages->create(
model: 'haijun-fable-5-1',
maxTokens: 16000,
thinking: BetaThinkingConfigAdaptive::with(
blockBinding: BetaThinkingBlockBinding::with(
prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::DROP_BLOCK,
),
),
messages: $compactedMessages,
betas: [JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01],
);
var_dump($response->inputTransformations); client = Juglow::Client.new
# compacted_messages: pesan ringkasan, lalu giliran yang dipertahankan sesuai yang dikembalikan
response = client.beta.messages.create(
model: "haijun-fable-5-1",
max_tokens: 16_000,
thinking: {
type: "adaptive",
block_binding: {prefix_mismatch_behavior: "drop_block"}
},
messages: compacted_messages,
betas: [Juglow::JuglowBeta::THINKING_BINDING_CONTROLS_2026_08_01]
)
puts response.input_transformationsRespons membawa giliran asisten baru seperti biasa, ditambah satu entri input_transformations untuk setiap blok yang dibuang. Untuk riwayat dalam diagram, itu adalah thinking pada giliran asisten 3 dan 4:
{
"input_transformations": [
{
"type": "thinking_dropped",
"path": "messages.2.content.0",
"reason": "prefix_binding_mismatch"
},
{
"type": "thinking_dropped",
"path": "messages.4.content.0",
"reason": "prefix_binding_mismatch"
}
]
}Terus kirim "drop_block" pada permintaan berikutnya selama kedua giliran tersebut masih berada dalam riwayat. Thinking yang dihasilkan model mulai dari permintaan ini dan seterusnya mengikuti ringkasan dan tetap valid. Jika Anda lebih memilih untuk tidak bergantung pada header beta, alternatifnya adalah menghapus sendiri blok thinking dan redacted_thinking dari giliran asisten yang dipertahankan saat Anda membangun riwayat yang dipadatkan.
Compaction latar belakang (async)
Compaction latar belakang menyusun ringkasan di luar jalur kritis selagi percakapan berlanjut, lalu menggantikannya beberapa permintaan kemudian. Untuk mempertahankan thinking yang dihasilkan selama itu, biarkan API menulis ringkasannya dengan compaction sesuai permintaan. Compaction di latar belakang berisi langkah-langkahnya. Thinking tersebut tetap valid dengan syarat agar pemikiran yang disimpan tetap valid yang sama seperti giliran terbaru yang dipertahankan.
Ringkasan yang Anda bangun sendiri melanggar aturan dengan cara yang sama seperti keep-tail, hanya saja tertunda: setiap giliran asisten yang dihasilkan selama ringkasan sedang dibangun membawa thinking yang mendahului penukaran, dan semuanya gagal begitu ringkasan diterapkan. Jika Anda menggunakannya, perlakukan penukaran seperti keep-tail dan kirim "drop_block" sejak penukaran dan seterusnya, atau lakukan compaction secara sinkron.
Pola yang tidak berfungsi dengan preserved thinking
- Memotong giliran dari bagian tengah. Menghapus giliran individual membuat setiap blok thinking setelahnya menjadi tidak valid, dan tidak ada skema compaction yang dapat menghindarinya. Jika Anda memotong giliran untuk mengubah instruksi, tambahkan pesan sistem di tengah percakapan sebagai gantinya. Untuk menghapus hasil alat lama atau thinking lama secara selektif, gunakan pengeditan konteks di sisi server.
- Melakukan compaction di tengah putaran alat. Jangan lakukan compaction di antara
tool_usepada giliran asisten dantool_resultyang menjawabnya. Kirim kembali giliran asisten tersebut dengan thinking-nya utuh agar model menyelesaikan putaran tersebut dengan penalarannya. Lihat Mempertahankan blok thinking.
Referensikan file berdasarkan ID, bukan berdasarkan URL yang kontennya berubah
Untuk blok image atau document dengan sumber url, pemeriksaan mencakup byte yang diambil, bukan string URL. URL yang kontennya berubah membuat thinking berikutnya tidak valid: misalnya endpoint "tangkapan layar terbaru", atau dokumen yang diedit seseorang di antara giliran. URL bertanda tangan yang berganti-ganti untuk file yang sama tidak menimbulkan masalah. Untuk konten yang Anda referensikan di beberapa giliran, unggah sekali dengan Files API dan gunakan file_id, atau kirim dalam base64.
Library, proxy, dan gateway
Library, proxy, atau gateway berada di antara riwayat milik pihak lain dan API, sehingga penulisan ulang yang dilakukannya dihitung sebagai edit, dan penggunanya tidak dapat melihat atau memperbaikinya.
- Teruskan apa yang tidak Anda kenali. Teruskan nilai
juglow-betadanthinking.block_bindingdari pemanggil tanpa perubahan, dan kembalikaninput_transformationskepada mereka. Skema opsi yang menolak key yang tidak dikenal akan menghalangi pengguna Anda memilih"drop_block".
- Biarkan pesan
role: "system"di tempat pemanggil meletakkannya. Memindahkannya ke fieldsystemtingkat atas akan mengubahsystempada permintaan tersebut dan membuat setiap blok thinking dalam percakapan menjadi tidak valid.
- Untuk menonaktifkan penggunaan alat pada suatu permintaan, kirim
tool_choice: {"type": "none"}. Jangan hapustools.
- Jangan sembunyikan error 400. Jika kode Anda menangkapnya, menghapus thinking, dan mencoba ulang atas nama pemanggil, catat bahwa hal itu dilakukan: riwayat mereka tetap teredit, dan model kehilangan penalaran sebelumnya pada setiap permintaan berikutnya.
FAQ
#### Apakah saya memerlukan akun baru untuk menguji preserved thinking?
Tidak. Kirim header beta thinking-binding-controls-2026-08-01 dan atur thinking.block_binding.prefix_mismatch_behavior. Mengatur field ini membuat permintaan tersebut ikut dalam penegakan pemeriksaan, berapa pun usia akun Anda. "error" menolak riwayat yang diedit dengan error 400 yang sama seperti yang diterima akun baru. "drop_block" meloloskan permintaan dan mencantumkan apa yang dibuang di input_transformations. Untuk menemukan edit prefiks dari akun lama tanpa menegakkan pemeriksaan, kirim header tersebut dan biarkan field tidak diatur. Blok yang gagal tetap sampai ke model, dan input_transformations mencantumkannya sebagai thinking_mismatch_allowed. Lihat Periksa apakah kode Anda mengedit prefiks.
#### Jika ada yang berubah sebelum blok thinking, bahkan satu deskripsi alat, apakah percakapan menjadi tidak dapat digunakan?
Tidak. Yang gagal adalah thinking yang sudah ada dalam riwayat setelah titik yang Anda ubah, dan Anda yang memilih apa yang terjadi padanya. Dengan prefix_mismatch_behavior: "drop_block", API membuang blok-blok tersebut dan permintaan berhasil: model menjawab giliran itu tanpa penalaran tersebut, dan caching prompt dimulai ulang dari titik edit. Dengan nilai default "error", API menolak permintaan dengan error 400 hingga Anda membatalkan edit atau mengirim ulang dengan "drop_block". Lihat Apa yang dilakukan API terhadap blok yang tidak valid. Apa yang dihitung sebagai edit mencantumkan perubahan mana yang berpengaruh.
#### Apakah mengubah effort atau pengaturan thinking lainnya di antara permintaan membuat thinking sebelumnya tidak valid?
Tidak. output_config.effort, max_tokens, dan konfigurasi thinking bukan bagian dari prefiks yang diperiksa, yang hanya mencakup system, tools, dan messages. Perubahan effort di tingkat atas membuat sebagian besar cache untuk prompt menjadi tidak valid. Pada Haijun Fable 5.1, perubahan effort per pesan mempertahankan cache untuk prompt dan digunakan sebagai tingkat effort baru hingga diubah lagi.
#### Daftar alat saya berubah di tengah sesi. Bagaimana cara menghindari percakapan menjadi tidak valid?
Jangan edit tools. Deklarasikan set lengkap di awal sesi, tandai alat yang belum tersedia dengan defer_loading: true, lalu tawarkan atau tarik kembali alat tersebut dengan blok tool_addition dan tool_removal. Jika Anda baru mengetahui skema suatu alat di tengah sesi, definisikan alat tersebut di dalam blok tool_addition (inline-tools-2026-09-15, ditambah mcp-client-2026-09-15 untuk server yang dijangkau konektor MCP milik API) dan biarkan tools tidak berubah. Pesan role: "system" yang membawa blok-blok ini menjadi bagian dari prefiks untuk thinking berikutnya, jadi jangan pindahkan, ubah kata-katanya, atau hapus pesan tersebut setelahnya. Lihat Menambah atau menghapus alat dengan tool_addition dan tool_removal.
#### Saya melakukan compaction dengan meringkas giliran lama dan mempertahankan giliran terbaru secara verbatim. Apakah itu masih berfungsi?
Ya, jika API yang menulis ringkasannya. Compaction sesuai permintaan (header beta compact-2026-09-04) meringkas giliran lama menjadi blok bertanda tangan yang Anda kirim sebagai penggantinya. Giliran terbaru mempertahankan thinking-nya selama memenuhi syarat agar pemikiran yang disimpan tetap valid.
Jika Anda menulis ringkasannya sendiri, thinking pada giliran yang dipertahankan gagal dalam pemeriksaan, karena blok-blok tersebut dihasilkan berdasarkan riwayat yang Anda ganti. Hapus blok thinking dan redacted_thinking dari giliran yang Anda bawa dan pertahankan blok text dan tool_use-nya, atau kirim prefix_mismatch_behavior: "drop_block" dan biarkan API membuangnya. Compaction sederhana tidak meninggalkan thinking yang dapat gagal dan merupakan pendekatan yang direkomendasikan: satu pesan ringkasan ditambah giliran pengguna berikutnya, tanpa memutar ulang giliran sebelumnya. Compaction dan pengeditan konteks di sisi server tidak dihitung sebagai edit. Lihat Lakukan compaction di sisi klien.
#### Bagaimana cara menangani file instruksi seperti AGENTS.md atau HAIJUN.md yang berubah di tengah sesi?
Muat file tersebut sekali di awal sesi dan pertahankan prompt system tingkat atas serta tools tetap. Ketika sebuah file berubah, tambahkan versi barunya pada titik tersebut di messages alih-alih mengedit yang asli. Gunakan pesan sistem di tengah percakapan untuk instruksi yang berasal dari Anda sebagai operator. Untuk teks file yang Anda anggap tidak tepercaya, yang tidak seharusnya memiliki otoritas prompt sistem, letakkan kontennya di giliran user berikutnya. Lihat Menambahkan instruksi dengan pesan sistem di tengah percakapan dan Batasan.
#### Dapatkah saya melanjutkan sesi yang tersimpan nanti, setelah restart atau keesokan harinya?
Ya. Sesi yang dilanjutkan adalah permintaan lanjutan biasa: system, tools, dan messages sebelumnya harus memiliki konten yang sama dengan yang terakhir Anda kirim. Format JSON dan urutan key tidak berpengaruh; nilainya yang berpengaruh. Simpan persis apa yang Anda kirim dan terima, lalu putar ulang itu: prompt sistem yang telah dirender, definisi alat, dan setiap giliran asisten seperti yang dikembalikan. Jangan merender ulang dari input yang mungkin telah berubah sejak saat itu, seperti tanggal, file instruksi yang diperbarui, atau versi alat yang baru. Apa pun yang baru dimasukkan ke dalam pesan yang ditambahkan. Lihat Kirim kembali giliran asisten persis seperti yang dikembalikan.
#### Sesi yang tersimpan sekarang gagal pada setiap permintaan. Bagaimana cara membuatnya berfungsi kembali?
Riwayat yang tersimpan mengandung edit, sehingga memutarnya ulang tidak akan berhasil. Kirim sesi tersebut dengan prefix_mismatch_behavior: "drop_block" mulai sekarang, atau hapus blok thinking dan redacted_thinking-nya sekali lalu lanjutkan. Thinking yang dihasilkan model sejak titik itu tetap valid selama tidak ada yang berubah lagi sebelumnya. Kemudian temukan edit tersebut agar sesi baru tidak mengalaminya. Lihat Menangani error dalam kode.
#### Harness saya dapat merutekan giliran ke model non-Haijun. Apakah giliran tersebut membuat thinking Haijun sebelumnya tidak valid?
Tidak, asalkan giliran tersebut ditambahkan setelah riwayat yang ada dan tidak ada yang berubah sebelumnya: pesan asisten tanpa blok thinking adalah pesan tambahan seperti pesan lainnya. Kirim output model lain sebagai konten text dan tool_use.
#### Dapatkah saya membawa penalaran suatu percakapan ke percakapan baru?
Tidak ke percakapan yang berbeda. Blok thinking hanya dapat digunakan ketika mengikuti system, tools, dan messages yang persis sama dengan yang menghasilkannya. Cabang yang memutar ulang riwayat tersebut tanpa perubahan hingga titik percabangan mempertahankan thinking-nya. Percakapan yang dimulai dari hal lain tidak dapat menggunakannya, jadi mulailah percakapan tersebut dari ringkasan status tugas, seperti pada compaction sederhana: tujuan, keputusan yang telah dibuat, file dan hasil sejauh ini, serta langkah berikutnya.
Langkah selanjutnya
Diagnosis dan perbaiki kegagalan thinking yang paling umum: error 400 konfigurasi, blok thinking kosong atau hilang, penghentian max\_tokens, dan cache miss.
Ubah instruksi sistem atau ketersediaan alat di tengah percakapan tanpa membatalkan validitas prefiks yang di-cache sebelumnya.
Compaction konteks sisi server untuk mengelola percakapan panjang yang mendekati batas jendela konteks.
Cache prefiks prompt dengan cache_control untuk memangkas biaya dan latensi, menggunakan caching otomatis atau breakpoint eksplisit dengan TTL 5 menit atau 1 jam.