@arcfold/dsh 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -2
  3. package/THIRD_PARTY_NOTICES.md +11 -0
  4. package/cordis.patch.yml +138 -0
  5. package/package.json +70 -4
  6. package/patches/deepseek-0.2.2-rc.1-transport.json +65 -0
  7. package/patches/deepseek-0.2.2-rc.1-transport.patch +61 -0
  8. package/presets/arcfold.patch.yml +110 -0
  9. package/runtime/README.md +19 -0
  10. package/runtime/bootstrap.json +15 -0
  11. package/runtime/desktop-python.tar.gz +0 -0
  12. package/runtime/host/package.json +11 -0
  13. package/runtime/host/pnpm-workspace.yaml +9 -0
  14. package/runtime/initial-policy.json +94 -0
  15. package/runtime/profile/pnpm-workspace.yaml +7 -0
  16. package/scripts/exact-package-patch.mjs +106 -0
  17. package/scripts/patch-deepseek-transport.mjs +14 -0
  18. package/src/agent.mjs +56 -0
  19. package/src/browse-scope.mjs +14 -0
  20. package/src/budget.mjs +369 -0
  21. package/src/business.mjs +334 -0
  22. package/src/context-material.mjs +119 -0
  23. package/src/deepseek-budget-plugin.mjs +58 -0
  24. package/src/deepseek-provider.mjs +57 -0
  25. package/src/deepseek-receipt.mjs +97 -0
  26. package/src/deepseek-transport.mjs +97 -0
  27. package/src/desktop/adapter.mjs +16 -0
  28. package/src/desktop/bootstrap.mjs +84 -0
  29. package/src/desktop/configuration.mjs +117 -0
  30. package/src/desktop/provider.mjs +46 -0
  31. package/src/desktop/python-runtime.mjs +105 -0
  32. package/src/desktop/setup-service.mjs +81 -0
  33. package/src/desktop/vendor/LICENSE.deepseek +21 -0
  34. package/src/desktop/vendor/NOTICE.md +5 -0
  35. package/src/desktop/vendor/deepseek-0.2.2-rc.1.mjs +2919 -0
  36. package/src/evidence-ownership.mjs +51 -0
  37. package/src/evidence.mjs +35 -0
  38. package/src/goal-context.mjs +52 -0
  39. package/src/goal-execution-tool.mjs +74 -0
  40. package/src/goal-execution.mjs +333 -0
  41. package/src/goal-tool.mjs +56 -0
  42. package/src/goal-work-control.mjs +63 -0
  43. package/src/goal-work.mjs +257 -0
  44. package/src/goals.mjs +578 -0
  45. package/src/importer.mjs +298 -0
  46. package/src/index.mjs +53 -0
  47. package/src/learning-contracts.mjs +220 -0
  48. package/src/learning-defaults.mjs +98 -0
  49. package/src/learning-goals.mjs +165 -0
  50. package/src/learning-plugin.mjs +28 -0
  51. package/src/learning-runner.mjs +275 -0
  52. package/src/learning.mjs +534 -0
  53. package/src/legacy-export.mjs +332 -0
  54. package/src/legacy-import-source.mjs +356 -0
  55. package/src/metered-provider-host.mjs +101 -0
  56. package/src/metered-transport.mjs +435 -0
  57. package/src/method-context.mjs +57 -0
  58. package/src/method-lifecycle.mjs +34 -0
  59. package/src/method-tool.mjs +61 -0
  60. package/src/methods.mjs +425 -0
  61. package/src/model-selection.mjs +41 -0
  62. package/src/native-context-call.mjs +88 -0
  63. package/src/native-continuation.mjs +217 -0
  64. package/src/native-request-authority.mjs +90 -0
  65. package/src/openai-models.mjs +4 -0
  66. package/src/openai-receipt.mjs +98 -0
  67. package/src/openai-transport.mjs +167 -0
  68. package/src/openai-usage.mjs +194 -0
  69. package/src/opportunities.mjs +295 -0
  70. package/src/preparation-artifacts.mjs +213 -0
  71. package/src/preparation-plugin.mjs +290 -0
  72. package/src/runtime-command.mjs +264 -0
  73. package/src/runtime-config.mjs +417 -0
  74. package/src/runtime-guard.mjs +284 -0
  75. package/src/runtime-host.mjs +212 -0
  76. package/src/runtime-init.mjs +278 -0
  77. package/src/runtime-installation.mjs +518 -0
  78. package/src/runtime-lifecycle.mjs +227 -0
  79. package/src/runtime-model-settings.mjs +111 -0
  80. package/src/runtime-readiness.mjs +285 -0
  81. package/src/runtime-workspace.mjs +18 -0
  82. package/src/session-bridge.mjs +365 -0
  83. package/src/store.mjs +394 -0
  84. package/src/tree/LICENSE +21 -0
  85. package/src/tree/attribution.mjs +120 -0
  86. package/src/tree/clusters.mjs +61 -0
  87. package/src/tree/consolidation.mjs +103 -0
  88. package/src/tree/context.mjs +211 -0
  89. package/src/tree/contracts.mjs +142 -0
  90. package/src/tree/experience.mjs +140 -0
  91. package/src/tree/experiment-budget.mjs +84 -0
  92. package/src/tree/hooks.mjs +254 -0
  93. package/src/tree/host-context.mjs +107 -0
  94. package/src/tree/host-process.mjs +288 -0
  95. package/src/tree/host.mjs +37 -0
  96. package/src/tree/improvement.mjs +106 -0
  97. package/src/tree/items.mjs +294 -0
  98. package/src/tree/jobs.mjs +184 -0
  99. package/src/tree/learning.mjs +202 -0
  100. package/src/tree/metrics.mjs +203 -0
  101. package/src/tree/model-owner.mjs +254 -0
  102. package/src/tree/observations.mjs +73 -0
  103. package/src/tree/prompts.mjs +500 -0
  104. package/src/tree/reports.mjs +67 -0
  105. package/src/tree/repository.mjs +236 -0
  106. package/src/tree/runtime.mjs +745 -0
  107. package/src/tree/script-writer.mjs +149 -0
  108. package/src/tree/scripts.mjs +208 -0
  109. package/src/tree/signals.mjs +118 -0
  110. package/src/tree/snapshots.mjs +379 -0
  111. package/src/tree/token-counter.mjs +75 -0
  112. package/src/tree/token-counter.py +37 -0
  113. package/src/tree/tokenizer-resources/LICENSE +21 -0
  114. package/src/tree/tokenizer-resources/README.md +31 -0
  115. package/src/tree/tokenizer-resources/deepseek_recipe-0.2.0-cp310-abi3-macosx_11_0_arm64.whl +0 -0
  116. package/src/tree/tokenizer-resources/manifest.json +61 -0
  117. package/src/tree/tokenizer-resources/native.pyi +1042 -0
  118. package/src/tree/tokenizer-resources/tokenizer-NOTICE.md +26 -0
  119. package/src/tree/tokenizer-resources/tokenizer-v4-NOTICE.md +27 -0
  120. package/src/tree/tokenizer-resources/tokenizer-v4.json +267359 -0
  121. package/src/tree/tokenizer-resources/tokenizer.json +267359 -0
  122. package/src/tree/tools.mjs +99 -0
  123. package/src/tree/tree.mjs +202 -0
  124. package/src/tree/ui.mjs +285 -0
  125. package/src/tree/verification.mjs +143 -0
  126. package/src/understandings.mjs +309 -0
  127. package/src/web-budget-recovery.mjs +181 -0
