Skip to content

Commit f46ac66

Browse files
committed
docs(release): document late-merged 0.10 changes before tagging
Two commits landed on main between when the 0.10 release-prep PR was cut and when it merged, but neither updated CHANGELOG nor docs: - 87a3028 feat: synthetic_user_message / is_synthetic_message factories - b8aebc1 feat(providers): drop the "minimal" ThinkingLevel (BREAKING) Without this patch, tagging 0.10.0 ships: - A BREAKING ThinkingLevel change with no CHANGELOG entry or migration note (anyone passing thinking="minimal" gets a silent ValidationError). - A documented "minimal" thinking level in the 0.10 docs snapshot (current/ + version-0.10/, EN + zh-Hans) that the released code rejects. - A new public synthetic-message API with no Chinese docs and no snapshot mention (only EN current/hooks.md was updated in 87a3028). This commit: - CHANGELOG.md: adds [0.10.0] ### Removed (BREAKING) entry for the minimal drop with migration guidance, and ### Added entry for the synthetic factories. - website/docs + zh-Hans current/: strips "minimal" from the providers/ anthropic and providers/overview guides (table row, code samples, prose enumerations). - website/versioned_docs/version-0.10/ + zh-Hans mirror: same strips + mirrors the EN hooks.md synthetic_user_message section into zh-Hans current/ and copies hooks.md into both snapshots. - website/versioned_docs/version-0.10/api/: regenerates the auto- generated API mdx (pnpm apiref) and copies the fresh files into the snapshot so it reflects the actual 0.10.0 surface — ThinkingLevel no longer lists "minimal", synthetic_user_message and is_synthetic_message appear in cubepi-providers.mdx. Verified: diff -r current vs version-0.10 yields only the intro.mdx Status block (expected), no "minimal" remains in any thinking-level context, pnpm build (EN + zh-Hans) clean, vitest 4/4.
1 parent c25946e commit f46ac66

14 files changed

Lines changed: 181 additions & 107 deletions

File tree

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## [0.10.0] - 2026-06-10
1111

12+
### Removed (BREAKING)
13+
14+
- **`"minimal"` removed from `ThinkingLevel`.** `ThinkingLevel` now reads
15+
`Literal["off", "low", "medium", "high", "xhigh"]`; the `.minimal` field
16+
is gone from `ThinkingBudgets`; `THINKING_LEVELS` no longer contains it;
17+
Anthropic's default `level_budgets` and OpenAI Responses' `_THINKING_TO_EFFORT`
18+
no longer map it. **Callers that previously passed `thinking="minimal"`
19+
must switch to `thinking="low"` (or `"off"`).** Rationale: DeepSeek's
20+
Anthropic-shape endpoint rejects `effort=minimal` on `output_config`,
21+
and OpenAI's `reasoning.effort` path rewrote it to `"low"` downstream
22+
anyway — keeping it was a footgun that surfaced as a 400 + fallback.
23+
1224
### Added
1325

26+
- **`synthetic_user_message(text, *, source) -> UserMessage`** and
27+
**`is_synthetic_message(message) -> bool`** — public marker for
28+
framework-injected user-role messages. Middleware-injected nudges
29+
(todo guard errors, goal continuations, compaction summaries,
30+
`generate_structured` retry feedback) now stamp
31+
`metadata["synthetic"] = True` so downstream UIs can tell internal
32+
scaffolding apart from real human input. Real `Agent.prompt()` /
33+
`Agent.steer()` messages remain unmarked. Closes #171. Exported from
34+
`cubepi` and `cubepi.providers`. Use this factory (not bare
35+
`UserMessage`) when returning messages from `TurnAction.inject_messages`
36+
or `on_run_end`.
37+
1438
- **`DeferredToolGroup` / `DeferredToolsMiddleware`** — progressive tool
1539
disclosure primitive. Hides MCP tool schemas from the model by default,
1640
injecting a compact catalog into the system prompt instead. The model

