Skip to content

Commit

Permalink
Merge branch 'main' into brace/interrupt-schema
Browse files Browse the repository at this point in the history
  • Loading branch information
bracesproul authored Jan 13, 2025
2 parents cfb121e + c86155d commit 5aefa5d
Show file tree
Hide file tree
Showing 49 changed files with 2,920 additions and 236 deletions.
24 changes: 23 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,31 @@ jobs:
- name: Build
run: yarn build

test-js:
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
- "libs/sdk-js"
defaults:
run:
working-directory: ${{ matrix.working-directory }}
steps:
- uses: actions/checkout@v3
- name: Setup Node.js (LTS)
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "yarn"
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
- name: Install dependencies
run: yarn install
- name: Run tests
run: yarn test

ci_success:
name: "CI Success"
needs: [lint, lint-js, test, test-langgraph, test-scheduler-kafka, integration-test]
needs: [lint, lint-js, test, test-langgraph, test-scheduler-kafka, integration-test, test-js]
if: |
always()
runs-on: ubuntu-latest
Expand Down
93 changes: 93 additions & 0 deletions docs/_scripts/_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import functools

from urllib3 import __version__ as urllib3version # type: ignore[import-untyped]
from urllib3 import connection # type: ignore[import-untyped]


def _ensure_str(s, encoding="utf-8", errors="strict") -> str:
if isinstance(s, str):
return s

if isinstance(s, bytes):
return s.decode(encoding, errors)
return str(s)


# Copied from https://github.com/urllib3/urllib3/blob/1c994dfc8c5d5ecaee8ed3eb585d4785f5febf6e/src/urllib3/connection.py#L231
def request(self, method, url, body=None, headers=None):
"""Make the request.
This function is based on the urllib3 request method, with modifications
to handle potential issues when using vcrpy in concurrent workloads.
Args:
self: The HTTPConnection instance.
method (str): The HTTP method (e.g., 'GET', 'POST').
url (str): The URL for the request.
body (Optional[Any]): The body of the request.
headers (Optional[dict]): Headers to send with the request.
Returns:
The result of calling the parent request method.
"""
# Update the inner socket's timeout value to send the request.
# This only triggers if the connection is re-used.
if getattr(self, "sock", None) is not None:
self.sock.settimeout(self.timeout)

if headers is None:
headers = {}
else:
# Avoid modifying the headers passed into .request()
headers = headers.copy()
if "user-agent" not in (_ensure_str(k.lower()) for k in headers):
headers["User-Agent"] = connection._get_default_user_agent()
# The above is all the same ^^^
# The following is different:
return self._parent_request(method, url, body=body, headers=headers)


_PATCHED = False


def patch_urllib3():
"""Patch the request method of urllib3 to avoid type errors when using vcrpy.
In concurrent workloads (such as the tracing background queue), the
connection pool can get in a state where an HTTPConnection is created
before vcrpy patches the HTTPConnection class. In urllib3 >= 2.0 this isn't
a problem since they use the proper super().request(...) syntax, but in older
versions, super(HTTPConnection, self).request is used, resulting in a TypeError
since self is no longer a subclass of "HTTPConnection" (which at this point
is vcr.stubs.VCRConnection).
This method patches the class to fix the super() syntax to avoid mixed inheritance.
In the case of the LangSmith tracing logic, it doesn't really matter since we always
exclude cache checks for calls to LangSmith.
The patch is only applied for urllib3 versions older than 2.0.
"""
global _PATCHED
if _PATCHED:
return
from packaging import version

if version.parse(urllib3version) >= version.parse("2.0"):
_PATCHED = True
return

# Lookup the parent class and its request method
parent_class = connection.HTTPConnection.__bases__[0]
parent_request = parent_class.request

def new_request(self, *args, **kwargs):
"""Handle parent request.
This method binds the parent's request method to self and then
calls our modified request function.
"""
self._parent_request = functools.partial(parent_request, self)
return request(self, *args, **kwargs)

connection.HTTPConnection.request = new_request
_PATCHED = True
17 changes: 16 additions & 1 deletion docs/_scripts/prepare_notebooks_for_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
"docs/docs/tutorials/lats/lats.ipynb", # issues only when running with VCR
"docs/docs/tutorials/rag/langgraph_crag.ipynb", # flakiness from tavily
"docs/docs/tutorials/rag/langgraph_adaptive_rag.ipynb", # Cannot create a consistent method resolution error from VCR
"docs/docs/how-tos/map-reduce.ipynb" # flakiness from structured output, only when running with VCR
"docs/docs/how-tos/map-reduce.ipynb", # flakiness from structured output, only when running with VCR
"docs/docs/tutorials/tot/tot.ipynb",
"docs/docs/how-tos/visualization.ipynb"
]


Expand Down Expand Up @@ -86,6 +88,7 @@ def add_vcr_to_notebook(
) -> nbformat.NotebookNode:
"""Inject `with vcr.cassette` into each code cell of the notebook."""

uses_langsmith = False
# Inject VCR context manager into each code cell
for idx, cell in enumerate(notebook.cells):
if cell.cell_type != "code":
Expand Down Expand Up @@ -120,6 +123,9 @@ def add_vcr_to_notebook(
f" {line}" for line in lines
)

if any("hub.pull" in line or "from langsmith import" in line for line in lines):
uses_langsmith = True

# Add import statement
vcr_import_lines = [
"import nest_asyncio",
Expand Down Expand Up @@ -152,6 +158,15 @@ def add_vcr_to_notebook(
"custom_vcr.register_serializer('advanced_compressed', AdvancedCompressedSerializer())",
"custom_vcr.serializer = 'advanced_compressed'",
]
if uses_langsmith:
vcr_import_lines.extend(
# patch urllib3 to handle vcr errors, see more here:
# https://github.com/langchain-ai/langsmith-sdk/blob/main/python/langsmith/_internal/_patch.py
"import sys",
f"sys.path.insert(0, '{os.path.join(DOCS_PATH, '_scripts')}')",
"import _patch as patch_urllib3",
"patch_urllib3.patch_urllib3()",
)
import_cell = nbformat.v4.new_code_cell(source="\n".join(vcr_import_lines))
import_cell.pop("id", None)
notebook.cells.insert(0, import_cell)
Expand Down
2 changes: 1 addition & 1 deletion docs/cassettes/pass-config-to-tools_14.msgpack.zlib
Original file line number Diff line number Diff line change
@@ -1 +1 @@
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
Loading

0 comments on commit 5aefa5d

Please sign in to comment.