mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-20 14:42:28 +02:00
Bumps the minor-and-patch group in /libs/cli with 5 updates: | Package | From | To | | --- | --- | --- | | [click](https://github.com/pallets/click) | `8.4.1` | `8.4.2` | | [pytest](https://github.com/pytest-dev/pytest) | `9.0.3` | `9.1.1` | | [ruff](https://github.com/astral-sh/ruff) | `0.15.15` | `0.15.20` | | [ty](https://github.com/astral-sh/ty) | `0.0.43` | `0.0.55` | | [hatch](https://github.com/pypa/hatch) | `1.16.5` | `1.17.0` | Updates `click` from 8.4.1 to 8.4.2 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pallets/click/releases">click's releases</a>.</em></p> <blockquote> <h2>8.4.2</h2> <p>This is the Click 8.4.1 fix release, which fixes bugs but does not otherwise change behavior and should not result in breaking changes compared to the latest feature release.</p> <p>PyPI: <a href="https://pypi.org/project/click/8.4.2/">https://pypi.org/project/click/8.4.2/</a> Changes: <a href="https://click.palletsprojects.com/page/changes/#version-8-4-2">https://click.palletsprojects.com/page/changes/#version-8-4-2</a> Milestone: <a href="https://github.com/pallets/click/milestone/34">https://github.com/pallets/click/milestone/34</a></p> <ul> <li>Fix Fish shell completion broken in <code>8.4.0</code> by <a href="https://redirect.github.com/pallets/click/issues/3126">#3126</a>. Newlines and tabs in option help text are now escaped, keeping the original completion format while still supporting multi-line help. <a href="https://redirect.github.com/pallets/click/issues/3502">#3502</a> <a href="https://redirect.github.com/pallets/click/issues/3043">#3043</a> <a href="https://redirect.github.com/pallets/click/issues/3504">#3504</a> <a href="https://redirect.github.com/pallets/click/issues/3508">#3508</a></li> <li>Deprecated commands and options with empty or missing help text no longer render a stray leading space before the <code>(DEPRECATED)</code> label. <a href="https://redirect.github.com/pallets/click/issues/3509">#3509</a></li> <li>A {class}<code>Group</code> with <code>invoke_without_command=True</code> marks its subcommand as optional in the usage help, showing <code>[COMMAND]</code> instead of <code>COMMAND</code>. <a href="https://redirect.github.com/pallets/click/issues/3059">#3059</a> <a href="https://redirect.github.com/pallets/click/issues/3507">#3507</a></li> <li><code>echo_via_pager</code> flushes after each write, so passing a generator streams output to the pager incrementally instead of staying hidden until the pipe buffer fills. <a href="https://redirect.github.com/pallets/click/issues/3242">#3242</a> <a href="https://redirect.github.com/pallets/click/issues/2542">#2542</a> <a href="https://redirect.github.com/pallets/click/issues/3534">#3534</a></li> <li><code>echo_via_pager</code> and <code>get_pager_file</code> no longer close a borrowed stdout stream when no external pager runs, completing the partial <code>I/O operation on closed file</code> fix from <a href="https://redirect.github.com/pallets/click/issues/3482">#3482</a>. <a href="https://redirect.github.com/pallets/click/issues/3449">#3449</a> <a href="https://redirect.github.com/pallets/click/issues/3533">#3533</a></li> <li>Fix CLI usage symopsis for optional arguments producing double square brackets <code>[[a|b|c]]...</code> whose type already brackets their metavar. <a href="https://redirect.github.com/pallets/click/issues/3578">#3578</a></li> <li>{func}<code>version_option</code> resolves a <code>package_name</code> that does not match an installed distribution as an import (top-level module) name via {func}<code>importlib.metadata.packages_distributions</code>. Packages whose top-level module name differs from their distribution name (<code>PIL</code> vs <code>Pillow</code>, <code>jwt</code> vs <code>PyJWT</code>) no longer raise <code>RuntimeError</code> out of the box. <a href="https://redirect.github.com/pallets/click/issues/2331">#2331</a> <a href="https://redirect.github.com/pallets/click/issues/1884">#1884</a> <a href="https://redirect.github.com/pallets/click/issues/3125">#3125</a> <a href="https://redirect.github.com/pallets/click/issues/3582">#3582</a></li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pallets/click/blob/main/CHANGES.md">click's changelog</a>.</em></p> <blockquote> <h2>Version 8.4.2</h2> <p>Released 2026-06-24</p> <ul> <li>Fix Fish shell completion broken in <code>8.4.0</code> by {pr}<code>3126</code>. Newlines and tabs in option help text are now escaped, keeping the original completion format while still supporting multi-line help. {issue}<code>3502</code> {issue}<code>3043</code> {pr}<code>3504</code> {pr}<code>3508</code></li> <li>Deprecated commands and options with empty or missing help text no longer render a stray leading space before the <code>(DEPRECATED)</code> label. {pr}<code>3509</code></li> <li>A {class}<code>Group</code> with <code>invoke_without_command=True</code> marks its subcommand as optional in the usage help, showing <code>[COMMAND]</code> instead of <code>COMMAND</code>. {issue}<code>3059</code> {pr}<code>3507</code></li> <li><code>echo_via_pager</code> flushes after each write, so passing a generator streams output to the pager incrementally instead of staying hidden until the pipe buffer fills. {issue}<code>3242</code> {issue}<code>2542</code> {pr}<code>3534</code></li> <li><code>echo_via_pager</code> and <code>get_pager_file</code> no longer close a borrowed stdout stream when no external pager runs, completing the partial <code>I/O operation on closed file</code> fix from {pr}<code>3482</code>. {issue}<code>3449</code> {pr}<code>3533</code></li> <li>Fix CLI usage symopsis for optional arguments producing double square brackets <code>[[a|b|c]]...</code> whose type already brackets their metavar. {pr}<code>3578</code></li> <li>{func}<code>version_option</code> resolves a <code>package_name</code> that does not match an installed distribution as an import (top-level module) name via {func}<code>importlib.metadata.packages_distributions</code>. Packages whose top-level module name differs from their distribution name (<code>PIL</code> vs <code>Pillow</code>, <code>jwt</code> vs <code>PyJWT</code>) no longer raise <code>RuntimeError</code> out of the box. {issue}<code>2331</code> {issue}<code>1884</code> {issue}<code>3125</code> {pr}<code>3582</code></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pallets/click/commit/b2e30a175449cfda909ee4fbf4a29a6a071cad53"><code>b2e30a1</code></a> Release version 8.4.2</li> <li><a href="https://github.com/pallets/click/commit/7a16b20e8a8a9bb57c7b4f6f15f60f6597478a49"><code>7a16b20</code></a> Fix <code>package_name</code> resolution when module differs from distribution name (<a href="https://redirect.github.com/pallets/click/issues/3582">#3582</a>)</li> <li><a href="https://github.com/pallets/click/commit/bec59289d8cf9b9b4010642b2fee483e5f8eeefc"><code>bec5928</code></a> Fix <code>package_name</code> resolution when top-level module differs from distribution...</li> <li><a href="https://github.com/pallets/click/commit/916883afad450c0c9bbc4212817900949131adbd"><code>916883a</code></a> Fix tests to not rely on <code>-Wdefault</code> option (<a href="https://redirect.github.com/pallets/click/issues/3591">#3591</a>)</li> <li><a href="https://github.com/pallets/click/commit/09195f6a92972c4e1bbb5493686456e6ba624520"><code>09195f6</code></a> Fix double-bracketing of choices in synopsis (<a href="https://redirect.github.com/pallets/click/issues/3578">#3578</a>)</li> <li><a href="https://github.com/pallets/click/commit/1557e265222c431b1e4d6c4dd6754006ed10dc02"><code>1557e26</code></a> Check for warning exception with idiomatic context manager</li> <li><a href="https://github.com/pallets/click/commit/d9ff13369ac78d9acff693faa79f26badd566ab3"><code>d9ff133</code></a> Static typing improvements in <code>click.shell_completion</code> (<a href="https://redirect.github.com/pallets/click/issues/3460">#3460</a>)</li> <li><a href="https://github.com/pallets/click/commit/762c97eef7c1b3779678992f26a553a2a8c80793"><code>762c97e</code></a> Fix double-bracketing of choices in synopsis</li> <li><a href="https://github.com/pallets/click/commit/8929d392781c8113bc569f388c15c47b94f86581"><code>8929d39</code></a> Convert changes to markdown. (<a href="https://redirect.github.com/pallets/click/issues/3559">#3559</a>)</li> <li><a href="https://github.com/pallets/click/commit/237be507dbe3e653f6b41b3ea53266805534e8cd"><code>237be50</code></a> Move changes headings down a level.</li> <li>Additional commits viewable in <a href="https://github.com/pallets/click/compare/8.4.1...8.4.2">compare view</a></li> </ul> </details> <br /> Updates `pytest` from 9.0.3 to 9.1.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest/releases">pytest's releases</a>.</em></p> <blockquote> <h2>9.1.1</h2> <h1>pytest 9.1.1 (2026-06-19)</h1> <h2>Bug fixes</h2> <ul> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14220">#14220</a>: Fixed a logic bug in <code>pytest.RaisesGroup</code> which would might cause it to display incorrect "It matches <!-- raw HTML omitted -->FooError()<!-- raw HTML omitted --> which was paired with <!-- raw HTML omitted -->BarError<!-- raw HTML omitted -->" messages.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14591">#14591</a>: Fixed a regression in pytest 9.1.0 which caused overriding a parametrized fixture with an indirect <!-- raw HTML omitted --><a href="https://github.com/pytest"><code>@pytest</code></a>.mark.parametrize<!-- raw HTML omitted --> to fail with "duplicate parametrization of '<fixture name>'".</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14606">#14606</a>: Fixed <code>list-item</code> typing errors from mypy in <code>@pytest.mark.parametrize <pytest.mark.parametrize ref></code> <code>argvalues</code> parameter.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14608">#14608</a>: Fixed a regression in pytest 9.1.0 where <code>conftest.py</code> files located in <code><invocation dir>/test*</code> were no longer loaded as initial conftests when invoked without arguments. This could cause certain hooks (like <code>pytest_addoption</code>) in these files to not fire.</li> </ul> <h2>9.1.0</h2> <h1>pytest 9.1.0 (2026-06-13)</h1> <h2>Removals and backward incompatible breaking changes</h2> <ul> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/14533">#14533</a>: When using <code>--doctest-modules</code>, autouse fixtures with <code>module</code>, <code>package</code> or <code>session</code> scope that are defined inline in Python test modules (not plugins or conftests) will now possibly execute twice.</p> <p>If this is undesirable, move the fixture definition to a <code>conftest.py</code> file if possible.</p> <p>Technical explanation for those interested: When using <!-- raw HTML omitted -->--doctest-modules<!-- raw HTML omitted -->, pytest possibly collects Python modules twice, once as <code>pytest.Module</code> and once as a <code>DoctestModule</code> (depending on the configuration). Due to improvements in pytest's fixture implementation, if e.g. the <code>DoctestModule</code> collects a fixture, it is now visible to it only, and not to the <code>Module</code>. This means that both need to register the fixtures independently.</p> </li> </ul> <h2>Deprecations (removal in next major release)</h2> <ul> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/10819">#10819</a>: Added a deprecation warning for class-scoped fixtures defined as instance methods (without <code>@classmethod</code>). Such fixtures set attributes on a different instance than the test methods use, leading to unexpected behavior. Use <code>@classmethod</code> decorator instead -- by <code>yastcher</code>.</p> <p>See <code>10819</code> and <code>14011</code>.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/12882">#12882</a>: Calling <code>request.getfixturevalue() <pytest.FixtureRequest.getfixturevalue></code> during teardown to request a fixture that was not already requested is now deprecated and will become an error in pytest 10.</p> <p>See <code>dynamic-fixture-request-during-teardown</code> for details.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13409">#13409</a>: Using non-<code>~collections.abc.Collection</code> iterables (such as generators, iterators, or custom iterable objects) for the <code>argvalues</code> parameter in <code>@pytest.mark.parametrize <pytest.mark.parametrize ref></code> and <code>metafunc.parametrize <pytest.Metafunc.parametrize></code> is now deprecated.</p> <p>These iterables get exhausted after the first iteration, leading to tests getting unexpectedly skipped in cases such as running <code>pytest.main()</code> multiple times, using class-level parametrize decorators, or collecting tests multiple times.</p> <p>See <code>parametrize-iterators</code> for details and suggestions.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13946">#13946</a>: The private <code>config.inicfg</code> attribute is now deprecated. Use <code>config.getini() <pytest.Config.getini></code> to access configuration values instead.</p> <p>See <code>config-inicfg</code> for more details.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/14004">#14004</a>: Passing <code>baseid</code> to <code>~pytest.FixtureDef</code> or <code>nodeid</code> strings to fixture registration APIs is now deprecated. These are internal pytest APIs that are used by some plugins.</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pytest-dev/pytest/commit/cf470ec0bf7eb89cd97dd56df4859eae5db46447"><code>cf470ec</code></a> Prepare release version 9.1.1</li> <li><a href="https://github.com/pytest-dev/pytest/commit/e0c8ce6cc5db1f08363be6f152c32e6838df2690"><code>e0c8ce6</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14625">#14625</a> from pytest-dev/patchback/backports/9.1.x/a07c31a97...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/1b82d1694fce22385ee7a4287917fbafbaf2e757"><code>1b82d16</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14624">#14624</a> from pytest-dev/patchback/backports/9.1.x/b375b79ec...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/501c4bc784da3b08bfcaa64858eba5d15dc59e53"><code>501c4bc</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14596">#14596</a> from bluetech/doc-classmethod</li> <li><a href="https://github.com/pytest-dev/pytest/commit/b61f588e36e9377c3d1d3f06bece1da0fc31d9ca"><code>b61f588</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14622">#14622</a> from chrisburr/fix-14608-initial-conftest-test-subdir</li> <li><a href="https://github.com/pytest-dev/pytest/commit/9a567e009f4d2da3ce1721c6db3109cb5744d40a"><code>9a567e0</code></a> [automated] Update plugin list (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14617">#14617</a>) (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14618">#14618</a>)</li> <li><a href="https://github.com/pytest-dev/pytest/commit/ef8b2993e5b48639e4a3d97d0525df9760781384"><code>ef8b299</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14620">#14620</a> from pytest-dev/patchback/backports/9.1.x/680f9f3ed...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/66abd0784d4cb7c1ba44ab9a8896506cd4985acc"><code>66abd07</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14220">#14220</a> from bysiber/fix-stale-iexp-raisesgroup</li> <li><a href="https://github.com/pytest-dev/pytest/commit/79fbf93b666cac5f27c9dad047943d47b766c8d5"><code>79fbf93</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14612">#14612</a> from pytest-dev/patchback/backports/9.1.x/974ed48b6...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/0d312eb876177e9f1c04262b54060a41034ebf5c"><code>0d312eb</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14611">#14611</a> from bluetech/parametrize-argvalues-typing</li> <li>Additional commits viewable in <a href="https://github.com/pytest-dev/pytest/compare/9.0.3...9.1.1">compare view</a></li> </ul> </details> <br /> Updates `ruff` from 0.15.15 to 0.15.20 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p> <blockquote> <h2>0.15.20</h2> <h2>Release Notes</h2> <p>Released on 2026-06-25.</p> <h3>Preview features</h3> <ul> <li>Allow human-readable names in rule selectors (<a href="https://redirect.github.com/astral-sh/ruff/pull/25887">#25887</a>)</li> <li>Emit a warning instead of an error for unknown rule selectors (<a href="https://redirect.github.com/astral-sh/ruff/pull/26113">#26113</a>)</li> <li>Match <code>noqa</code> shebang handling in <code>ruff:ignore</code> comments (<a href="https://redirect.github.com/astral-sh/ruff/pull/26286">#26286</a>)</li> <li>[<code>ruff</code>] Remove <code>pytest-fixture-autouse</code> (<code>RUF076</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26240">#26240</a>, <a href="https://redirect.github.com/astral-sh/ruff/pull/26371">#26371</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Add versioning sections to custom crate READMEs (<a href="https://redirect.github.com/astral-sh/ruff/pull/26317">#26317</a>)</li> <li>Update <code>ruff_python_parser</code> README for crates.io (<a href="https://redirect.github.com/astral-sh/ruff/pull/26315">#26315</a>)</li> <li>[<code>perflint</code>] Clarify that <code>PERF402</code> applies to any iterable (<a href="https://redirect.github.com/astral-sh/ruff/pull/26242">#26242</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/dhruvmanila"><code>@dhruvmanila</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/trilamsr"><code>@trilamsr</code></a></li> </ul> <h2>Install ruff 0.15.20</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-installer.sh | sh </code></pre> <h3>Install prebuilt binaries via powershell script</h3> <pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c "irm https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-installer.ps1 | iex" </code></pre> <h2>Download ruff 0.15.20</h2> <table> <thead> <tr> <th>File</th> <th>Platform</th> <th>Checksum</th> </tr> </thead> <tbody> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td> <td>Apple Silicon macOS</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td> <td>Intel macOS</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td> <td>ARM64 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td> <td>x86 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-pc-windows-msvc.zip">ruff-x86_64-pc-windows-msvc.zip</a></td> <td>x64 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-unknown-linux-gnu.tar.gz">ruff-aarch64-unknown-linux-gnu.tar.gz</a></td> <td>ARM64 Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-unknown-linux-gnu.tar.gz">ruff-i686-unknown-linux-gnu.tar.gz</a></td> <td>x86 Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> </tbody> </table> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p> <blockquote> <h2>0.15.20</h2> <p>Released on 2026-06-25.</p> <h3>Preview features</h3> <ul> <li>Allow human-readable names in rule selectors (<a href="https://redirect.github.com/astral-sh/ruff/pull/25887">#25887</a>)</li> <li>Emit a warning instead of an error for unknown rule selectors (<a href="https://redirect.github.com/astral-sh/ruff/pull/26113">#26113</a>)</li> <li>Match <code>noqa</code> shebang handling in <code>ruff:ignore</code> comments (<a href="https://redirect.github.com/astral-sh/ruff/pull/26286">#26286</a>)</li> <li>[<code>ruff</code>] Remove <code>pytest-fixture-autouse</code> (<code>RUF076</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26240">#26240</a>, <a href="https://redirect.github.com/astral-sh/ruff/pull/26371">#26371</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Add versioning sections to custom crate READMEs (<a href="https://redirect.github.com/astral-sh/ruff/pull/26317">#26317</a>)</li> <li>Update <code>ruff_python_parser</code> README for crates.io (<a href="https://redirect.github.com/astral-sh/ruff/pull/26315">#26315</a>)</li> <li>[<code>perflint</code>] Clarify that <code>PERF402</code> applies to any iterable (<a href="https://redirect.github.com/astral-sh/ruff/pull/26242">#26242</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/dhruvmanila"><code>@dhruvmanila</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/trilamsr"><code>@trilamsr</code></a></li> </ul> <h2>0.15.19</h2> <p>Released on 2026-06-23.</p> <h3>Preview features</h3> <ul> <li>Support human-readable names when hovering suppression comments and in code actions (<a href="https://redirect.github.com/astral-sh/ruff/pull/26114">#26114</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>Fall back to default settings when editor-only settings are invalid (<a href="https://redirect.github.com/astral-sh/ruff/pull/26244">#26244</a>)</li> <li>Fix panic when inserting text at a notebook cell boundary (<a href="https://redirect.github.com/astral-sh/ruff/pull/26111">#26111</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>[<code>pylint</code>] Update fix suggestions for <code>__floor__</code>, <code>__trunc__</code>, <code>__length_hint__</code>, and <code>__matmul__</code> variants (<code>PLC2801</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26239">#26239</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid allocating when parsing single string literals (<a href="https://redirect.github.com/astral-sh/ruff/pull/26200">#26200</a>)</li> <li>Avoid reallocating singleton call arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/26223">#26223</a>)</li> <li>Lazily create source files for lint diagnostics (<a href="https://redirect.github.com/astral-sh/ruff/pull/26226">#26226</a>)</li> <li>Optimize formatter text width and indentation (<a href="https://redirect.github.com/astral-sh/ruff/pull/26236">#26236</a>)</li> <li>Reserve capacity for builtin bindings (<a href="https://redirect.github.com/astral-sh/ruff/pull/26229">#26229</a>)</li> <li>Skip repeated-key checks for singleton dictionaries (<a href="https://redirect.github.com/astral-sh/ruff/pull/26228">#26228</a>)</li> <li>Use ArrayVec for qualified name segments (<a href="https://redirect.github.com/astral-sh/ruff/pull/26224">#26224</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ruff/commit/f82a36b6baf8c0547a17bbde6c0d927ccd45d938"><code>f82a36b</code></a> Bump 0.15.20 (<a href="https://redirect.github.com/astral-sh/ruff/issues/26376">#26376</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/af329438b55d5aa8ca28725f17abbae63b5c815d"><code>af32943</code></a> Improve the summarise-ecosystem-results skill (<a href="https://redirect.github.com/astral-sh/ruff/issues/26378">#26378</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/485ebab5de692aad34720898cd80245b6092ba86"><code>485ebab</code></a> Remove <code>RUF076</code> name from schema (<a href="https://redirect.github.com/astral-sh/ruff/issues/26371">#26371</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/ef81835ce3da615346584dc446de0fe26bfc154b"><code>ef81835</code></a> [ty] Implement rust-analyzer's "Click for full compiler diagnostic" feature (...</li> <li><a href="https://github.com/astral-sh/ruff/commit/572b31e2377a701a7365f069f6ef87002962cb2b"><code>572b31e</code></a> [<code>ruff</code>] Remove <code>pytest-fixture-autouse</code> (<code>RUF076</code>) (<a href="https://redirect.github.com/astral-sh/ruff/issues/26240">#26240</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/f703f219d7fddd1a4abba9fa81e34773c185a4b9"><code>f703f21</code></a> Allow human-readable names in rule selectors (<a href="https://redirect.github.com/astral-sh/ruff/issues/25887">#25887</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/0d726b28ee35413926145ffef4ac1143cae9ea1e"><code>0d726b2</code></a> [ty] Reuse equality semantics for membership compatibility (<a href="https://redirect.github.com/astral-sh/ruff/issues/25955">#25955</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/dbe6e9848c3f78fdaf543cfc000939ebc73b5f00"><code>dbe6e98</code></a> [ty] Infer definite equality comparison results (<a href="https://redirect.github.com/astral-sh/ruff/issues/26337">#26337</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/e700ea357a2196d76b58eb89b2031ddb5ca896e0"><code>e700ea3</code></a> [ty] Prove TypedDict structural patterns exhaustive (<a href="https://redirect.github.com/astral-sh/ruff/issues/26285">#26285</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/6a0d2ec93959d966430b8c39d4de5c3e8a88e911"><code>6a0d2ec</code></a> [ty] Widen inferred class-valued instance attributes (<a href="https://redirect.github.com/astral-sh/ruff/issues/26338">#26338</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ruff/compare/0.15.15...0.15.20">compare view</a></li> </ul> </details> <br /> Updates `ty` from 0.0.43 to 0.0.55 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/releases">ty's releases</a>.</em></p> <blockquote> <h2>0.0.55</h2> <h2>Release Notes</h2> <p>Released on 2026-06-26.</p> <h3>LSP server</h3> <ul> <li>Render full diagnostics in color (<a href="https://redirect.github.com/astral-sh/ruff/pull/26384">#26384</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Document colored diagnostic output (<a href="https://redirect.github.com/astral-sh/ty/pull/3858">#3858</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Improve vendored filesystem concurrency (<a href="https://redirect.github.com/astral-sh/ruff/pull/26408">#26408</a>)</li> <li>Optimize enum comparisons in equality evaluation (<a href="https://redirect.github.com/astral-sh/ruff/pull/26340">#26340</a>)</li> <li>Remove redundant semantic index shrinks (<a href="https://redirect.github.com/astral-sh/ruff/pull/26392">#26392</a>)</li> <li>Use never-change durability for one-shot checks (<a href="https://redirect.github.com/astral-sh/ruff/pull/26359">#26359</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Correct enum alias detection and scalar constructors (<a href="https://redirect.github.com/astral-sh/ruff/pull/26345">#26345</a>)</li> <li>Fix structural pattern binding inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/26411">#26411</a>)</li> <li>Improve variable-length tuple slicing (<a href="https://redirect.github.com/astral-sh/ruff/pull/26151">#26151</a>)</li> <li>Infer class and mapping pattern bindings (<a href="https://redirect.github.com/astral-sh/ruff/pull/25941">#25941</a>)</li> <li>Infer empty collection constructors from later uses (<a href="https://redirect.github.com/astral-sh/ruff/pull/26389">#26389</a>)</li> <li>Skip shadowed submodule bindings during import analysis (<a href="https://redirect.github.com/astral-sh/ruff/pull/26385">#26385</a>)</li> <li>Sync vendored typeshed stubs (<a href="https://redirect.github.com/astral-sh/ruff/pull/26406">#26406</a>). <a href="https://github.com/python/typeshed/compare/8e6a886ca5b14742924be721d345a619762d6e93...3c6221722aac5bd9dbfc5fbf7b4f0bf64b2c5724">Typeshed diff</a></li> <li>Track literal iterable emptiness for reachability (<a href="https://redirect.github.com/astral-sh/ruff/pull/25222">#25222</a>)</li> <li>Validate positional class patterns against <code>__match_args__</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/26195">#26195</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/carljm"><code>@carljm</code></a></li> <li><a href="https://github.com/AlexWaygood"><code>@AlexWaygood</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/mtshiba"><code>@mtshiba</code></a></li> <li><a href="https://github.com/felixscherz"><code>@felixscherz</code></a></li> </ul> <h2>Install ty 0.0.55</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://releases.astral.sh/github/ty/releases/download/0.0.55/ty-installer.sh | sh </code></pre> <h3>Install prebuilt binaries via powershell script</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/blob/main/CHANGELOG.md">ty's changelog</a>.</em></p> <blockquote> <h2>0.0.55</h2> <p>Released on 2026-06-26.</p> <h3>LSP server</h3> <ul> <li>Render full diagnostics in color (<a href="https://redirect.github.com/astral-sh/ruff/pull/26384">#26384</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Document colored diagnostic output (<a href="https://redirect.github.com/astral-sh/ty/pull/3858">#3858</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Improve vendored filesystem concurrency (<a href="https://redirect.github.com/astral-sh/ruff/pull/26408">#26408</a>)</li> <li>Optimize enum comparisons in equality evaluation (<a href="https://redirect.github.com/astral-sh/ruff/pull/26340">#26340</a>)</li> <li>Remove redundant semantic index shrinks (<a href="https://redirect.github.com/astral-sh/ruff/pull/26392">#26392</a>)</li> <li>Use never-change durability for one-shot checks (<a href="https://redirect.github.com/astral-sh/ruff/pull/26359">#26359</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Correct enum alias detection and scalar constructors (<a href="https://redirect.github.com/astral-sh/ruff/pull/26345">#26345</a>)</li> <li>Fix structural pattern binding inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/26411">#26411</a>)</li> <li>Improve variable-length tuple slicing (<a href="https://redirect.github.com/astral-sh/ruff/pull/26151">#26151</a>)</li> <li>Infer class and mapping pattern bindings (<a href="https://redirect.github.com/astral-sh/ruff/pull/25941">#25941</a>)</li> <li>Infer empty collection constructors from later uses (<a href="https://redirect.github.com/astral-sh/ruff/pull/26389">#26389</a>)</li> <li>Skip shadowed submodule bindings during import analysis (<a href="https://redirect.github.com/astral-sh/ruff/pull/26385">#26385</a>)</li> <li>Sync vendored typeshed stubs (<a href="https://redirect.github.com/astral-sh/ruff/pull/26406">#26406</a>). <a href="https://github.com/python/typeshed/compare/8e6a886ca5b14742924be721d345a619762d6e93...3c6221722aac5bd9dbfc5fbf7b4f0bf64b2c5724">Typeshed diff</a></li> <li>Track literal iterable emptiness for reachability (<a href="https://redirect.github.com/astral-sh/ruff/pull/25222">#25222</a>)</li> <li>Validate positional class patterns against <code>__match_args__</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/26195">#26195</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/carljm"><code>@carljm</code></a></li> <li><a href="https://github.com/AlexWaygood"><code>@AlexWaygood</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/mtshiba"><code>@mtshiba</code></a></li> <li><a href="https://github.com/felixscherz"><code>@felixscherz</code></a></li> </ul> <h2>0.0.54</h2> <p>Released on 2026-06-25.</p> <h3>Bug fixes</h3> <ul> <li>Avoid duplicate configuration error output (<a href="https://redirect.github.com/astral-sh/ruff/pull/26375">#26375</a>)</li> <li>Avoid stack overflows in reachability analysis (<a href="https://redirect.github.com/astral-sh/ruff/pull/26272">#26272</a>)</li> <li>Fix divergent recursive tuple cycle handling in ty (<a href="https://redirect.github.com/astral-sh/ruff/pull/26316">#26316</a>)</li> <li>Fix panic from relation queries during cycle recovery (<a href="https://redirect.github.com/astral-sh/ruff/pull/26335">#26335</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ty/commit/42869400da56f4ee7ce752141f81b50bb318e4e2"><code>4286940</code></a> Bump version to 0.0.55 (<a href="https://redirect.github.com/astral-sh/ty/issues/3866">#3866</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/5374b30ff462ef6e59d23dc9ba515007b02464a8"><code>5374b30</code></a> Update benchmarks for ty 0.0.54 (<a href="https://redirect.github.com/astral-sh/ty/issues/3865">#3865</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/3ed874d053ff9529c9fd0205a6d3bbe6a7407535"><code>3ed874d</code></a> Document colored diagnostic output (<a href="https://redirect.github.com/astral-sh/ty/issues/3858">#3858</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/bf8a7dd584f53d67d873c750afc1494331f93502"><code>bf8a7dd</code></a> Bump version to 0.0.54</li> <li><a href="https://github.com/astral-sh/ty/commit/78e094dfaf6245514f124b043b18c9a20edd8f08"><code>78e094d</code></a> Document the <code>fullDiagnosticOutput</code> extension to the Language Server Protocol...</li> <li><a href="https://github.com/astral-sh/ty/commit/7bda89e5069d747bd7f54513dcd0263157a8f694"><code>7bda89e</code></a> Document ty's <code>@Todo</code> type in the typing FAQ (<a href="https://redirect.github.com/astral-sh/ty/issues/3847">#3847</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/66a94cde4970b405a770e4c6ef4ac2a9bb6bf733"><code>66a94cd</code></a> Update maturin to v1.14.0 (<a href="https://redirect.github.com/astral-sh/ty/issues/3840">#3840</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/dc2b39d1e29e55a4a6d83486fffa936ba5121a72"><code>dc2b39d</code></a> Update prek dependencies (<a href="https://redirect.github.com/astral-sh/ty/issues/3839">#3839</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/23f26f98a22d3a0df412846506f3af6e76cf48e4"><code>23f26f9</code></a> Bump version to 0.0.53 (<a href="https://redirect.github.com/astral-sh/ty/issues/3841">#3841</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/13f91b093e004c76aa548a221c7b577dfbdd7ea6"><code>13f91b0</code></a> Bump version to 0.0.52 (<a href="https://redirect.github.com/astral-sh/ty/issues/3828">#3828</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ty/compare/0.0.43...0.0.55">compare view</a></li> </ul> </details> <br /> Updates `hatch` from 1.16.5 to 1.17.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pypa/hatch/releases">hatch's releases</a>.</em></p> <blockquote> <h2>Hatchling v1.17.0</h2> <p><em><strong>Added:</strong></em></p> <ul> <li>The <code>app</code> build target now embeds the project version in the name of binaries</li> </ul> <h2>Hatch v1.17.0</h2> <p><em><strong>Changed:</strong></em></p> <ul> <li>The <code>hatch fmt</code> command is now deprecated in favor of the new <code>hatch check</code> command group</li> <li>Migrate HTTP client from <code>httpx</code> to <code>httpx2</code></li> </ul> <p><em><strong>Added:</strong></em></p> <ul> <li>Add <code>hatch check</code> command group with subcommands for <code>check code</code> (linting), <code>check fmt</code> (formatting), and <code>check types</code> (type checking)</li> <li>Add <code>hatch check types</code> command for type checking using Pyrefly, with <code>--summarize</code> and <code>--cover</code> flags</li> <li>Add <code>hatch env lock</code> command to generate PEP 751 compliant lockfiles (<code>pylock.toml</code>) for environments</li> <li>Add <code>hatch dep lock</code> and <code>hatch lock</code> commands as shortcuts for locking the active environment</li> <li>Add <code>hatch dep sync</code> command for syncing dependencies from a lockfile</li> <li>Add pluggable dependency locker interface with built-in UV and pip implementations</li> <li>Add <code>--cover-xml</code> and <code>--cover-xml-output</code> flags to the <code>hatch test</code> command for generating XML coverage reports</li> <li>Add linehaul telemetry data to User-Agent header for PyPI download statistics</li> <li>Auto-create environment when locking if it doesn't exist</li> </ul> <p><em><strong>Fixed:</strong></em></p> <ul> <li>Fix help output formatting for the <code>run</code> command</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pypa/hatch/commit/37b00c3d2221438fa79084b92e81ee1819d6c630"><code>37b00c3</code></a> release Hatchling v1.30.1 (<a href="https://redirect.github.com/pypa/hatch/issues/2298">#2298</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/0446d99ef6461644624e8bdc461fd3c0a684a13c"><code>0446d99</code></a> Update history for new patch release of hatchling after fixing default metada...</li> <li><a href="https://github.com/pypa/hatch/commit/4f5cdf094ec515488777705fc01e484ddd4f3e5f"><code>4f5cdf0</code></a> Make 2.4 metadata default until other tools support it. (<a href="https://redirect.github.com/pypa/hatch/issues/2296">#2296</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/0497be09d555c300851d55344104e9aea2f9f200"><code>0497be0</code></a> Fix draft release uploads. (<a href="https://redirect.github.com/pypa/hatch/issues/2293">#2293</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/3aae0faf98a5e90c146d5af21738e049ecac471e"><code>3aae0fa</code></a> Fix hatchling to use Metadata 2.4 (<a href="https://redirect.github.com/pypa/hatch/issues/2291">#2291</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/5ee41893d556aaa862d32621e37bb179646c60e8"><code>5ee4189</code></a> release Hatch v1.17.0 (<a href="https://redirect.github.com/pypa/hatch/issues/2290">#2290</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/6109ee756a79d1341798a47517d778d149807b15"><code>6109ee7</code></a> release Hatchling v1.30.0 (<a href="https://redirect.github.com/pypa/hatch/issues/2289">#2289</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/246e22bb1681b74ff493ec60aa8849d95ce048fe"><code>246e22b</code></a> Block duplicate files in wheel archives (closes <a href="https://redirect.github.com/pypa/hatch/issues/2066">#2066</a>) (<a href="https://redirect.github.com/pypa/hatch/issues/2269">#2269</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/d2afcb6003321c9dca1628b2840ec4acb1e1a9ef"><code>d2afcb6</code></a> Update docs as pre-release for 1.17.0 (<a href="https://redirect.github.com/pypa/hatch/issues/2287">#2287</a>)</li> <li><a href="https://github.com/pypa/hatch/commit/818d2841958f0797f0e4ed014b9f0a8123d11b63"><code>818d284</code></a> Feat hatch check command with new sub command for types (<a href="https://redirect.github.com/pypa/hatch/issues/2278">#2278</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pypa/hatch/compare/hatch-v1.16.5...hatch-v1.17.0">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Kennedy <65985482+jkennedyvz@users.noreply.github.com> Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
637 lines
20 KiB
Python
637 lines
20 KiB
Python
import asyncio
|
|
import json
|
|
from typing import Annotated
|
|
|
|
from langchain_community.retrievers import WikipediaRetriever
|
|
from langchain_community.tools.tavily_search import TavilySearchResults
|
|
from langchain_community.vectorstores import SKLearnVectorStore
|
|
from langchain_core.documents import Document
|
|
from langchain_core.messages import (
|
|
AIMessage,
|
|
AnyMessage,
|
|
HumanMessage,
|
|
ToolMessage,
|
|
)
|
|
from langchain_core.output_parsers import StrOutputParser
|
|
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
from langchain_core.runnables import RunnableConfig, RunnableLambda
|
|
from langchain_core.runnables import chain as as_runnable
|
|
from langchain_core.tools import tool
|
|
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
|
from langgraph.graph import END, StateGraph
|
|
from pydantic import BaseModel, Field
|
|
from typing_extensions import TypedDict
|
|
|
|
fast_llm = ChatOpenAI(model="gpt-4o-mini")
|
|
# Uncomment for a Fireworks model
|
|
# fast_llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", max_tokens=32_000)
|
|
long_context_llm = ChatOpenAI(model="gpt-4o")
|
|
|
|
|
|
direct_gen_outline_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"You are a Wikipedia writer. Write an outline for a Wikipedia page about a user-provided topic. Be comprehensive and specific.",
|
|
),
|
|
("user", "{topic}"),
|
|
]
|
|
)
|
|
|
|
|
|
class Subsection(BaseModel):
|
|
subsection_title: str = Field(..., title="Title of the subsection")
|
|
description: str = Field(..., title="Content of the subsection")
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
return f"### {self.subsection_title}\n\n{self.description}".strip()
|
|
|
|
|
|
class Section(BaseModel):
|
|
section_title: str = Field(..., title="Title of the section")
|
|
description: str = Field(..., title="Content of the section")
|
|
subsections: list[Subsection] | None = Field(
|
|
default=None,
|
|
title="Titles and descriptions for each subsection of the Wikipedia page.",
|
|
)
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
subsections = "\n\n".join(
|
|
f"### {subsection.subsection_title}\n\n{subsection.description}"
|
|
for subsection in self.subsections or []
|
|
)
|
|
return f"## {self.section_title}\n\n{self.description}\n\n{subsections}".strip()
|
|
|
|
|
|
class Outline(BaseModel):
|
|
page_title: str = Field(..., title="Title of the Wikipedia page")
|
|
sections: list[Section] = Field(
|
|
default_factory=list,
|
|
title="Titles and descriptions for each section of the Wikipedia page.",
|
|
)
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
sections = "\n\n".join(section.as_str for section in self.sections)
|
|
return f"# {self.page_title}\n\n{sections}".strip()
|
|
|
|
|
|
generate_outline_direct = direct_gen_outline_prompt | fast_llm.with_structured_output(
|
|
Outline
|
|
)
|
|
|
|
gen_related_topics_prompt = ChatPromptTemplate.from_template(
|
|
"""I'm writing a Wikipedia page for a topic mentioned below. Please identify and recommend some Wikipedia pages on closely related subjects. I'm looking for examples that provide insights into interesting aspects commonly associated with this topic, or examples that help me understand the typical content and structure included in Wikipedia pages for similar topics.
|
|
|
|
Please list the as many subjects and urls as you can.
|
|
|
|
Topic of interest: {topic}
|
|
"""
|
|
)
|
|
|
|
|
|
class RelatedSubjects(BaseModel):
|
|
topics: list[str] = Field(
|
|
description="Comprehensive list of related subjects as background research.",
|
|
)
|
|
|
|
|
|
expand_chain = gen_related_topics_prompt | fast_llm.with_structured_output(
|
|
RelatedSubjects
|
|
)
|
|
|
|
|
|
class Editor(BaseModel):
|
|
affiliation: str = Field(
|
|
description="Primary affiliation of the editor.",
|
|
)
|
|
name: str = Field(
|
|
description="Name of the editor.",
|
|
)
|
|
role: str = Field(
|
|
description="Role of the editor in the context of the topic.",
|
|
)
|
|
description: str = Field(
|
|
description="Description of the editor's focus, concerns, and motives.",
|
|
)
|
|
|
|
@property
|
|
def persona(self) -> str:
|
|
return f"Name: {self.name}\nRole: {self.role}\nAffiliation: {self.affiliation}\nDescription: {self.description}\n"
|
|
|
|
|
|
class Perspectives(BaseModel):
|
|
editors: list[Editor] = Field(
|
|
description="Comprehensive list of editors with their roles and affiliations.",
|
|
# Add a pydantic validation/restriction to be at most M editors
|
|
)
|
|
|
|
|
|
gen_perspectives_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"""You need to select a diverse (and distinct) group of Wikipedia editors who will work together to create a comprehensive article on the topic. Each of them represents a different perspective, role, or affiliation related to this topic.\
|
|
You can use other Wikipedia pages of related topics for inspiration. For each editor, add a description of what they will focus on.
|
|
|
|
Wiki page outlines of related topics for inspiration:
|
|
{examples}""",
|
|
),
|
|
("user", "Topic of interest: {topic}"),
|
|
]
|
|
)
|
|
|
|
gen_perspectives_chain = gen_perspectives_prompt | ChatOpenAI(
|
|
model="gpt-4o-mini"
|
|
).with_structured_output(Perspectives)
|
|
|
|
|
|
wikipedia_retriever = WikipediaRetriever(load_all_available_meta=True, top_k_results=1)
|
|
|
|
|
|
def format_doc(doc, max_length=1000):
|
|
related = "- ".join(doc.metadata["categories"])
|
|
return f"### {doc.metadata['title']}\n\nSummary: {doc.page_content}\n\nRelated\n{related}"[
|
|
:max_length
|
|
]
|
|
|
|
|
|
def format_docs(docs):
|
|
return "\n\n".join(format_doc(doc) for doc in docs)
|
|
|
|
|
|
@as_runnable
|
|
async def survey_subjects(topic: str):
|
|
related_subjects = await expand_chain.ainvoke({"topic": topic})
|
|
retrieved_docs = await wikipedia_retriever.abatch(
|
|
related_subjects.topics, return_exceptions=True
|
|
)
|
|
all_docs = []
|
|
for docs in retrieved_docs:
|
|
if isinstance(docs, BaseException):
|
|
continue
|
|
all_docs.extend(docs)
|
|
formatted = format_docs(all_docs)
|
|
return await gen_perspectives_chain.ainvoke({"examples": formatted, "topic": topic})
|
|
|
|
|
|
def add_messages(left, right):
|
|
if not isinstance(left, list):
|
|
left = [left]
|
|
if not isinstance(right, list):
|
|
right = [right]
|
|
return left + right
|
|
|
|
|
|
def update_references(references, new_references):
|
|
if not references:
|
|
references = {}
|
|
references.update(new_references)
|
|
return references
|
|
|
|
|
|
def update_editor(editor, new_editor):
|
|
# Can only set at the outset
|
|
if not editor:
|
|
return new_editor
|
|
return editor
|
|
|
|
|
|
class InterviewState(TypedDict):
|
|
messages: Annotated[list[AnyMessage], add_messages]
|
|
references: Annotated[dict | None, update_references]
|
|
editor: Annotated[Editor | None, update_editor]
|
|
|
|
|
|
gen_qn_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"""You are an experienced Wikipedia writer and want to edit a specific page. \
|
|
Besides your identity as a Wikipedia writer, you have a specific focus when researching the topic. \
|
|
Now, you are chatting with an expert to get information. Ask good questions to get more useful information.
|
|
|
|
When you have no more questions to ask, say "Thank you so much for your help!" to end the conversation.\
|
|
Please only ask one question at a time and don't ask what you have asked before.\
|
|
Your questions should be related to the topic you want to write.
|
|
Be comprehensive and curious, gaining as much unique insight from the expert as possible.\
|
|
|
|
Stay true to your specific perspective:
|
|
|
|
{persona}""",
|
|
),
|
|
MessagesPlaceholder(variable_name="messages", optional=True),
|
|
]
|
|
)
|
|
|
|
|
|
def tag_with_name(ai_message: AIMessage, name: str):
|
|
ai_message.name = name.replace(" ", "_").replace(".", "_")
|
|
return ai_message
|
|
|
|
|
|
def swap_roles(state: InterviewState, name: str):
|
|
converted = []
|
|
for message in state["messages"]:
|
|
if isinstance(message, AIMessage) and message.name != name:
|
|
message = HumanMessage(**message.model_dump(exclude={"type"}))
|
|
converted.append(message)
|
|
return {"messages": converted}
|
|
|
|
|
|
@as_runnable
|
|
async def generate_question(state: InterviewState):
|
|
editor = state["editor"]
|
|
gn_chain = (
|
|
RunnableLambda(swap_roles).bind(name=editor.name)
|
|
| gen_qn_prompt.partial(persona=editor.persona)
|
|
| fast_llm
|
|
| RunnableLambda(tag_with_name).bind(name=editor.name)
|
|
)
|
|
result = await gn_chain.ainvoke(state)
|
|
return {"messages": [result]}
|
|
|
|
|
|
class Queries(BaseModel):
|
|
queries: list[str] = Field(
|
|
description="Comprehensive list of search engine queries to answer the user's questions.",
|
|
)
|
|
|
|
|
|
gen_queries_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"You are a helpful research assistant. Query the search engine to answer the user's questions.",
|
|
),
|
|
MessagesPlaceholder(variable_name="messages", optional=True),
|
|
]
|
|
)
|
|
gen_queries_chain = gen_queries_prompt | ChatOpenAI(
|
|
model="gpt-4o-mini"
|
|
).with_structured_output(Queries, include_raw=True)
|
|
|
|
|
|
class AnswerWithCitations(BaseModel):
|
|
answer: str = Field(
|
|
description="Comprehensive answer to the user's question with citations.",
|
|
)
|
|
cited_urls: list[str] = Field(
|
|
description="List of urls cited in the answer.",
|
|
)
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
return f"{self.answer}\n\nCitations:\n\n" + "\n".join(
|
|
f"[{i + 1}]: {url}" for i, url in enumerate(self.cited_urls)
|
|
)
|
|
|
|
|
|
gen_answer_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"""You are an expert who can use information effectively. You are chatting with a Wikipedia writer who wants\
|
|
to write a Wikipedia page on the topic you know. You have gathered the related information and will now use the information to form a response.
|
|
|
|
Make your response as informative as possible and make sure every sentence is supported by the gathered information.
|
|
Each response must be backed up by a citation from a reliable source, formatted as a footnote, reproducing the URLS after your response.""",
|
|
),
|
|
MessagesPlaceholder(variable_name="messages", optional=True),
|
|
]
|
|
)
|
|
|
|
gen_answer_chain = gen_answer_prompt | fast_llm.with_structured_output(
|
|
AnswerWithCitations, include_raw=True
|
|
).with_config(run_name="GenerateAnswer")
|
|
|
|
|
|
# Tavily is typically a better search engine, but your free queries are limited
|
|
tavily_search = TavilySearchResults(max_results=4)
|
|
|
|
|
|
@tool
|
|
async def search_engine(query: str):
|
|
"""Search engine to the internet."""
|
|
results = tavily_search.invoke(query)
|
|
return [{"content": r["content"], "url": r["url"]} for r in results]
|
|
|
|
|
|
async def gen_answer(
|
|
state: InterviewState,
|
|
config: RunnableConfig | None = None,
|
|
name: str = "Subject_Matter_Expert",
|
|
max_str_len: int = 15000,
|
|
):
|
|
swapped_state = swap_roles(state, name) # Convert all other AI messages
|
|
queries = await gen_queries_chain.ainvoke(swapped_state)
|
|
query_results = await search_engine.abatch(
|
|
queries["parsed"].queries, config, return_exceptions=True
|
|
)
|
|
successful_results = [
|
|
res for res in query_results if not isinstance(res, Exception)
|
|
]
|
|
all_query_results = {
|
|
res["url"]: res["content"] for results in successful_results for res in results
|
|
}
|
|
# We could be more precise about handling max token length if we wanted to here
|
|
dumped = json.dumps(all_query_results)[:max_str_len]
|
|
ai_message: AIMessage = queries["raw"]
|
|
tool_call = queries["raw"].tool_calls[0]
|
|
tool_id = tool_call["id"]
|
|
tool_message = ToolMessage(tool_call_id=tool_id, content=dumped)
|
|
swapped_state["messages"].extend([ai_message, tool_message])
|
|
# Only update the shared state with the final answer to avoid
|
|
# polluting the dialogue history with intermediate messages
|
|
generated = await gen_answer_chain.ainvoke(swapped_state)
|
|
cited_urls = set(generated["parsed"].cited_urls)
|
|
# Save the retrieved information to a the shared state for future reference
|
|
cited_references = {k: v for k, v in all_query_results.items() if k in cited_urls}
|
|
formatted_message = AIMessage(name=name, content=generated["parsed"].as_str)
|
|
return {"messages": [formatted_message], "references": cited_references}
|
|
|
|
|
|
max_num_turns = 5
|
|
|
|
|
|
def route_messages(state: InterviewState, name: str = "Subject_Matter_Expert"):
|
|
messages = state["messages"]
|
|
num_responses = len(
|
|
[m for m in messages if isinstance(m, AIMessage) and m.name == name]
|
|
)
|
|
if num_responses >= max_num_turns:
|
|
return END
|
|
last_question = messages[-2]
|
|
if last_question.content.endswith("Thank you so much for your help!"):
|
|
return END
|
|
return "ask_question"
|
|
|
|
|
|
builder = StateGraph(InterviewState)
|
|
|
|
builder.add_node("ask_question", generate_question)
|
|
builder.add_node("answer_question", gen_answer)
|
|
builder.add_conditional_edges("answer_question", route_messages)
|
|
builder.add_edge("ask_question", "answer_question")
|
|
|
|
builder.set_entry_point("ask_question")
|
|
interview_graph = builder.compile().with_config(run_name="Conduct Interviews")
|
|
|
|
refine_outline_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"""You are a Wikipedia writer. You have gathered information from experts and search engines. Now, you are refining the outline of the Wikipedia page. \
|
|
You need to make sure that the outline is comprehensive and specific. \
|
|
Topic you are writing about: {topic}
|
|
|
|
Old outline:
|
|
|
|
{old_outline}""",
|
|
),
|
|
(
|
|
"user",
|
|
"Refine the outline based on your conversations with subject-matter experts:\n\nConversations:\n\n{conversations}\n\nWrite the refined Wikipedia outline:",
|
|
),
|
|
]
|
|
)
|
|
|
|
# Using turbo preview since the context can get quite long
|
|
refine_outline_chain = refine_outline_prompt | long_context_llm.with_structured_output(
|
|
Outline
|
|
)
|
|
|
|
|
|
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
|
|
# reference_docs = [
|
|
# Document(page_content=v, metadata={"source": k})
|
|
# for k, v in final_state["references"].items()
|
|
# ]
|
|
# # This really doesn't need to be a vectorstore for this size of data.
|
|
# # It could just be a numpy matrix. Or you could store documents
|
|
# # across requests if you want.
|
|
# vectorstore = SKLearnVectorStore.from_documents(
|
|
# reference_docs,
|
|
# embedding=embeddings,
|
|
# )
|
|
# retriever = vectorstore.as_retriever(k=10)
|
|
|
|
vectorstore = SKLearnVectorStore(embedding=embeddings)
|
|
retriever = vectorstore.as_retriever(k=10)
|
|
|
|
|
|
class SubSection(BaseModel):
|
|
subsection_title: str = Field(..., title="Title of the subsection")
|
|
content: str = Field(
|
|
...,
|
|
title="Full content of the subsection. Include [#] citations to the cited sources where relevant.",
|
|
)
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
return f"### {self.subsection_title}\n\n{self.content}".strip()
|
|
|
|
|
|
class WikiSection(BaseModel):
|
|
section_title: str = Field(..., title="Title of the section")
|
|
content: str = Field(..., title="Full content of the section")
|
|
subsections: list[Subsection] | None = Field(
|
|
default=None,
|
|
title="Titles and descriptions for each subsection of the Wikipedia page.",
|
|
)
|
|
citations: list[str] = Field(default_factory=list)
|
|
|
|
@property
|
|
def as_str(self) -> str:
|
|
subsections = "\n\n".join(
|
|
subsection.as_str for subsection in self.subsections or []
|
|
)
|
|
citations = "\n".join([f" [{i}] {cit}" for i, cit in enumerate(self.citations)])
|
|
return (
|
|
f"## {self.section_title}\n\n{self.content}\n\n{subsections}".strip()
|
|
+ f"\n\n{citations}".strip()
|
|
)
|
|
|
|
|
|
section_writer_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"You are an expert Wikipedia writer. Complete your assigned WikiSection from the following outline:\n\n"
|
|
"{outline}\n\nCite your sources, using the following references:\n\n<Documents>\n{docs}\n<Documents>",
|
|
),
|
|
("user", "Write the full WikiSection for the {section} section."),
|
|
]
|
|
)
|
|
|
|
|
|
async def retrieve(inputs: dict):
|
|
docs = await retriever.ainvoke(inputs["topic"] + ": " + inputs["section"])
|
|
formatted = "\n".join(
|
|
[
|
|
f'<Document href="{doc.metadata["source"]}"/>\n{doc.page_content}\n</Document>'
|
|
for doc in docs
|
|
]
|
|
)
|
|
return {"docs": formatted, **inputs}
|
|
|
|
|
|
section_writer = (
|
|
retrieve
|
|
| section_writer_prompt
|
|
| long_context_llm.with_structured_output(WikiSection)
|
|
)
|
|
|
|
|
|
writer_prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
(
|
|
"system",
|
|
"You are an expert Wikipedia author. Write the complete wiki article on {topic} using the following section drafts:\n\n"
|
|
"{draft}\n\nStrictly follow Wikipedia format guidelines.",
|
|
),
|
|
(
|
|
"user",
|
|
'Write the complete Wiki article using markdown format. Organize citations using footnotes like "[1]",'
|
|
" avoiding duplicates in the footer. Include URLs in the footer.",
|
|
),
|
|
]
|
|
)
|
|
|
|
writer = writer_prompt | long_context_llm | StrOutputParser()
|
|
|
|
|
|
class ResearchState(TypedDict):
|
|
topic: str
|
|
outline: Outline
|
|
editors: list[Editor]
|
|
interview_results: list[InterviewState]
|
|
# The final sections output
|
|
sections: list[WikiSection]
|
|
article: str
|
|
|
|
|
|
async def initialize_research(state: ResearchState):
|
|
topic = state["topic"]
|
|
coros = (
|
|
generate_outline_direct.ainvoke({"topic": topic}),
|
|
survey_subjects.ainvoke(topic),
|
|
)
|
|
results = await asyncio.gather(*coros)
|
|
return {
|
|
**state,
|
|
"outline": results[0],
|
|
"editors": results[1].editors,
|
|
}
|
|
|
|
|
|
async def conduct_interviews(state: ResearchState):
|
|
topic = state["topic"]
|
|
initial_states = [
|
|
{
|
|
"editor": editor,
|
|
"messages": [
|
|
AIMessage(
|
|
content=f"So you said you were writing an article on {topic}?",
|
|
name="Subject_Matter_Expert",
|
|
)
|
|
],
|
|
}
|
|
for editor in state["editors"]
|
|
]
|
|
# We call in to the sub-graph here to parallelize the interviews
|
|
interview_results = await interview_graph.abatch(initial_states)
|
|
|
|
return {
|
|
**state,
|
|
"interview_results": interview_results,
|
|
}
|
|
|
|
|
|
def format_conversation(interview_state):
|
|
messages = interview_state["messages"]
|
|
convo = "\n".join(f"{m.name}: {m.content}" for m in messages)
|
|
return f"Conversation with {interview_state['editor'].name}\n\n" + convo
|
|
|
|
|
|
async def refine_outline(state: ResearchState):
|
|
convos = "\n\n".join(
|
|
[
|
|
format_conversation(interview_state)
|
|
for interview_state in state["interview_results"]
|
|
]
|
|
)
|
|
|
|
updated_outline = await refine_outline_chain.ainvoke(
|
|
{
|
|
"topic": state["topic"],
|
|
"old_outline": state["outline"].as_str,
|
|
"conversations": convos,
|
|
}
|
|
)
|
|
return {**state, "outline": updated_outline}
|
|
|
|
|
|
async def index_references(state: ResearchState):
|
|
all_docs = []
|
|
for interview_state in state["interview_results"]:
|
|
reference_docs = [
|
|
Document(page_content=v, metadata={"source": k})
|
|
for k, v in interview_state["references"].items()
|
|
]
|
|
all_docs.extend(reference_docs)
|
|
await vectorstore.aadd_documents(all_docs)
|
|
return state
|
|
|
|
|
|
async def write_sections(state: ResearchState):
|
|
outline = state["outline"]
|
|
sections = await section_writer.abatch(
|
|
[
|
|
{
|
|
"outline": outline.as_str,
|
|
"section": section.section_title,
|
|
"topic": state["topic"],
|
|
}
|
|
for section in outline.sections
|
|
]
|
|
)
|
|
return {
|
|
**state,
|
|
"sections": sections,
|
|
}
|
|
|
|
|
|
async def write_article(state: ResearchState):
|
|
topic = state["topic"]
|
|
sections = state["sections"]
|
|
draft = "\n\n".join([section.as_str for section in sections])
|
|
article = await writer.ainvoke({"topic": topic, "draft": draft})
|
|
return {
|
|
**state,
|
|
"article": article,
|
|
}
|
|
|
|
|
|
builder_of_storm = StateGraph(ResearchState)
|
|
|
|
nodes = [
|
|
("init_research", initialize_research),
|
|
("conduct_interviews", conduct_interviews),
|
|
("refine_outline", refine_outline),
|
|
("index_references", index_references),
|
|
("write_sections", write_sections),
|
|
("write_article", write_article),
|
|
]
|
|
for i in range(len(nodes)):
|
|
name, node = nodes[i]
|
|
builder_of_storm.add_node(name, node)
|
|
if i > 0:
|
|
builder_of_storm.add_edge(nodes[i - 1][0], name)
|
|
|
|
builder_of_storm.set_entry_point(nodes[0][0])
|
|
builder_of_storm.set_finish_point(nodes[-1][0])
|
|
graph = builder_of_storm.compile()
|