website/docs/guides/providers/anthropic.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ CubePi maps a `ThinkingLevel` enum onto Anthropic's `budget_tokens`:
4949
| Level | Default budget |
5050
|---|---|
5151
| `"off"` | thinking disabled |
52-
| `"minimal"` | 1024 |
5352
| `"low"` | 2048 |
5453
| `"medium"` | 8192 |
5554
| `"high"` | 16384 |
@@ -78,7 +77,7 @@ provider = AnthropicProvider(
7877
reasoning_level=ReasoningLevelSpec(
7978
path="thinking.budget_tokens",
8079
kind="int_budget",
81-
level_budgets={"off": 0, "minimal": 1024, "low": 4096,
80+
level_budgets={"off": 0, "low": 4096,
8281
"medium": 12288, "high": 16384, "xhigh": 16384},
8382
),
8483
),

website/docs/guides/providers/overview.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ provider = OpenAIProvider(
107107

108108
- `reasoning_on_payload / reasoning_off_payload` — payload merged when
109109
reasoning is on/off.
110-
- `reasoning_level` (`ReasoningLevelSpec`) — map `off`/`minimal`/... to backend
110+
- `reasoning_level` (`ReasoningLevelSpec`) — map `off`/`low`/... to backend
111111
payload paths.
112112
- `temperature` (`TemperatureSpec`) — clip, force, or strip temperature.
113113
- `max_tokens_field` — pick `max_tokens` or `max_completion_tokens`.
@@ -225,14 +225,14 @@ the capability value wins.
225225
### Reasoning level: `reasoning_level` (three shapes)
226226

227227
Beyond on/off, CubePi maps a `ThinkingLevel`
228-
(`off`/`minimal`/`low`/`medium`/`high`/`xhigh`) onto a concrete wire value
228+
(`off`/`low`/`medium`/`high`/`xhigh`) onto a concrete wire value
229229
written at a dotted `path`. `kind` picks the shape:
230230

231231
`ReasoningLevelSpec` only changes how that level is serialized. You still need
232232
two call-site controls:
233233

234234
- set `reasoning=True` when binding the model (enable reasoning for that model)
235-
- set the Agent's `thinking` argument to one of `off|minimal|low|medium|high|xhigh`
235+
- set the Agent's `thinking` argument to one of `off|low|medium|high|xhigh`
236236
(defaults to `off`).
237237

238238
```python
@@ -249,7 +249,6 @@ provider = OpenAIProvider(
249249
kind="effort",
250250
level_to_effort={
251251
"off": "low",
252-
"minimal": "low",
253252
"low": "low",
254253
"medium": "medium",
255254
"high": "high",
@@ -268,15 +267,15 @@ from cubepi import ReasoningLevelSpec
268267
# int_budget — a token budget (Anthropic).
269268
ReasoningLevelSpec(
270269
path="thinking.budget_tokens", kind="int_budget",
271-
level_budgets={"off": 0, "minimal": 1024, "low": 2048,
270+
level_budgets={"off": 0, "low": 2048,
272271
"medium": 8192, "high": 16384, "xhigh": 16384},
273272
)
274273

275274
# effort — an effort string (OpenAI Responses).
276275
ReasoningLevelSpec(
277276
path="reasoning.effort", kind="effort",
278-
level_to_effort={"minimal": "minimal", "low": "low",
279-
"medium": "medium", "high": "high", "xhigh": "high"},
277+
level_to_effort={"low": "low", "medium": "medium",
278+
"high": "high", "xhigh": "high"},
280279
)
281280

282281
# enum — a vendor-specific state (Doubao's 3-state thinking).

website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/middleware/hooks.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,22 @@ async def after_model_response(
160160

161161
```python
162162
from cubepi.middleware.base import TurnAction
163-
from cubepi.providers.base import UserMessage, TextContent
163+
from cubepi.providers.base import synthetic_user_message
164164

165165
TurnAction(
166166
response=modified_message, # 替换消息;None 则保留原消息
167-
inject_messages=[UserMessage(...)], # 在下一轮之前追加的额外消息
167+
inject_messages=[ # 在下一轮之前追加的额外消息
168+
synthetic_user_message("", source="my_middleware"),
169+
],
168170
decision="natural", # "natural" | "stop" | "loop_to_model"
169171
)
170172
```
171173

174+
注入的 user 角色消息**必须**`synthetic_user_message(text, source=...)`
175+
构造,不要直接 `UserMessage(...)`。工厂会写入 `metadata["synthetic"] = True`
176+
下游消费者(重放历史的 UI)就能把框架插入的提示和用户真正输入的区分开来;
177+
`source` 是个自由格式标签,只用于 trace。判断可用 `is_synthetic_message(msg)`
178+
172179
三个控制流旋钮:
173180

174181
- `decision="natural"`(默认)—— 正常进入工具执行 / 下一轮。
@@ -194,12 +201,13 @@ async def on_run_end(
194201
...
195202
```
196203

197-
**每次 `prompt()` 调用结束时触发一次**——所有轮次和工具调用完成后、
198-
`AgentEndEvent` 发出前。返回非空 `list[Message]` 会将这些消息注入上下文
199-
并运行**一轮额外的模型调用**(run-end pass)。返回 `None``[]` 不做任何操作。
204+
**每次外层循环迭代后触发**——所有轮次和工具调用完成、循环本应退出之前。
205+
返回非空 `list[Message]` 会将这些消息注入上下文并继续循环(agent 再跑一次)。
206+
返回 `None``[]` 什么也不做(循环退出)。和 `inject_messages` 一样,
207+
返回的 user 角色消息要用 `synthetic_user_message(...)` 构造,让它们带上
208+
synthetic 标记。
200209

201-
额外轮次只触发一次——循环内的 `_reflection_fired` 标志阻止注入轮次再次触发
202-
`on_run_end`
210+
每次 `prompt()`**可以多次触发**。中间件每次返回消息,worker 就再跑一轮。
203211

204212
**何时触发:**
205213
- 正常完成(所有轮次结束后循环自然 break)。

website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/providers/anthropic.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ CubePi 把 `ThinkingLevel` 枚举映射到 Anthropic 的 `budget_tokens`:
4646
| Level | 默认 budget |
4747
|---|---|
4848
| `"off"` | 关闭思考 |
49-
| `"minimal"` | 1024 |
5049
| `"low"` | 2048 |
5150
| `"medium"` | 8192 |
5251
| `"high"` | 16384 |

website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/providers/overview.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ provider = OpenAIProvider(
7272

7373
- `reasoning_on_payload / reasoning_off_payload` — 在 reasoning 开/关时,深度
7474
合并到最终 payload。
75-
- `reasoning_level``ReasoningLevelSpec`)— 将 `off`/`minimal`/... 映射到后端字段。
75+
- `reasoning_level``ReasoningLevelSpec`)— 将 `off`/`low`/... 映射到后端字段。
7676
- `temperature``TemperatureSpec`)— 裁剪、固定或去掉温度参数。
7777
- `max_tokens_field` — 选 `max_tokens``max_completion_tokens`
7878
- `supports_tools` / `supports_images` / `supports_streaming` — 供宿主应用或前端消费的能力元数据。
@@ -161,12 +161,12 @@ CapabilityDescriptor(
161161

162162
### 推理级别:`reasoning_level`(三种形状)
163163

164-
在开/关之外,CubePi 将 `ThinkingLevel``off`/`minimal`/`low`/`medium`/`high`/`xhigh`)映射到通过点路径 `path` 写入的具体 wire 值。`kind` 决定形状:
164+
在开/关之外,CubePi 将 `ThinkingLevel``off`/`low`/`medium`/`high`/`xhigh`)映射到通过点路径 `path` 写入的具体 wire 值。`kind` 决定形状:
165165

