summaryrefslogtreecommitdiff
path: root/docs/archive/anthropic-thinking-plan.md
blob: 7577647c0c622c43b68bf59104d6fcb80809d641 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Anthropic Thinking Support — Implementation Plan

## Overview

Add `Thinking`, `Effort`, `thinking_budget_tokens`, and `thinking_interleaved`
fields to `AnthropicMessagesConfig` and wire them through to the Anthropic
Messages API. OpenAI config is unchanged.

## Design decisions

- `Thinking = .enabled` by default (compatible with all current models incl. Haiku 4.5)
- `Effort = .medium` by default (only used when `thinking = .adaptive`)
- `thinking_budget_tokens: ?u32 = 32_000` (quality/cost shoulder per Anthropic docs; ignored when adaptive)
- `thinking_interleaved: bool = false` (requires explicit opt-in; beta header 400s on unsupported models)
- Always send `display: "summarized"` to get visible thinking text in all modes
- `effort` is only emitted when `thinking == .adaptive`
- `budget_tokens` uses `thinking_budget_tokens orelse (max_tokens - 1)` when `.enabled` without interleaving
- `interleaved-thinking-2025-05-14` beta header only sent when `thinking == .enabled && thinking_interleaved == true`
- `WireIdentity` for Anthropic extended with thinking/effort/budget/interleaved so sessions with different thinking configs are distinct

---

## Phase 1 — Config types and `AnthropicMessagesConfig` fields ✅ COMPLETE

**Files:** `libpanto/src/config.zig`

- Add `Thinking` enum: `disabled`, `enabled`, `adaptive`
- Add `Effort` enum: `low`, `medium`, `high`, `xhigh`, `max`
- Add fields to `AnthropicMessagesConfig`:
  - `thinking: Thinking = .enabled`
  - `effort: Effort = .medium`
  - `thinking_budget_tokens: ?u32 = 32_000`
  - `thinking_interleaved: bool = false`
- Update `WireIdentity` to include `thinking`, `effort`, `thinking_budget_tokens`,
  `thinking_interleaved` for Anthropic; `wireIdentity()` on Anthropic variant fills them in
- Update tests in `config.zig`

---

## Phase 2 — Wire serialization (`anthropic_messages_json.zig`) ✅ COMPLETE

**Files:** `libpanto/src/anthropic_messages_json.zig`

- In `serializeRequest`, after the system prompt block:
  - `thinking == .disabled` → nothing
  - `thinking == .enabled` → emit `thinking: { type: "enabled", budget_tokens: B, display: "summarized" }`
    where `B = thinking_budget_tokens orelse (max_tokens - 1)`, clamped so `B < max_tokens`
  - `thinking == .adaptive` → emit `thinking: { type: "adaptive", display: "summarized" }` + top-level `effort: "<level>"`
- Add unit tests covering all three modes, budget fallback/clamp, effort gating

---

## Phase 3 — Beta header in provider (`provider_anthropic_messages.zig`) ✅ COMPLETE

**Files:** `libpanto/src/provider_anthropic_messages.zig`

- In `AnthropicMessagesRequest.open`, add `anthropic-beta` header only when
  `config.thinking == .enabled && config.thinking_interleaved == true`
- Value: `"interleaved-thinking-2025-05-14"`
- Add unit test (or update existing open/serialize path test) confirming header presence/absence

---

## Phase 4 — Session persistence ✅ COMPLETE

**Files:** `libpanto/src/session.zig`, `libpanto/src/session_store.zig`,
`libpanto/src/file_system_jsonl_store.zig`, `libpanto/src/null_store.zig`

- Extend the stamp serialization / deserialization in `session.zig` to
  read/write `thinking`, `effort`, `thinking_budget_tokens`, `thinking_interleaved`
  from/to JSONL
- Update `WireIdentity` in `session_store.zig` (distinct from config's) to carry the same fields
- Update `null_store.zig` and `file_system_jsonl_store.zig` default stamps
- Add round-trip tests

---

## Phase 5 — `models.toml` parsing and `buildProviderConfig` ✅ COMPLETE

**Files:** `src/models_toml.zig`, `src/config_file.zig`

- Add Anthropic fields to `ModelDef`: `thinking`, `effort`, `thinking_budget_tokens`, `thinking_interleaved`
- Hand-parse all four from TOML in `ingestModel` (string→enum for thinking/effort, int for budget, bool for interleaved)
- Thread them through `buildProviderConfig` into `AnthropicMessagesConfig`
- Update schema doc comment in `models_toml.zig` and sample config in `src/luarocks_runtime.zig`
- Add parse and buildProviderConfig tests

---

## Phase 6 — Build verification and test run ✅ COMPLETE

- `zig build` clean
- `zig build test` passes (all existing + new tests)
- Smoke-check that the TOML sample in `luarocks_runtime.zig` is valid

---