{"slug": "show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or", "title": "Show HN: jev-bisect – Find answers with Jev via higher, lower, or", "summary": "A new Python library, jev-bisect, lets developers find numeric answers by having the Jev model make repeated higher, lower, or exactly decisions, using the official TypeSafe Python SDK. The package requires Python 3.10 or newer, installs via pip, and exposes a bisect function taking a question plus required min and max bounds, with a SearchConfig offering a default precision of 1 and max_turns of 20. Results are returned only after Jev selects exactly and include answer, turns, final state, and history recording state, choice, confidence, probabilities, and model version.", "body_md": "Find numeric answers with Jev through repeated `higher`, `lower`, or `exactly`\ndecisions. Supply a question and bounds; the library calculates the guesses\nusing the official [TypeSafe Python SDK](https://docs.typesafe.ai/sdk/python).\n\nRequires Python 3.10 or newer. Install from PyPI:\n\n```\npip install jev-bisect\nexport TYPESAFE_API_KEY=\"your-typesafe-api-key\"\npython\nfrom jev_bisect import bisect\n\nresult = bisect(\n    \"How many slices in a pizza?\",\n    min=0,\n    max=100,\n)\nprint(result.answer)\nprint(result.turns)\n```\n\n`min` and `max` are required keyword arguments and must be finite numbers with\n**`min < max`**. Omit `last_guess` or pass `None` to start at the midpoint.\nTo choose the first guess, supply an override such as\n`bisect(question, min=0, max=100, last_guess=25)`.\n\nA result is returned only after Jev selects `exactly`. It contains `answer`,\n`turns`, the final `state`, and `history`. Each history entry records the\nstate, choice, confidence, probabilities, and model version.\n\n``` python\nfrom jev_bisect import SearchConfig, bisect\n\nresult = bisect(\n    \"What is pi?\",\n    min=3,\n    max=4,\n    config=SearchConfig(precision=0.01, max_turns=10),\n)\nprint(result.answer)  # 3.14 if Jev makes the correct comparisons\n```\n\n| Field | Default | Meaning | \n|---|---|---|\n| `precision` | `1` | Smallest search increment; a positive finite `int` or`float` . | \n| `max_turns` | `20` | Maximum evaluated guesses; an integer from 1 through 20. | \n\nOmitting `config` or passing `None` uses these defaults. Both settings belong\nin `SearchConfig`. Each evaluated guess counts as one turn, including the\ninitial midpoint. SDK retries are disabled for these calls.\n\nCandidates are multiples of `precision` measured from zero: `1` searches\nwhole numbers, `0.01` searches hundredths, and `2.5` searches values such as\n`0`, `2.5`, and `5`. Jev is instructed to round the answer to the nearest\nmultiple before comparing, with halfway values rounded away from zero.\nPrecision specifies search resolution, not significant digits or an error\ntolerance.\n\nAfter `higher` or `lower`, the current guess is excluded and the next guess\nis the floor midpoint of the remaining candidates. For `min=0, max=100` at\ndefault precision, the choices `higher`, `lower`, `exactly` evaluate `50`,\n`75`, and `62`. Rounding down also applies to negative numbers: the first\nguess for `min=-5, max=0` is `-3`.\n\nBounds snap inward to the candidate grid. With `min=0.001, max=0.019` and\nprecision 0.01, the only candidate is `0.01`. With `min=0.1, max=5.9` and\nprecision 1, candidates are the integers 1 through 5. Any explicit\n`last_guess` must be within the bounds and a multiple of `precision`.\n\nEndpoints on the grid are reachable. A valid search may narrow internally to\none candidate, which still needs an `exactly` decision. Choose bounds that\ncontain the rounded answer; the search does not expand them. A large range\nor fine precision may require more guesses than the configured limit, and\nJev can make incorrect comparisons.\n\nGuesses use exact rational arithmetic and integer candidate indexes internally.\nWhole-number increments, including `1.0`, return integers; fractional increments\nreturn floats. Trailing zeros are not preserved.\n\n| Exception | Condition | \n|---|---|\n| `ValueError` | Invalid bounds ( `bisect` requires`min < max` ), config, question, model, or starting guess. | \n| `SearchExhaustedError` | No candidate within bounds, no possible next guess, or a candidate cannot be represented as a float at the configured precision. | \n| `MaxTurnsExceededError` | No `exactly` decision within`max_turns` . | \n\nFailures during the model loop include the last evaluated `state` and completed\n`history`; `MaxTurnsExceededError` also includes `max_turns`. Exhaustion before\nany evaluation has `state=None` and empty history. SDK errors propagate.\n\n``` python\nfrom jev_bisect import MaxTurnsExceededError, SearchExhaustedError, bisect\n\ntry:\n    result = bisect(\"How many minutes are in three hours?\", min=0, max=300)\nexcept (MaxTurnsExceededError, SearchExhaustedError) as error:\n    print(error)\n    print(error.state, error.history)\nelse:\n    print(result.answer)\n```\n\n`advance` performs one step without an API call and returns a `SearchState`.\nWhen `last_guess` is omitted, the choice applies to the bounds' midpoint.\nSupply the returned bounds and guess for the next step, using the same config.\nIf the returned bounds are equal, pass `last_guess` to evaluate the remaining\ncandidate: `exactly` returns that state, while `higher` or `lower` raises\n`SearchExhaustedError`. Without `last_guess`, `advance` requires `min < max`.\n\n``` python\nfrom jev_bisect import advance\n\nstate = advance(\"higher\", min=0, max=100)\nassert state.to_dict() == {\"max\": 100, \"min\": 51, \"last_guess\": 75}\n\nstate = advance(\"lower\", min=state.min, max=state.max, last_guess=state.last_guess)\nassert state.last_guess == 62\npython\nfrom typesafe_sdk import TypeSafeClient\nfrom jev_bisect import bisect\n\nwith TypeSafeClient() as client:\n    result = bisect(\n        \"How many centimeters are in three quarters of a meter?\",\n        min=0,\n        max=100,\n        client=client,\n        model=\"jev-1.13.0\",\n    )\n```\n\nThe default model is [`jev-latest`](https://docs.typesafe.ai/models). A supplied\nclient remains open; otherwise, `bisect` creates and closes its own client on\nsuccess or error.\n\n```\npip install -e '.[dev]'\npytest\nruff check .\npython -m build\n```\n\nTests use deterministic responses and a mock HTTP transport, requiring no API key or network requests.\n\nUpdate `version` in `pyproject.toml` for each new release, then build and check\nthe wheel and source distribution:\n\n```\npip install -e '.[dev,release]'\npytest\nruff check .\npython -m build\npython -m twine check --strict dist/*\n```\n\nThese commands prepare files locally. When ready to publish, set\n`TWINE_USERNAME=__token__` and `TWINE_PASSWORD` to a PyPI API token, then upload\nonly the files for that release:\n\n```\npython -m twine upload dist/jev_bisect-0.1.0-py3-none-any.whl dist/jev_bisect-0.1.0.tar.gz\n```\n\nMIT; see [LICENSE](https://github.com/mkly/jev-bisect/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or", "canonical_source": "https://github.com/mkly/jev-bisect", "published_at": "2026-10-08 18:40:33+00:00", "updated_at": "2026-10-08 18:47:46.875342+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "large-language-models", "ai-products"], "entities": ["jev-bisect", "Jev", "TypeSafe", "TypeSafe Python SDK", "PyPI", "SearchConfig", "MaxTurnsExceededError", "SearchExhaustedError"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or", "markdown": "https://wpnews.pro/news/show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or.md", "text": "https://wpnews.pro/news/show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or.txt", "jsonld": "https://wpnews.pro/news/show-hn-jev-bisect-find-answers-with-jev-via-higher-lower-or.jsonld"}}