166-
`ReasoningLevelSpec` 只负责「`thinking`/`minimal`/`low`/... 具体映射成后端字段」;要真正生效,还要配两个参数:
166+
`ReasoningLevelSpec` 只负责「`thinking`/`low`/... 具体映射成后端字段」;要真正生效,还要配两个参数:
167167

168168
-`provider.model(...)` 时把 `reasoning=True`(把这个模型设为推理模型)
169-
-`Agent(...)` 初始化时把 `thinking` 设成 `off|minimal|low|medium|high|xhigh`(默认 `off`
169+
-`Agent(...)` 初始化时把 `thinking` 设成 `off|low|medium|high|xhigh`(默认 `off`
170170

171171
```python
172172
from cubepi import Agent, CapabilityDescriptor, ReasoningLevelSpec
@@ -181,7 +181,6 @@ provider = OpenAIProvider(
181181
kind="effort",
182182
level_to_effort={
183183
"off": "low",
184-
"minimal": "low",
185184
"low": "low",
186185
"medium": "medium",
187186
"high": "high",
@@ -200,15 +199,15 @@ from cubepi import ReasoningLevelSpec
200199
# int_budget — a token budget (Anthropic).
201200
ReasoningLevelSpec(
202201
path="thinking.budget_tokens", kind="int_budget",
203-
level_budgets={"off": 0, "minimal": 1024, "low": 2048,
202+
level_budgets={"off": 0, "low": 2048,
204203
"medium": 8192, "high": 16384, "xhigh": 16384},
205204
)
206205

207206
# effort — an effort string (OpenAI Responses).
208207
ReasoningLevelSpec(
209208
path="reasoning.effort", kind="effort",
210-
level_to_effort={"minimal": "minimal", "low": "low",
211-
"medium": "medium", "high": "high", "xhigh": "high"},
209+
level_to_effort={"low": "low", "medium": "medium",
210+
"high": "high", "xhigh": "high"},
212211
)
213212

214213
# enum — a vendor-specific state (Doubao's 3-state thinking).

website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.10/guides/middleware/hooks.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,22 @@ async def after_model_response(
160160

161161
```python
162162
from cubepi.middleware.base import TurnAction
163-
from cubepi.providers.base import UserMessage, TextContent
163+
from cubepi.providers.base import synthetic_user_message
164164

165165
TurnAction(
166166
response=modified_message, # 替换消息;None 则保留原消息
167-
inject_messages=[UserMessage(...)], # 在下一轮之前追加的额外消息
167+
inject_messages=[ # 在下一轮之前追加的额外消息
168+
synthetic_user_message("", source="my_middleware"),
169+
],
168170
decision="natural", # "natural" | "stop" | "loop_to_model"
169171
)
170172
```
171173

174+
注入的 user 角色消息**必须**`synthetic_user_message(text, source=...)`
175+
构造,不要直接 `UserMessage(...)`。工厂会写入 `metadata["synthetic"] = True`
176+
下游消费者(重放历史的 UI)就能把框架插入的提示和用户真正输入的区分开来;
177+
`source` 是个自由格式标签,只用于 trace。判断可用 `is_synthetic_message(msg)`
178+
172179
三个控制流旋钮:
173180

174181
- `decision="natural"`(默认)—— 正常进入工具执行 / 下一轮。
@@ -194,12 +201,13 @@ async def on_run_end(
194201
...
195202
```
196203

197-
**每次 `prompt()` 调用结束时触发一次**——所有轮次和工具调用完成后、
198-
`AgentEndEvent` 发出前。返回非空 `list[Message]` 会将这些消息注入上下文
199-
并运行**一轮额外的模型调用**(run-end pass)。返回 `None``[]` 不做任何操作。
204+
**每次外层循环迭代后触发**——所有轮次和工具调用完成、循环本应退出之前。
205+
返回非空 `list[Message]` 会将这些消息注入上下文并继续循环(agent 再跑一次)。
206+
返回 `None``[]` 什么也不做(循环退出)。和 `inject_messages` 一样,
207+
返回的 user 角色消息要用 `synthetic_user_message(...)` 构造,让它们带上
208+
synthetic 标记。
200209

201-
额外轮次只触发一次——循环内的 `_reflection_fired` 标志阻止注入轮次再次触发
202-
`on_run_end`
210+
每次 `prompt()`**可以多次触发**。中间件每次返回消息,worker 就再跑一轮。
203211

204212
**何时触发:**
205213
- 正常完成(所有轮次结束后循环自然 break)。

website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.10/guides/providers/anthropic.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ CubePi 把 `ThinkingLevel` 枚举映射到 Anthropic 的 `budget_tokens`:
4646
| Level | 默认 budget |
4747
|---|---|
4848
| `"off"` | 关闭思考 |
49-
| `"minimal"` | 1024 |
5049
| `"low"` | 2048 |
5150
| `"medium"` | 8192 |
5251
| `"high"` | 16384 |

website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.10/guides/providers/overview.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ provider = OpenAIProvider(
7272

7373
- `reasoning_on_payload / reasoning_off_payload` — 在 reasoning 开/关时,深度
7474
合并到最终 payload。
75-
- `reasoning_level``ReasoningLevelSpec`)— 将 `off`/`minimal`/... 映射到后端字段。
75+
- `reasoning_level``ReasoningLevelSpec`)— 将 `off`/`low`/... 映射到后端字段。
7676
- `temperature``TemperatureSpec`)— 裁剪、固定或去掉温度参数。
7777
- `max_tokens_field` — 选 `max_tokens``max_completion_tokens`
7878
- `supports_tools` / `supports_images` / `supports_streaming` — 供宿主应用或前端消费的能力元数据。
@@ -161,12 +161,12 @@ CapabilityDescriptor(
161161

162162
### 推理级别:`reasoning_level`(三种形状)
163163

164-
在开/关之外,CubePi 将 `ThinkingLevel``off`/`minimal`/`low`/`medium`/`high`/`xhigh`)映射到通过点路径 `path` 写入的具体 wire 值。`kind` 决定形状:
164+
在开/关之外,CubePi 将 `ThinkingLevel``off`/`low`/`medium`/`high`/`xhigh`)映射到通过点路径 `path` 写入的具体 wire 值。`kind` 决定形状:
165165

