wrencode 0.3.2__tar.gz → 0.3.3__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: wrencode
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: A minimal agent harness for coding: a readable agent loop and the modules it calls
5
5
  Project-URL: Homepage, https://github.com/almostly/wrencode
6
6
  Project-URL: Repository, https://github.com/almostly/wrencode
@@ -759,7 +759,9 @@ What a session looks like, and the keys that drive it.
759
759
  accent blue on the assistant's dot, the prompt and the banner. The background
760
760
  is read from `COLORFGBG` or asked of the terminal itself (most answer); when
761
761
  neither says, the first run asks you once and `/theme light|dark|auto`
762
- changes the saved answer. `WRENCODE_THEME=light` or `dark` forces one, `ansi` draws with the terminal's
762
+ changes the saved answer. Colors are 24-bit where the terminal takes them (`COLORTERM`, or iTerm2,
763
+ WezTerm, Ghostty and VS Code's terminal) and the nearest of 256 elsewhere;
764
+ `WRENCODE_TRUECOLOR=1|0` overrides. `WRENCODE_THEME=light` or `dark` forces one, `ansi` draws with the terminal's
763
765
  own colors instead, and a [Zed](https://zed.dev) theme file
764
766
  (`~/.config/zed/themes/mine.json#Mine Light`) replaces the palette with its
765
767
  own.
@@ -730,7 +730,9 @@ What a session looks like, and the keys that drive it.
730
730
  accent blue on the assistant's dot, the prompt and the banner. The background
731
731
  is read from `COLORFGBG` or asked of the terminal itself (most answer); when
732
732
  neither says, the first run asks you once and `/theme light|dark|auto`
733
- changes the saved answer. `WRENCODE_THEME=light` or `dark` forces one, `ansi` draws with the terminal's
733
+ changes the saved answer. Colors are 24-bit where the terminal takes them (`COLORTERM`, or iTerm2,
734
+ WezTerm, Ghostty and VS Code's terminal) and the nearest of 256 elsewhere;
735
+ `WRENCODE_TRUECOLOR=1|0` overrides. `WRENCODE_THEME=light` or `dark` forces one, `ansi` draws with the terminal's
734
736
  own colors instead, and a [Zed](https://zed.dev) theme file
735
737
  (`~/.config/zed/themes/mine.json#Mine Light`) replaces the palette with its
736
738
  own.
@@ -61,7 +61,7 @@ include = ["src/wrencode", "README.md"]
61
61
 
62
62
  [tool.commitizen]
63
63
  name = "cz_conventional_commits"
64
- version = "0.3.2"
64
+ version = "0.3.3"
65
65
  version_scheme = "pep440"
66
66
  tag_format = "$version"
67
67
  legacy_tag_formats = ["v$version"]
@@ -4,4 +4,4 @@
4
4
  with `wrencode` (the installed command) or `python -m wrencode`.
5
5
  """
6
6
 
7
- __version__ = "0.3.2"
7
+ __version__ = "0.3.3"
@@ -337,6 +337,27 @@ WEB_SEARCH = os.environ.get("WRENCODE_WEB_SEARCH", "1").lower() not in (
337
337
  "no",
338
338
  )
339
339
  WEB_SEARCH_TOOL: dict[str, Any] = {"type": "web_search_20260209", "name": "web_search"}
340
+ # The models that take the current search tool (with dynamic filtering); the
341
+ # others, Haiku among them, refuse it and take the basic one.
342
+ _WEB_SEARCH_CURRENT = (
343
+ "opus-5",
344
+ "opus-4-8",
345
+ "opus-4-7",
346
+ "opus-4-6",
347
+ "sonnet-5",
348
+ "sonnet-4-6",
349
+ "fable-5",
350
+ )
351
+
352
+
353
+ def web_search_tool(model: str) -> dict[str, Any]:
354
+ """The server-side web search tool definition `model` accepts."""
355
+ m = model.lower().replace(".", "-")
356
+ if any(tag in m for tag in _WEB_SEARCH_CURRENT):
357
+ return dict(WEB_SEARCH_TOOL)
358
+ return {"type": "web_search_20250305", "name": "web_search"}
359
+
360
+
340
361
  WEB_SEARCH_USD = 0.01 # $10 per 1,000 searches
341
362
 
342
363
 
@@ -1884,7 +1905,7 @@ def get_response(
1884
1905
  defs[-1] = {**defs[-1], "cache_control": {"type": "ephemeral"}}
1885
1906
  if WEB_SEARCH and BACKEND == "anthropic" and tools:
1886
1907
  defs = [
1887
- dict(WEB_SEARCH_TOOL),
1908
+ web_search_tool(MODEL),
1888
1909
  *defs,
1889
1910
  ] # first, so the cache marker stays last
1890
1911
  payload = {
@@ -15,7 +15,7 @@ import select
15
15
  import sys
16
16
  import threading
17
17
  import time
18
- from collections.abc import Callable, Generator
18
+ from collections.abc import Callable, Generator, Mapping
19
19
  from dataclasses import dataclass
20
20
  from typing import Any
21
21
 
@@ -186,13 +186,50 @@ def ansi_palette(theme: str) -> Palette:
186
186
  )
187
187
 
188
188
 
189
+ def supports_truecolor(env: Mapping[str, str] | None = None) -> bool:
190
+ """Whether the terminal takes 24-bit colors: COLORTERM says so, or it is a
191
+ terminal known to (iTerm2, WezTerm, Ghostty, kitty, VS Code's), or
192
+ WRENCODE_TRUECOLOR=1 says it does. Terminal.app and a tmux without
193
+ truecolor configured do not, and get the nearest of 256 colors instead."""
194
+ env = os.environ if env is None else env
195
+ if env.get("WRENCODE_TRUECOLOR", "").lower() in ("1", "true", "yes"):
196
+ return True
197
+ if env.get("WRENCODE_TRUECOLOR", "").lower() in ("0", "false", "no"):
198
+ return False
199
+ if env.get("COLORTERM", "").lower() in ("truecolor", "24bit"):
200
+ return True
201
+ return env.get("TERM_PROGRAM", "") in ("iTerm.app", "WezTerm", "ghostty", "vscode")
202
+
203
+
204
+ TRUECOLOR = supports_truecolor()
205
+
206
+
207
+ def nearest_256(r: int, g: int, b: int) -> int:
208
+ """The index of the closest color in the xterm 256-color table."""
209
+ steps = (0, 95, 135, 175, 215, 255)
210
+
211
+ def near(v: int) -> int:
212
+ return min(range(6), key=lambda i: abs(steps[i] - v))
213
+
214
+ cr, cg, cb = near(r), near(g), near(b)
215
+ cube = 16 + 36 * cr + 6 * cg + cb
216
+ cube_dist = (steps[cr] - r) ** 2 + (steps[cg] - g) ** 2 + (steps[cb] - b) ** 2
217
+ grey_level = max(0, min(23, round((((r + g + b) / 3) - 8) / 10)))
218
+ grey = 8 + 10 * grey_level
219
+ grey_dist = (grey - r) ** 2 + (grey - g) ** 2 + (grey - b) ** 2
220
+ return 232 + grey_level if grey_dist < cube_dist else cube
221
+
222
+
189
223
  def truecolor(hex_color: str) -> str:
190
- """An SGR for a "#rrggbb" or "#rrggbbaa" color (the alpha is ignored)."""
224
+ """An SGR for a "#rrggbb" or "#rrggbbaa" color (the alpha is ignored):
225
+ 24-bit where the terminal takes it, else the nearest of 256 colors."""
191
226
  h = hex_color.strip().lstrip("#")
192
227
  if len(h) not in (6, 8) or any(c not in "0123456789abcdefABCDEF" for c in h):
193
228
  raise ValueError(f"not a color: {hex_color!r}")
194
229
  r, g, b = (int(h[i : i + 2], 16) for i in (0, 2, 4))
195
- return f"\033[38;2;{r};{g};{b}m"
230
+ if TRUECOLOR:
231
+ return f"\033[38;2;{r};{g};{b}m"
232
+ return f"\033[38;5;{nearest_256(r, g, b)}m"
196
233
 
197
234
 
198
235
  def palette_from_zed(style: dict[str, Any]) -> Palette:
File without changes
File without changes
File without changes
File without changes
File without changes