@@ -0,0 +1,1042 @@
1
+ from collections.abc import Callable, Sequence
2
+ from typing import Any, Literal, TypeAlias
3
+
4
+ __version__: str
5
+
6
+ IMAGE_SPECIAL_TOKEN_ID: int
7
+
8
+ ToolChoice: TypeAlias = Literal["auto", "none", "required"]
9
+ ReasoningEffort: TypeAlias = Literal["low", "high", "xhigh", "max"]
10
+ ResponseFormat: TypeAlias = Literal["text", "json_object", "json_schema", "regex"]
11
+ ImageDetail: TypeAlias = Literal["low", "high", "original", "auto"]
12
+ Role: TypeAlias = Literal["system", "user", "assistant", "tool", "latest_reminder"]
13
+ ImageSourceKind: TypeAlias = Literal["data_url", "url", "bytes"]
14
+ RequestBody: TypeAlias = bytes | str | dict[str, Any]
15
+
16
+ class SpecialToken:
17
+ """A kind of special token."""
18
+
19
+ Bos: SpecialToken
20
+ Eos: SpecialToken
21
+ ThinkingStart: SpecialToken
22
+ ThinkingEnd: SpecialToken
23
+ System: SpecialToken
24
+ User: SpecialToken
25
+ Assistant: SpecialToken
26
+ LatestReminder: SpecialToken
27
+ Dsml: SpecialToken
28
+ Image: SpecialToken
29
+ Ref: SpecialToken
30
+ RefEnd: SpecialToken
31
+ Box: SpecialToken
32
+ BoxEnd: SpecialToken
33
+ Point: SpecialToken
34
+ PointEnd: SpecialToken
35
+ Polygon: SpecialToken
36
+ PolygonEnd: SpecialToken
37
+
38
+ def default_str(self) -> str:
39
+ """Return the default literal spelling of this token."""
40
+
41
+ class SpecialTokens:
42
+ """A mapping from each `SpecialToken` to its spelling.
43
+
44
+ Every keyword defaults to the default spelling of its token, so only
45
+ overridden tokens need to be supplied.
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ *,
51
+ bos: str | None = None,
52
+ eos: str | None = None,
53
+ thinking_start: str | None = None,
54
+ thinking_end: str | None = None,
55
+ system: str | None = None,
56
+ user: str | None = None,
57
+ assistant: str | None = None,
58
+ latest_reminder: str | None = None,
59
+ dsml: str | None = None,
60
+ image: str | None = None,
61
+ ref: str | None = None,
62
+ ref_end: str | None = None,
63
+ box: str | None = None,
64
+ box_end: str | None = None,
65
+ point: str | None = None,
66
+ point_end: str | None = None,
67
+ polygon: str | None = None,
68
+ polygon_end: str | None = None,
69
+ ) -> None: ...
70
+ def token(self, token: SpecialToken) -> str:
71
+ """Return the spelling of `token` in this mapping."""
72
+
73
+ class ConversionError(Exception):
74
+ """Raised when a protocol request is invalid or cannot be converted."""
75
+
76
+ status_code: int
77
+ body: str
78
+
79
+ class ImageError(Exception):
80
+ """A failure to resolve, fetch, or preprocess images, including request limits.
81
+
82
+ `kind` names the Rust `ImageError` variant, and `is_retryable` holds its
83
+ retry classification.
84
+ """
85
+
86
+ kind: str
87
+ is_retryable: bool
88
+
89
+ class CalcResizeError(ValueError):
90
+ """The Rust image token calculation did not converge."""
91
+
92
+ class ToolCall:
93
+ """A historical tool call and its arguments."""
94
+
95
+ def __init__(self, id: str, name: str, arguments: str) -> None: ...
96
+ @property
97
+ def id(self) -> str: ...
98
+ @property
99
+ def name(self) -> str: ...
100
+ @property
101
+ def arguments(self) -> str:
102
+ """Caller-supplied arguments, expected to encode a JSON object; not validated."""
103
+
104
+ class ToolDefinition:
105
+ """A client tool definition.
106
+
107
+ `strict` is passed through. Direct construction does not normalize
108
+ `parameters`, unlike conversion, which normalizes the parameters of a tool
109
+ with `strict: true`.
110
+ """
111
+
112
+ def __init__(
113
+ self,
114
+ name: str,
115
+ description: str | None = None,
116
+ parameters: Any = None,
117
+ strict: bool | None = None,
118
+ defer_loading: bool = False,
119
+ ) -> None: ...
120
+ @property
121
+ def name(self) -> str: ...
122
+ @property
123
+ def description(self) -> str | None: ...
124
+ @property
125
+ def parameters(self) -> Any:
126
+ """Input JSON Schema of the tool."""
127
+
128
+ @property
129
+ def strict(self) -> bool | None:
130
+ """The `strict` setting, passed through without normalizing `parameters`."""
131
+ @property
132
+ def defer_loading(self) -> bool: ...
133
+
134
+ class ImageSource:
135
+ """Base class of the image sources supplied with a conversation.
136
+
137
+ Every source records a `path`: the request location of the image as error
138
+ messages report it, such as `messages.0.content[1]`. Conversion fills it; a
139
+ source constructed directly has an empty path unless the `path` keyword
140
+ supplies one.
141
+ """
142
+
143
+ @property
144
+ def kind(self) -> ImageSourceKind: ...
145
+ @property
146
+ def detail(self) -> ImageDetail: ...
147
+ @property
148
+ def data_url(self) -> str | None: ...
149
+ @property
150
+ def url(self) -> str | None: ...
151
+ @property
152
+ def data(self) -> bytes | None: ...
153
+ @property
154
+ def path(self) -> str:
155
+ """Request location of the image; empty when the source has none."""
156
+
157
+ class DataUrlImageSource(ImageSource):
158
+ """An image referenced by a data URL with a base64 or percent-encoded body."""
159
+
160
+ def __init__(self, data_url: str, detail: ImageDetail = "high", *, path: str = "") -> None: ...
161
+
162
+ class UrlImageSource(ImageSource):
163
+ """An image referenced by an external URL."""
164
+
165
+ def __init__(self, url: str, detail: ImageDetail = "high", *, path: str = "") -> None: ...
166
+
167
+ class BytesImageSource(ImageSource):
168
+ """An image supplied as encoded bytes."""
169
+
170
+ def __init__(self, data: bytes, detail: ImageDetail = "high", *, path: str = "") -> None: ...
171
+
172
+ class Message:
173
+ """Base class of the messages in a conversation.
174
+
175
+ Every message has a role and content. On a message of another role, the
176
+ role-specific properties have fixed values: `reasoning_content`,
177
+ `tool_calls`, and `tool_call_id` are `None`, `prefix` is `False`, and
178
+ `image_sources` is an empty list.
179
+ """
180
+
181
+ @property
182
+ def role(self) -> Role: ...
183
+ @property
184
+ def content(self) -> str: ...
185
+ @property
186
+ def reasoning_content(self) -> str | None: ...
187
+ @property
188
+ def tool_calls(self) -> list[ToolCall] | None: ...
189
+ @property
190
+ def tool_call_id(self) -> str | None: ...
191
+ @property
192
+ def image_sources(self) -> list[ImageSource]: ...
193
+ @property
194
+ def prefix(self) -> bool:
195
+ """Whether an assistant message is continued instead of starting a new turn."""
196
+
197
+ class SystemMessage(Message):
198
+ """A system message.
199
+
200
+ See `UserMessage` for image placeholder rules.
201
+ """
202
+
203
+ def __init__(
204
+ self,
205
+ content: str,
206
+ image_sources: Sequence[ImageSource] | None = None,
207
+ tools: Sequence[ToolDefinition] | None = None,
208
+ *,
209
+ image_token: str | None = None,
210
+ ) -> None: ...
211
+ @property
212
+ def tools(self) -> list[ToolDefinition] | None: ...
213
+
214
+ class UserMessage(Message):
215
+ """A user message.
216
+
217
+ The first occurrences of `image_token` in `content`, one per image source,
218
+ become the placeholders of the image sources; later occurrences are plain
219
+ text. `image_token` defaults to the default image token spelling; a caller
220
+ that renders with a `SpecialTokens` mapping whose image token differs
221
+ passes that mapping's spelling. When `content` holds fewer occurrences than
222
+ there are image sources, the message keeps every image source, so a
223
+ rendered prompt holds fewer placeholders than image sources; construction
224
+ does not report the mismatch. An empty `image_token` raises `ValueError`.
225
+ """
226
+
227
+ def __init__(
228
+ self,
229
+ content: str,
230
+ image_sources: Sequence[ImageSource] | None = None,
231
+ *,
232
+ image_token: str | None = None,
233
+ ) -> None: ...
234
+
235
+ class AssistantMessage(Message):
236
+ """An assistant message."""
237
+
238
+ def __init__(
239
+ self,
240
+ content: str,
241
+ reasoning_content: str | None = None,
242
+ tool_calls: Sequence[ToolCall] | None = None,
243
+ prefix: bool = False,
244
+ ) -> None: ...
245
+
246
+ class ToolMessage(Message):
247
+ """A tool result message.
248
+
249
+ The first occurrences of `image_token` in `content`, one per image source,
250
+ become the placeholders of the image sources; later occurrences are plain
251
+ text. `image_token` defaults to the default image token spelling; a caller
252
+ that renders with a `SpecialTokens` mapping whose image token differs
253
+ passes that mapping's spelling. When `content` holds fewer occurrences than
254
+ there are image sources, the message keeps every image source, so a
255
+ rendered prompt holds fewer placeholders than image sources; construction
256
+ does not report the mismatch. An empty `image_token` raises `ValueError`.
257
+ """
258
+
259
+ def __init__(
260
+ self,
261
+ content: str,
262
+ tool_call_id: str | None = None,
263
+ image_sources: Sequence[ImageSource] | None = None,
264
+ *,
265
+ image_token: str | None = None,
266
+ ) -> None: ...
267
+
268
+ class LatestReminderMessage(Message):
269
+ """A reminder message that carries additional instructions."""
270
+
271
+ def __init__(self, content: str) -> None: ...
272
+
273
+ class Conversation:
274
+ """A conversation and its prompt configuration.
275
+
276
+ Thinking mode is enabled by default, tool selection defaults to `auto`, and
277
+ the response format defaults to `text`. `response_format` accepts `text` or
278
+ `json_object`; `response_schema` selects the `json_schema` format with that
279
+ JSON Schema, and `response_regex` selects the `regex` format with that
280
+ regular expression. Supplying both, or either with `json_object`, raises
281
+ `ValueError`.
282
+ """
283
+
284
+ def __init__(
285
+ self,
286
+ messages: Sequence[Message] | None = None,
287
+ *,
288
+ thinking_mode: bool = True,
289
+ tools: Sequence[ToolDefinition] | None = None,
290
+ tool_choice: ToolChoice = "auto",
291
+ reasoning_effort: ReasoningEffort | None = None,
292
+ response_format: Literal["text", "json_object"] = "text",
293
+ response_schema: Any | None = None,
294
+ response_regex: str | None = None,
295
+ ) -> None: ...
296
+ @property
297
+ def messages(self) -> list[Message]: ...
298
+ @property
299
+ def thinking_mode(self) -> bool: ...
300
+ @property
301
+ def tools(self) -> list[ToolDefinition]: ...
302
+ @property
303
+ def tool_choice(self) -> ToolChoice: ...
304
+ @property
305
+ def reasoning_effort(self) -> ReasoningEffort | None: ...
306
+ @property
307
+ def response_format(self) -> ResponseFormat:
308
+ """Requested answer format; the caller enforces it during inference."""
309
+ @property
310
+ def response_schema(self) -> Any | None:
311
+ """The JSON Schema of a `json_schema` response format, or `None`."""
312
+ @property
313
+ def response_regex(self) -> str | None:
314
+ """The regular expression of a `regex` response format, or `None`."""
315
+
316
+ class RenderedPrompt:
317
+ """A rendered prompt and the image sources its placeholders refer to."""
318
+
319
+ @property
320
+ def prompt(self) -> str: ...
321
+ @property
322
+ def special_ranges(self) -> list[tuple[int, int]]:
323
+ """Ascending, disjoint ranges of `prompt` that hold explicit special tokens.
324
+
325
+ Each range is a half-open `(start, end)` pair of code point offsets into
326
+ `prompt` (Python `str` indices), so `prompt[start:end]` is the spelling of
327
+ one token. The Rust `RenderedPrompt::special_ranges` field holds byte
328
+ offsets instead.
329
+
330
+ The text between the ranges is plain text, which prompt encoding encodes
331
+ without the tokenizer's added vocabulary. `Tokenizer.encode` uses the full
332
+ vocabulary, so it encodes a special-token spelling in plain text as that
333
+ token's ID. `DeepseekV4Encoding.encode` and `DeepseekV41Encoding.encode`
334
+ perform prompt encoding.
335
+ """
336
+ @property
337
+ def image_sources(self) -> list[ImageSource]: ...
338
+
339
+ class DeepseekV4Encoding:
340
+ """The V4 prompt encoding.
341
+
342
+ It renders a conversation and, with an attached tokenizer, encodes it into
343
+ token IDs.
344
+ """
345
+
346
+ def __init__(self) -> None: ...
347
+ def with_tokenizer(self, tokenizer: Tokenizer) -> DeepseekV4Encoding:
348
+ """Return a new prompt encoding that uses `tokenizer` for `encode`."""
349
+ def with_special_tokens(self, special_tokens: SpecialTokens) -> DeepseekV4Encoding:
350
+ """Return a new prompt encoding that renders prompts with `special_tokens`."""
351
+ def render_conversation(self, conversation: Conversation) -> RenderedPrompt: ...
352
+ def encode(self, conversation: Conversation) -> list[int]:
353
+ """Encode a conversation into token IDs using the attached tokenizer.
354
+
355
+ Raises `RuntimeError` when no tokenizer is attached or encoding fails.
356
+ """
357
+
358
+ class DeepseekV41Encoding:
359
+ """The V4.1 prompt encoding.
360
+
361
+ It renders a conversation and, with an attached tokenizer, encodes it into
362
+ token IDs.
363
+ """
364
+
365
+ def __init__(self) -> None: ...
366
+ def with_tokenizer(self, tokenizer: Tokenizer) -> DeepseekV41Encoding:
367
+ """Return a new prompt encoding that uses `tokenizer` for `encode`."""
368
+ def with_special_tokens(self, special_tokens: SpecialTokens) -> DeepseekV41Encoding:
369
+ """Return a new prompt encoding that renders prompts with `special_tokens`."""
370
+ def render_conversation(self, conversation: Conversation) -> RenderedPrompt: ...
371
+ def encode(self, conversation: Conversation) -> list[int]:
372
+ """Encode a conversation into token IDs using the attached tokenizer.
373
+
374
+ Raises `RuntimeError` when no tokenizer is attached or encoding fails.
375
+ """
376
+
377
+ class WebSearchBehavior:
378
+ """Handling of supported web-search declarations, choices, and Messages blocks."""
379
+
380
+ Drop: WebSearchBehavior
381
+ """Drop matching declarations and choices, plus Messages server-tool blocks."""
382
+ Reject: WebSearchBehavior
383
+ """Reject matching declarations and choices, plus Messages server-tool blocks."""
384
+
385
+ class ReasoningContentBehavior:
386
+ """Handling of assistant history missing reasoning content in thinking mode."""
387
+
388
+ FillEmpty: ReasoningContentBehavior
389
+ """Fill missing reasoning content with an empty string."""
390
+ Reject: ReasoningContentBehavior
391
+ """Reject the request when reasoning content that must be passed back is missing."""
392
+
393
+ class ModelVersion:
394
+ """The model version a converted conversation targets.
395
+
396
+ Conversion resolves it from the request's model name through
397
+ `ConversionOptions.model_versions_by_name`, and it selects the prompt
398
+ encoding: `DeepseekV4Encoding` or `DeepseekV41Encoding`.
399
+ """
400
+
401
+ DeepseekV4Pro: ModelVersion
402
+ """DeepSeek V4 Pro, rendered by `DeepseekV4Encoding`."""
403
+ DeepseekV41Flash: ModelVersion
404
+ """DeepSeek V4.1 Flash, rendered by `DeepseekV41Encoding`."""
405
+
406
+ class ConversionOptions:
407
+ """Options for protocol request conversion.
408
+
409
+ By default, thinking mode is enabled, missing reasoning content is filled
410
+ with an empty string, Responses `web_search` is dropped, Messages
411
+ `web_search` is rejected, the model version is resolved from the request's
412
+ model name (`DeepSeek-V4-Pro` or `DeepSeek-V4.1-Flash`), and the
413
+ `max_tokens` upper bound is 393216 in thinking mode and outside it.
414
+ """
415
+
416
+ def __init__(
417
+ self,
418
+ *,
419
+ default_thinking_mode: bool = True,
420
+ reasoning_content_behavior: ReasoningContentBehavior = ReasoningContentBehavior.FillEmpty,
421
+ responses_web_search: WebSearchBehavior = WebSearchBehavior.Drop,
422
+ messages_web_search: WebSearchBehavior = WebSearchBehavior.Reject,
423
+ thinking_max_tokens_upper_bound: int = 393216,
424
+ non_thinking_max_tokens_upper_bound: int = 393216,
425
+ ) -> None: ...
426
+ @property
427
+ def default_thinking_mode(self) -> bool:
428
+ """Whether requests that do not specify a thinking mode use thinking mode.
429
+
430
+ Defaults to `True`.
431
+ """
432
+ @property
433
+ def model_versions_by_name(self) -> dict[str, ModelVersion]:
434
+ """The target model version of each accepted request model name.
435
+
436
+ Defaults to `DeepSeek-V4-Pro` and `DeepSeek-V4.1-Flash`; conversion
437
+ rejects a request whose model is not a key.
438
+ """
439
+ @property
440
+ def thinking_max_tokens_upper_bound(self) -> int:
441
+ """The largest accepted `max_tokens` (`max_output_tokens` in Responses)
442
+ of a request in thinking mode.
443
+
444
+ Chat Completions and Responses reject a larger value; Messages lowers it
445
+ to this bound.
446
+ """
447
+ @property
448
+ def non_thinking_max_tokens_upper_bound(self) -> int:
449
+ """The largest accepted `max_tokens` (`max_output_tokens` in Responses)
450
+ of a request outside thinking mode.
451
+
452
+ Chat Completions and Responses reject a larger value; Messages lowers it
453
+ to this bound.
454
+ """
455
+ @property
456
+ def reasoning_content_behavior(self) -> ReasoningContentBehavior:
457
+ """Missing-reasoning-content behavior, defaulting to `FillEmpty`."""
458
+ @property
459
+ def responses_web_search(self) -> WebSearchBehavior:
460
+ """Responses web-search behavior, defaulting to `Drop`."""
461
+ @property
462
+ def messages_web_search(self) -> WebSearchBehavior:
463
+ """Messages web-search behavior, defaulting to `Reject`."""
464
+ @property
465
+ def special_tokens(self) -> SpecialTokens:
466
+ """Special token mapping, defaulting to the built-in mapping."""
467
+ def with_default_thinking_mode(self, default_thinking_mode: bool) -> ConversionOptions:
468
+ """Construct options with the supplied default thinking mode."""
469
+ def with_reasoning_content_behavior(
470
+ self, reasoning_content_behavior: ReasoningContentBehavior
471
+ ) -> ConversionOptions:
472
+ """Construct options with the supplied missing-reasoning-content behavior."""
473
+ def with_responses_web_search(
474
+ self, responses_web_search: WebSearchBehavior
475
+ ) -> ConversionOptions:
476
+ """Construct options with the supplied Responses web-search behavior."""
477
+ def with_messages_web_search(
478
+ self, messages_web_search: WebSearchBehavior
479
+ ) -> ConversionOptions:
480
+ """Construct options with the supplied Messages web-search behavior."""
481
+ def with_special_tokens(self, special_tokens: SpecialTokens) -> ConversionOptions:
482
+ """Construct options with the supplied special token mapping."""
483
+ def with_model_alias(self, model: str, model_version: ModelVersion) -> ConversionOptions:
484
+ """Accept `model` as a name of `model_version`.
485
+
486
+ Adds the name, or replaces the version of an existing one.
487
+ """
488
+ def with_model_versions_by_name(
489
+ self, model_versions_by_name: dict[str, ModelVersion]
490
+ ) -> ConversionOptions:
491
+ """Replace the whole table of accepted model names.
492
+
493
+ Drops the default names unless the mapping includes them.
494
+ """
495
+ def with_thinking_max_tokens_upper_bound(
496
+ self, thinking_max_tokens_upper_bound: int
497
+ ) -> ConversionOptions: ...
498
+ def with_non_thinking_max_tokens_upper_bound(self, non_thinking_max_tokens_upper_bound: int) -> ConversionOptions: ...
499
+
500
+ class ConversationRequest:
501
+ """A Rust conversation request with inference and parsing options."""
502
+
503
+ def __init__(self, conversation: Conversation, model_version: ModelVersion) -> None:
504
+ """Construct a request with default inference, parsing, and transport options."""
505
+ @property
506
+ def conversation(self) -> Conversation: ...
507
+ @property
508
+ def inference_options(self) -> InferenceOptions: ...
509
+ @property
510
+ def parsing_options(self) -> ParsingOptions: ...
511
+ @property
512
+ def model_version(self) -> ModelVersion:
513
+ """The target model version.
514
+
515
+ Conversion resolves it from the request's model name; the constructor
516
+ takes it as an argument.
517
+ """
518
+ @property
519
+ def stream(self) -> bool:
520
+ """Whether the protocol request asks for a streamed response."""
521
+ def resolve_max_tokens(self, prompt_tokens: int, context_limit: int) -> int:
522
+ """Resolve the `max_tokens` to send to the backend.
523
+
524
+ `prompt_tokens` is the number of tokens in the encoded prompt, with each
525
+ image counted at its image token count instead of as one placeholder,
526
+ and `context_limit` is the number of tokens the model's context holds.
527
+ A requested `max_tokens` is kept; an unspecified one becomes 8192
528
+ outside thinking mode, 131072 in thinking mode with `max` effort, and
529
+ 65536 in thinking mode otherwise. The result is lowered to the context
530
+ left after the prompt and raised to at least 1. Raises `ConversionError`
531
+ when `prompt_tokens` plus the requested `max_tokens` exceeds
532
+ `context_limit`, or, without a requested `max_tokens`, when
533
+ `prompt_tokens` alone exceeds it.
534
+ """
535
+
536
+ class ChatCompletionRequest:
537
+ """A Rust Chat Completions request; even failed conversion consumes it."""
538
+
539
+ def __init__(self, body: RequestBody) -> None: ...
540
+ @property
541
+ def model(self) -> str:
542
+ """The requested model name; read it before `convert` consumes the request."""
543
+ def convert(self, options: ConversionOptions) -> ConversationRequest: ...
544
+ @staticmethod
545
+ def chunk_generator(
546
+ request: ConversationRequest, id: str, model: str
547
+ ) -> ChatCompletionChunkGenerator: ...
548
+
549
+ class ResponsesRequest:
550
+ """A Rust Responses request; even failed conversion consumes it."""
551
+
552
+ def __init__(self, body: RequestBody) -> None: ...
553
+ @property
554
+ def model(self) -> str:
555
+ """The requested model name; read it before `convert` consumes the request."""
556
+ def namespace_tool_map(self, options: ConversionOptions) -> dict[str, tuple[str, str]]:
557
+ """Return the function names of the declared namespace tools.
558
+
559
+ Each function name maps to `(namespace, local name)`, as conversion with
560
+ `options` assigns them; read them before `convert` consumes this request.
561
+ Raises `ConversionError` for an invalid tool declaration.
562
+ """
563
+ def echo(self) -> ResponsesEcho:
564
+ """Return the request settings that responses report.
565
+
566
+ Read them before `convert` consumes this request.
567
+ """
568
+
569
+ def convert(self, options: ConversionOptions) -> ConversationRequest: ...
570
+ @staticmethod
571
+ def chunk_generator(
572
+ request: ConversationRequest, id: str, model: str
573
+ ) -> ResponsesChunkGenerator: ...
574
+
575
+ class MessagesRequest:
576
+ """A Rust Messages request; even failed conversion consumes it."""
577
+
578
+ def __init__(self, body: RequestBody) -> None: ...
579
+ @property
580
+ def model(self) -> str:
581
+ """The requested model name; read it before `convert` consumes the request."""
582
+ def convert(self, options: ConversionOptions) -> ConversationRequest: ...
583
+ @staticmethod
584
+ def chunk_generator(
585
+ request: ConversationRequest, id: str, model: str
586
+ ) -> MessagesChunkGenerator: ...
587
+
588
+ class InferenceOptions:
589
+ """Inference parameters extracted by protocol conversion.
590
+
591
+ Conversion always sets `temperature` (1.0 in thinking mode) and `top_p` to
592
+ their resolved values. Other unspecified parameters are `None`;
593
+ `ConversationRequest.resolve_max_tokens` supplies the default `max_tokens`,
594
+ and the caller applies the other model-specific defaults.
595
+ """
596
+
597
+ @property
598
+ def max_tokens(self) -> int | None:
599
+ """Maximum number of output tokens, or `None` when the request sets none.
600
+
601
+ `ConversationRequest.resolve_max_tokens` supplies the default after the
602
+ prompt is encoded.
603
+ """
604
+ @property
605
+ def temperature(self) -> float | None:
606
+ """Sampling temperature: 1.0 in thinking mode, otherwise the requested value or 1.0."""
607
+ @property
608
+ def top_p(self) -> float | None:
609
+ """Final `top_p` for the target model version."""
610
+ @property
611
+ def logprobs(self) -> bool:
612
+ """Whether the request asks for the log probability of each output token."""
613
+ @property
614
+ def top_logprobs(self) -> int | None:
615
+ """Number of most likely alternatives reported per output token, in `[0, 20]`."""
616
+ @property
617
+ def seed(self) -> int | None:
618
+ """Sampling seed in `[0, 2^63)`; the caller chooses an unspecified seed."""
619
+ @property
620
+ def output_constraint(self) -> OutputConstraint | None:
621
+ """The constraint that constrained decoding would enforce on the output,
622
+ or `None`; whether the backend applies it is the caller's decision.
623
+ """
624
+
625
+ class OutputConstraint:
626
+ """A constraint on the model output that the backend can enforce by
627
+ constrained decoding, as a kind name and a constraint string.
628
+ """
629
+
630
+ @property
631
+ def kind(self) -> str:
632
+ """`json`, `regex`, `tool_call`, or `tool_call_required`."""
633
+ @property
634
+ def schema(self) -> str:
635
+ """The schema as compact JSON, the regular expression, the tool list as
636
+ a compact JSON array of Chat Completions function tools with
637
+ `defer_loading: true` on deferred tools, or an empty string for any JSON
638
+ value.
639
+ """
640
+
641
+ class ImageInfo:
642
+ """A preprocessed image for the inference backend.
643
+
644
+ It holds the encoded image bytes and the image dimensions in pixels after
645
+ preprocessing.
646
+ """
647
+
648
+ def __init__(self, data: bytes, width: int, height: int) -> None: ...
649
+ @property
650
+ def data(self) -> bytes: ...
651
+ @property
652
+ def width(self) -> int: ...
653
+ @property
654
+ def height(self) -> int: ...
655
+
656
+ class MultiModalData:
657
+ """Images in the order their placeholders appear in a prompt."""
658
+
659
+ def __init__(self, images: Sequence[ImageInfo] | None = None) -> None: ...
660
+ @property
661
+ def images(self) -> list[ImageInfo]: ...
662
+ def is_empty(self) -> bool: ...
663
+ def image_token_adjustment(self) -> int:
664
+ """Return the number of inference input tokens beyond one per placeholder.
665
+
666
+ The V4.1 image token specification gives the image token count of each
667
+ image, which occupies one placeholder in the prompt; the adjustment is the
668
+ sum of the differences. Raises `CalcResizeError` when fitting an image
669
+ does not converge.
670
+ """
671
+
672
+ class ImageQuota:
673
+ """The image count and encoded bytes recorded by the completed resolve calls of one request.
674
+
675
+ To apply the image count and total byte limits across the resolve calls of a
676
+ request, the caller must pass the same quota to every call. A call records
677
+ its sources after it preprocesses every one of them, so a failed call adds
678
+ nothing.
679
+ """
680
+
681
+ def __init__(self) -> None: ...
682
+ def image_count(self) -> int: ...
683
+ def byte_size(self) -> int: ...
684
+
685
+ class PreprocessOptions:
686
+ """Options passed to one Rust image preprocessing operation."""
687
+
688
+ def __init__(
689
+ self, detail: ImageDetail, max_dimension_px: int, low_detail_max_dimension_px: int
690
+ ) -> None: ...
691
+ @property
692
+ def detail(self) -> ImageDetail: ...
693
+ @property
694
+ def max_dimension_px(self) -> int: ...
695
+ @property
696
+ def low_detail_max_dimension_px(self) -> int: ...
697
+
698
+ class ReqwestImageFetcher:
699
+ """An image fetcher that downloads external image URLs through the Rust `reqwest` client.
700
+
701
+ Without a destination filter, this fetcher connects to any address. When
702
+ untrusted clients can supply image URLs, the caller should install a filter
703
+ with `with_destination_filter` to protect against SSRF.
704
+ """
705
+
706
+ def __init__(self) -> None: ...
707
+ @staticmethod
708
+ def with_max_bytes(max_bytes: int) -> ReqwestImageFetcher: ...
709
+ def with_destination_filter(
710
+ self, destination_filter: Callable[[str, str], bool]
711
+ ) -> ReqwestImageFetcher:
712
+ """Return a fetcher with this size limit that connects only to allowed addresses.
713
+
714
+ `destination_filter(host, address)` receives the host of the image URL or
715
+ of a redirect target and one address as a string, such as `"10.0.0.1"`,
716
+ and returns whether the fetcher can connect to it. For a host name, the
717
+ fetcher connects only to the resolved addresses the filter allows. A host
718
+ with no allowed address raises `ImageError` with kind
719
+ `"DestinationRejected"`. A callable that raises or returns a non-boolean
720
+ value rejects the address. The returned fetcher uses no proxy. The
721
+ library does not include a filter implementation; the caller writes the
722
+ rule. Raises `TypeError` when `destination_filter` is not callable.
723
+ """
724
+ def fetch(self, url: str) -> bytes: ...
725
+
726
+ class OpenCvImagePreprocessor:
727
+ """An image preprocessor that uses the Rust OpenCV implementation."""
728
+
729
+ def __init__(self) -> None: ...
730
+ def preprocess(self, data: bytes, options: PreprocessOptions) -> ImageInfo: ...
731
+
732
+ class ImageResolver:
733
+ """An image resolver built from explicit fetching and preprocessing components."""
734
+
735
+ def __init__(
736
+ self, fetcher: ReqwestImageFetcher, preprocessor: OpenCvImagePreprocessor
737
+ ) -> None: ...
738
+ def resolve(self, sources: Sequence[ImageSource], quota: ImageQuota) -> MultiModalData:
739
+ """Resolve image sources and update the supplied quota.
740
+
741
+ A failed call leaves the quota unchanged.
742
+ """
743
+
744
+ class PromptUsage:
745
+ """Prompt-side token counts from the backend."""
746
+
747
+ def __init__(
748
+ self, *, prompt_tokens: int = 0, prompt_cache_hit_tokens: int = 0,
749
+ ) -> None: ...
750
+ @property
751
+ def prompt_tokens(self) -> int: ...
752
+ @property
753
+ def prompt_cache_hit_tokens(self) -> int: ...
754
+
755
+ class InferenceFinishReason:
756
+ """Backend finish reasons; output parsing determines the protocol finish reason."""
757
+
758
+ Stop: InferenceFinishReason
759
+ Length: InferenceFinishReason
760
+ ContentFilter: InferenceFinishReason
761
+
762
+ class InferenceChunk:
763
+ """One backend update, constructed with `ready`, `text`, `tokens`, or `finish`."""
764
+
765
+ @staticmethod
766
+ def ready(
767
+ *, prompt_usage: PromptUsage | None = None, system_fingerprint: str | None = None,
768
+ ) -> InferenceChunk: ...
769
+ @staticmethod
770
+ def text(content: str, token_count: int = 0) -> InferenceChunk:
771
+ """Construct a text chunk from `content` and the number of tokens it accounts for."""
772
+ @staticmethod
773
+ def tokens(
774
+ token_ids: Sequence[int],
775
+ logprobs: Sequence[tuple[float, Sequence[tuple[int, float]]]] | None = None,
776
+ ) -> InferenceChunk:
777
+ """Construct a chunk from the token IDs of one backend output.
778
+
779
+ `logprobs` holds one `(logprob, top_logprobs)` pair per token ID.
780
+ """
781
+ @staticmethod
782
+ def finish(finish_reason: InferenceFinishReason) -> InferenceChunk: ...
783
+ @property
784
+ def kind(self) -> Literal["ready", "text", "tokens", "finish"]: ...
785
+ @property
786
+ def content(self) -> str | None: ...
787
+ @property
788
+ def token_ids(self) -> list[int] | None:
789
+ """The token IDs of a `tokens` chunk."""
790
+ @property
791
+ def finish_reason(self) -> InferenceFinishReason | None: ...
792
+ @property
793
+ def prompt_usage(self) -> PromptUsage | None: ...
794
+ @property
795
+ def token_count(self) -> int | None:
796
+ """The number of tokens this chunk's content accounts for; text chunks only."""
797
+ @property
798
+ def system_fingerprint(self) -> str | None: ...
799
+
800
+ class ThinkingInitialStage:
801
+ """The stage where parsing begins in thinking mode."""
802
+
803
+ ReasoningStart: ThinkingInitialStage
804
+ """Begin the reasoning content of a new assistant turn, discarding leading newlines."""
805
+ ReasoningContinuation: ThinkingInitialStage
806
+ """Continue the reasoning content of a prefix continuation, preserving leading newlines."""
807
+ ContentContinuation: ThinkingInitialStage
808
+ """Continue the answer content of a prefix continuation whose reasoning content has ended.
809
+
810
+ Leading newlines are preserved.
811
+ """
812
+
813
+ def starts_in_reasoning(self) -> bool:
814
+ """Return whether parsing begins in reasoning content."""
815
+
816
+ class ParsingOptions:
817
+ """Settings passed directly to the Rust stream parser."""
818
+
819
+ def __init__(
820
+ self,
821
+ *,
822
+ parse_tool_calls: bool = True,
823
+ starts_in_tool_calls: bool = False,
824
+ parse_json_output: bool = False,
825
+ thinking_initial_stage: ThinkingInitialStage | None = None,
826
+ stop_sequences: Sequence[str] | None = None,
827
+ special_tokens: SpecialTokens | None = None,
828
+ ) -> None: ...
829
+ parse_tool_calls: bool
830
+ """Whether to parse model-specific tool-call markup."""
831
+ starts_in_tool_calls: bool
832
+ """Whether parsing begins inside the tool-call block that the prompt opened.
833
+
834
+ Used for a required tool choice; takes precedence over `thinking_initial_stage`.
835
+ """
836
+ parse_json_output: bool
837
+ """Whether to recognize fenced or bare JSON output and replace the text around it with spaces."""
838
+ thinking_initial_stage: ThinkingInitialStage | None
839
+ """The stage where parsing begins in thinking mode; `None` means thinking mode is off.
840
+
841
+ A stage also makes the processor report reasoning tokens.
842
+ """
843
+ @property
844
+ def stop_sequences(self) -> list[str]: ...
845
+ @stop_sequences.setter
846
+ def stop_sequences(self, value: Sequence[str]) -> None: ...
847
+ @property
848
+ def special_tokens(self) -> SpecialTokens: ...
849
+ @special_tokens.setter
850
+ def special_tokens(self, value: SpecialTokens) -> None: ...
851
+
852
+ class ChatCompletionChunkGenerator:
853
+ """A Rust Chat Completions generator consumed by a stream processor."""
854
+
855
+ class ResponsesChunkGenerator:
856
+ """A Rust Responses generator consumed by a stream processor."""
857
+
858
+ def with_namespace_tool_map(
859
+ self, namespace_tool_map: dict[str, tuple[str, str]]
860
+ ) -> ResponsesChunkGenerator:
861
+ """Consume this generator and construct one that splits namespace tool names."""
862
+ def with_echo(self, echo: ResponsesEcho) -> ResponsesChunkGenerator:
863
+ """Consume this generator and construct one whose responses report the request settings."""
864
+
865
+ class ResponsesEcho:
866
+ """Request settings that Responses response objects report, as the request specified them.
867
+
868
+ `ResponsesRequest.echo` reads them from a request; the constructor builds
869
+ the settings of an unspecified request. The properties expose the scalar
870
+ settings; the reasoning, text, tool choice, and tool settings are reported
871
+ only through the response.
872
+ """
873
+
874
+ def __init__(self) -> None:
875
+ """Construct the settings of an unspecified request.
876
+
877
+ No instructions, output token limit, or user; temperature and `top_p` of
878
+ 1.0; zero `top_logprobs`.
879
+ """
880
+ @property
881
+ def instructions(self) -> str | None: ...
882
+ @property
883
+ def max_output_tokens(self) -> int | None: ...
884
+ @property
885
+ def temperature(self) -> float:
886
+ """The requested temperature or 1.0, not the sampling temperature."""
887
+ @property
888
+ def top_p(self) -> float:
889
+ """The requested `top_p` or 1.0, not the sampling `top_p`."""
890
+ @property
891
+ def top_logprobs(self) -> int:
892
+ """The requested `top_logprobs`, or 0."""
893
+ @property
894
+ def user(self) -> str | None: ...
895
+
896
+ class MessagesChunkGenerator:
897
+ """A Rust Messages generator consumed by a stream processor."""
898
+
899
+ def __init__(self, id: str, model: str, thinking_mode: bool) -> None: ...
900
+ def with_signature(self, signature: str) -> MessagesChunkGenerator:
901
+ """Consume this generator and construct one with the supplied signature.
902
+
903
+ The new generator emits `signature` at the end of each thinking block. The
904
+ default signature is the response ID.
905
+ """
906
+
907
+ class ChatCompletionChunk:
908
+ """A Rust Chat Completions chunk consumed by response accumulation."""
909
+
910
+ def to_json(self) -> str: ...
911
+
912
+ class ResponsesStreamEvent:
913
+ """A Rust Responses event consumed by response accumulation."""
914
+
915
+ def to_json(self) -> str: ...
916
+
917
+ class MessagesStreamEvent:
918
+ """A Rust Messages event consumed by response accumulation."""
919
+
920
+ def to_json(self) -> str: ...
921
+
922
+ class ChatCompletionResponse:
923
+ """A Rust Chat Completions response with explicit accumulation."""
924
+
925
+ def __init__(
926
+ self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
927
+ ) -> None: ...
928
+ def accumulate(self, chunk: ChatCompletionChunk) -> None:
929
+ """Consume this chunk and apply its delta to the response."""
930
+
931
+ def to_json(self) -> str: ...
932
+ @staticmethod
933
+ def sse_event_name(chunk: ChatCompletionChunk) -> str | None:
934
+ """Return the SSE event name of `chunk`, or `None` for an unnamed data event."""
935
+ @staticmethod
936
+ def sse_done_data() -> str | None:
937
+ """Return the data of the final SSE message, `[DONE]`."""
938
+
939
+ class ResponsesResponse:
940
+ """A Rust Responses response with explicit accumulation."""
941
+
942
+ def __init__(
943
+ self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
944
+ ) -> None: ...
945
+ def accumulate(self, chunk: ResponsesStreamEvent) -> None:
946
+ """Consume this event and apply its delta to the response."""
947
+
948
+ def to_json(self) -> str: ...
949
+ @staticmethod
950
+ def sse_event_name(chunk: ResponsesStreamEvent) -> str | None:
951
+ """Return the SSE event name of `chunk`."""
952
+ @staticmethod
953
+ def sse_done_data() -> str | None:
954
+ """Return `None`: a Responses stream has no final data message."""
955
+
956
+ class MessagesResponse:
957
+ """A Rust Messages response with explicit accumulation."""
958
+
959
+ def __init__(
960
+ self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
961
+ ) -> None: ...
962
+ def accumulate(self, chunk: MessagesStreamEvent) -> None:
963
+ """Consume this event and apply its delta to the response."""
964
+
965
+ def to_json(self) -> str: ...
966
+ @staticmethod
967
+ def sse_event_name(chunk: MessagesStreamEvent) -> str | None:
968
+ """Return the SSE event name of `chunk`."""
969
+ @staticmethod
970
+ def sse_done_data() -> str | None:
971
+ """Return `None`: a Messages stream has no final data message."""
972
+
973
+ class Tokenizer:
974
+ """A Hugging Face tokenizer loaded from a `tokenizer.json` file.
975
+
976
+ A prompt encoding uses it, after `with_tokenizer`, to encode conversations into
977
+ token IDs. A stream processor uses it to decode the token IDs of `tokens`
978
+ inference chunks.
979
+ """
980
+
981
+ @staticmethod
982
+ def from_file(path: str) -> Tokenizer:
983
+ """Load a tokenizer from a `tokenizer.json` file."""
984
+
985
+ @staticmethod
986
+ def from_str(text: str) -> Tokenizer:
987
+ """Load a tokenizer from the contents of a `tokenizer.json` file."""
988
+
989
+ @staticmethod
990
+ def from_pretrained(
991
+ identifier: str, revision: str | None = None, token: str | None = None
992
+ ) -> Tokenizer:
993
+ """Download and cache `tokenizer.json` from the Hugging Face Hub."""
994
+
995
+ def encode(self, text: str) -> list[int]:
996
+ """Encode `text` into token IDs with the full vocabulary, including the added vocabulary.
997
+
998
+ A special-token spelling in `text` encodes as that token's ID. The
999
+ post-processor adds no special tokens, such as a BOS token. This is not
1000
+ prompt encoding, which encodes plain text without the added vocabulary:
1001
+ `DeepseekV4Encoding.encode` and `DeepseekV41Encoding.encode` perform
1002
+ prompt encoding.
1003
+ """
1004
+
1005
+ class StreamProcessor:
1006
+ """Adapt Python inference chunks to the Rust processor's input stream."""
1007
+
1008
+ def __init__(
1009
+ self,
1010
+ generator: ChatCompletionChunkGenerator | ResponsesChunkGenerator | MessagesChunkGenerator,
1011
+ options: ParsingOptions,
1012
+ tokenizer: Tokenizer | None = None,
1013
+ ) -> None:
1014
+ """Consume the generator and construct a Rust stream processor.
1015
+
1016
+ The optional tokenizer decodes `tokens` chunks. Without one, such a chunk
1017
+ raises `RuntimeError` and closes the processor.
1018
+ """
1019
+
1020
+ @property
1021
+ def finished(self) -> bool:
1022
+ """Whether processing completed normally and the processor remains unclosed."""
1023
+
1024
+ def push(
1025
+ self, chunk: InferenceChunk
1026
+ ) -> list[ChatCompletionChunk | ResponsesStreamEvent | MessagesStreamEvent]:
1027
+ """Process one chunk.
1028
+
1029
+ Raises `RuntimeError` after completion or close, or on a stream error: a
1030
+ `tokens` chunk without a tokenizer, a decoding failure, or a log
1031
+ probability count that differs from the token ID count. A stream error
1032
+ closes the processor.
1033
+ """
1034
+
1035
+ def finish(self) -> list[ChatCompletionChunk | ResponsesStreamEvent | MessagesStreamEvent]:
1036
+ """Close the input and process buffered output; repeated calls after completion yield no chunks.
1037
+
1038
+ Calls after close or a stream error raise `RuntimeError`.
1039
+ """
1040
+
1041
+ def close(self) -> None:
1042
+ """Release processing state without producing successful completion."""