166-
`ReasoningLevelSpec` 只负责「`thinking`/`minimal`/`low`/... 具体映射成后端字段」;要真正生效,还要配两个参数:
166+
`ReasoningLevelSpec` 只负责「`thinking`/`low`/... 具体映射成后端字段」;要真正生效,还要配两个参数:
167167

168168
-`provider.model(...)` 时把 `reasoning=True`(把这个模型设为推理模型)
169-
-`Agent(...)` 初始化时把 `thinking` 设成 `off|minimal|low|medium|high|xhigh`(默认 `off`
169+
-`Agent(...)` 初始化时把 `thinking` 设成 `off|low|medium|high|xhigh`(默认 `off`
170170

171171
```python
172172
from cubepi import Agent, CapabilityDescriptor, ReasoningLevelSpec
@@ -181,7 +181,6 @@ provider = OpenAIProvider(
181181
kind="effort",
182182
level_to_effort={
183183
"off": "low",
184-
"minimal": "low",
185184
"low": "low",
186185
"medium": "medium",
187186
"high": "high",
@@ -200,15 +199,15 @@ from cubepi import ReasoningLevelSpec
200199
# int_budget — a token budget (Anthropic).
201200
ReasoningLevelSpec(
202201
path="thinking.budget_tokens", kind="int_budget",
203-
level_budgets={"off": 0, "minimal": 1024, "low": 2048,
202+
level_budgets={"off": 0, "low": 2048,
204203
"medium": 8192, "high": 16384, "xhigh": 16384},
205204
)
206205

207206
# effort — an effort string (OpenAI Responses).
208207
ReasoningLevelSpec(
209208
path="reasoning.effort", kind="effort",
210-
level_to_effort={"minimal": "minimal", "low": "low",
211-
"medium": "medium", "high": "high", "xhigh": "high"},
209+
level_to_effort={"low": "low", "medium": "medium",
210+
"high": "high", "xhigh": "high"},
212211
)
213212

214213
# enum — a vendor-specific state (Doubao's 3-state thinking).

0 commit comments

Comments
 (0)