mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-18 05:35:43 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d5455227b | ||
|
|
1b28530d52 | ||
|
|
416da06d6b | ||
|
|
027bb0a1b8 | ||
|
|
cd30b9cfea | ||
|
|
5eb9826c46 |
@@ -0,0 +1,156 @@
|
||||
"""Logic to identify and transform cross-reference links in markdown files.
|
||||
|
||||
This module allows supporting custom markdown syntax for "autolinks". These are links
|
||||
that will be transformed based on the current scope context, such as "global", "python",
|
||||
or "js" into an appropriate markdown link format.
|
||||
|
||||
For example,
|
||||
|
||||
```markdown
|
||||
@[StateGraph]
|
||||
```
|
||||
|
||||
May be transformed into:
|
||||
|
||||
```markdown
|
||||
[StateGraph](some_path/api-reference/state-graph.md)
|
||||
```
|
||||
|
||||
The transformation value depends on the scope in which the link is used.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from _scripts.link_map import SCOPE_LINK_MAPS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _transform_link(
|
||||
link_name: str, scope: str, file_path: str, line_number: int
|
||||
) -> str | None:
|
||||
"""Transform a cross-reference link based on the current scope.
|
||||
|
||||
Args:
|
||||
link_name: The name of the link to transform (e.g., "StateGraph").
|
||||
scope: The current scope context ("global", "python", "js", etc.).
|
||||
file_path: The file path for error reporting.
|
||||
line_number: The line number for error reporting.
|
||||
|
||||
Returns:
|
||||
A formatted markdown link if the link is found in the scope mapping,
|
||||
None otherwise.
|
||||
|
||||
Example:
|
||||
>>> _transform_link("StateGraph", "python", "file.md", 5)
|
||||
"[StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph)"
|
||||
|
||||
>>> _transform_link("unknown-link", "python", "file.md", 5)
|
||||
None
|
||||
"""
|
||||
if scope == "global":
|
||||
# Special scope that is composed of both Python and JS links
|
||||
# For now, we will substitute in the python scope!
|
||||
# But we need to add support for handling both scopes.
|
||||
scope = "python"
|
||||
logger.error(
|
||||
"Encountered unhandled 'global' scope. Defaulting to 'python'."
|
||||
"In file: %s, line %d, link_name: %s",
|
||||
file_path,
|
||||
line_number,
|
||||
link_name,
|
||||
)
|
||||
link_map = SCOPE_LINK_MAPS.get(scope, {})
|
||||
url = link_map.get(link_name)
|
||||
|
||||
if url:
|
||||
return f"[{link_name}]({url})"
|
||||
else:
|
||||
# Log error with file location information
|
||||
logger.info(
|
||||
# Using %s
|
||||
"Link '%s' not found in scope '%s'. "
|
||||
"In file: %s, line %d. Available links in scope: %s",
|
||||
link_name,
|
||||
scope,
|
||||
file_path,
|
||||
line_number,
|
||||
list(link_map.keys() if link_map else []),
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
CONDITIONAL_FENCE_PATTERN = re.compile(
|
||||
r"""
|
||||
^ # Start of line
|
||||
(?P<indent>[ \t]*) # Optional indentation (spaces or tabs)
|
||||
::: # Literal fence marker
|
||||
(?P<language>\w+)? # Optional language identifier (named group: language)
|
||||
\s* # Optional trailing whitespace
|
||||
$ # End of line
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
CROSS_REFERENCE_PATTERN = re.compile(
|
||||
r"""
|
||||
@ # Literal @ symbol
|
||||
\[ # Opening bracket
|
||||
(?P<link_name>[^\]]+) # Link name - one or more non-bracket characters
|
||||
\] # Closing bracket
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
def _replace_autolinks(markdown: str, file_path: str) -> str:
|
||||
"""Preprocess markdown lines to handle @[links] with conditional fence scopes.
|
||||
|
||||
This function processes markdown content to transform @[link_name] references
|
||||
based on the current conditional fence scope. Conditional fences use the
|
||||
syntax :::language to define scope boundaries.
|
||||
|
||||
Args:
|
||||
markdown: The markdown content to process.
|
||||
file_path: The file path for error reporting.
|
||||
|
||||
Returns:
|
||||
Processed markdown content with @[references] transformed to proper
|
||||
markdown links or left unchanged if not found.
|
||||
|
||||
Example:
|
||||
Input:
|
||||
"@[StateGraph]\\n:::python\\n@[Command]\\n:::\\n"
|
||||
Output:
|
||||
"[StateGraph](url)\\n:::python\\n[Command](url)\\n:::\\n"
|
||||
"""
|
||||
# Track the current scope context
|
||||
current_scope = "global"
|
||||
lines = markdown.splitlines(keepends=True)
|
||||
processed_lines = []
|
||||
|
||||
for line_number, line in enumerate(lines, 1):
|
||||
line_stripped = line.strip()
|
||||
|
||||
# Check if this line defines a new conditional fence scope
|
||||
fence_match = CONDITIONAL_FENCE_PATTERN.match(line_stripped)
|
||||
if fence_match:
|
||||
language = fence_match.group("language")
|
||||
# Set scope to the specified language, or reset to global if no language
|
||||
current_scope = language.lower() if language else "global"
|
||||
processed_lines.append(line)
|
||||
continue
|
||||
|
||||
# Transform all @[link_name] references in this line based on current scope
|
||||
def replace_cross_reference(match: re.Match[str]) -> str:
|
||||
"""Replace a single @[link_name] with the scoped equivalent."""
|
||||
link_name = match.group("link_name")
|
||||
transformed = _transform_link(
|
||||
link_name, current_scope, file_path, line_number
|
||||
)
|
||||
return transformed if transformed is not None else match.group(0)
|
||||
|
||||
transformed_line = CROSS_REFERENCE_PATTERN.sub(replace_cross_reference, line)
|
||||
processed_lines.append(transformed_line)
|
||||
|
||||
return "".join(processed_lines)
|
||||
+141
-4
@@ -1,5 +1,142 @@
|
||||
JS_LINK_MAP = {
|
||||
"langgraph.types.interrupt": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph.interrupt-2.html",
|
||||
"create_react_agent": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"langgraph.types.Command": "https://langchain-ai.github.io/langgraphjs/reference/classes/langgraph.Command.html",
|
||||
"""Link mapping for cross-reference resolution across different scopes.
|
||||
|
||||
This module provides link mappings for different language/framework scopes
|
||||
to resolve @[link_name] references to actual URLs.
|
||||
"""
|
||||
|
||||
# Python-specific link mappings
|
||||
# Python-specific link mappings
|
||||
PYTHON_LINK_MAP = {
|
||||
"StateGraph": "reference/graphs/#langgraph.graph.StateGraph",
|
||||
"add_conditional_edges": "reference/graphs/#langgraph.graph.StateGraph.add_conditional_edges",
|
||||
"add_edge": "reference/graphs/#langgraph.graph.StateGraph.add_edge",
|
||||
"add_node": "reference/graphs/#langgraph.graph.StateGraph.add_node",
|
||||
"add_messages": "reference/messages/#langgraph.graph.message.add_messages",
|
||||
"ToolNode": "reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode",
|
||||
"CompiledStateGraph.astream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.astream",
|
||||
"Pregel.astream": "reference/graphs/#langgraph.pregel.Pregel.astream",
|
||||
"AsyncPostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.aio.AsyncPostgresSaver",
|
||||
"AsyncSqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver",
|
||||
"BaseCheckpointSaver": "reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver",
|
||||
"BaseStore": "reference/stores/#langgraph.store.base.BaseStore",
|
||||
"BaseStore.put": "reference/stores/#langgraph.store.base.BaseStore.put",
|
||||
"BinaryOperatorAggregate": "reference/channels/#langgraph.channels.BinaryOperatorAggregate",
|
||||
"CipherProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.CipherProtocol",
|
||||
"client.runs.stream": "reference/client/#langgraph_sdk.client.RunsClient.stream",
|
||||
"client.runs.wait": "reference/client/#langgraph_sdk.client.RunsClient.wait",
|
||||
"client.threads.get_history": "reference/client/#langgraph_sdk.client.ThreadsClient.get_history",
|
||||
"client.threads.update_state": "reference/client/#langgraph_sdk.client.ThreadsClient.update_state",
|
||||
"Command": "reference/types/#langgraph.types.Command",
|
||||
"CompiledStateGraph": "reference/graphs/#langgraph.graph.state.CompiledStateGraph",
|
||||
"create_react_agent": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
|
||||
"create_supervisor": "reference/supervisor/#langgraph_supervisor.supervisor.create_supervisor",
|
||||
"EncryptedSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer",
|
||||
"entrypoint.final": "reference/functions/#langgraph.func.entrypoint.final",
|
||||
"entrypoint": "reference/functions/#langgraph.func.entrypoint",
|
||||
"from_pycryptodome_aes": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes",
|
||||
# "getContextVariable": "<insert-ref>",
|
||||
"get_state_history": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.get_state_history",
|
||||
"get_stream_writer": "reference/config/#langgraph.config.get_stream_writer",
|
||||
"HumanInterrupt": "reference/prebuilt/#langgraph.prebuilt.interrupt.HumanInterrupt",
|
||||
"InjectedState": "reference/prebuilt/#langgraph.prebuilt.InjectedState",
|
||||
"InMemorySaver": "reference/checkpoints/#langgraph.checkpoint.memory.InMemorySaver",
|
||||
"interrupt": "reference/graphs/#langgraph.graph.interrupt",
|
||||
"CompiledStateGraph.invoke": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.invoke",
|
||||
"JsonPlusSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer",
|
||||
"langgraph.json": "reference/configuration/#configuration-file",
|
||||
"LastValue": "reference/channels/#langgraph.channels.LastValue",
|
||||
# "MemorySaver": "<insert-ref>",
|
||||
# "messagesStateReducer": "<insert-ref>",
|
||||
"PostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.PostgresSaver",
|
||||
"Pregel": "reference/graphs/#langgraph.pregel.Pregel",
|
||||
"Pregel.stream": "reference/graphs/#langgraph.pregel.Pregel.stream",
|
||||
"pre_model_hook": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
|
||||
"protocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
|
||||
"Send": "reference/types/#langgraph.types.Send",
|
||||
"SerializerProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
|
||||
"SqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.SqliteSaver",
|
||||
"START": "reference/constants/#langgraph.constants.START",
|
||||
"CompiledStateGraph.stream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.stream",
|
||||
"task": "reference/functions/#langgraph.func.task",
|
||||
"Topic": "reference/channels/#langgraph.channels.Topic",
|
||||
"update_state": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.update_state",
|
||||
}
|
||||
|
||||
|
||||
# JavaScript-specific link mappings
|
||||
JS_LINK_MAP = {
|
||||
"StateGraph": "reference/classes/langgraph.StateGraph.html",
|
||||
"add_conditional_edges": "reference/functions/langgraph_StateGraph.addConditionalEdges.html",
|
||||
"add_edge": "reference/functions/langgraph_StateGraph.addEdge.html",
|
||||
"add_node": "reference/functions/langgraph_StateGraph.addNode.html",
|
||||
"add_messages": "reference/functions/langgraph_message.addMessages.html",
|
||||
"ToolNode": "reference/classes/langgraph_prebuilt.ToolNode.html",
|
||||
"CompiledStateGraph.astream()": "reference/functions/langgraph_CompiledStateGraph.astream.html",
|
||||
"Pregel.astream": "reference/functions/langgraph_Pregel.astream.html",
|
||||
"AsyncPostgresSaver": "reference/classes/langgraph_checkpoint_postgres_aio.AsyncPostgresSaver.html",
|
||||
"AsyncSqliteSaver": "reference/classes/langgraph_checkpoint_sqlite_aio.AsyncSqliteSaver.html",
|
||||
"BaseCheckpointSaver": "reference/classes/langgraph_checkpoint_base.BaseCheckpointSaver.html",
|
||||
"BaseStore": "reference/classes/langgraph_store_base.BaseStore.html",
|
||||
"BaseStore.put": "reference/functions/langgraph_store_base.BaseStore.put.html",
|
||||
"BinaryOperatorAggregate": "reference/classes/langgraph_channels.BinaryOperatorAggregate.html",
|
||||
"CipherProtocol": "reference/classes/langgraph_checkpoint_serde_base.CipherProtocol.html",
|
||||
"client.runs.stream": "reference/functions/langgraph_sdk_client.RunsClient.stream.html",
|
||||
"client.runs.wait": "reference/functions/langgraph_sdk_client.RunsClient.wait.html",
|
||||
"client.threads.get_history": "reference/functions/langgraph_sdk_client.ThreadsClient.getHistory.html",
|
||||
"client.threads.update_state": "reference/functions/langgraph_sdk_client.ThreadsClient.updateState.html",
|
||||
"Command": "reference/classes/langgraph.Command.html",
|
||||
"CompiledStateGraph": "reference/classes/langgraph.CompiledStateGraph.html",
|
||||
"create_react_agent": "reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"create_supervisor": "reference/functions/langgraph_supervisor.createSupervisor.html",
|
||||
"EncryptedSerializer": "reference/classes/langgraph_checkpoint_serde_encrypted.EncryptedSerializer.html",
|
||||
"entrypoint.final": "reference/functions/langgraph_func.entrypoint.final.html",
|
||||
"entrypoint": "reference/functions/langgraph_func.entrypoint.html",
|
||||
"from_pycryptodome_aes": "reference/functions/langgraph_checkpoint_serde_encrypted.EncryptedSerializer.fromPycryptodomeAes.html",
|
||||
# "getContextVariable": "<insert-ref>",
|
||||
"get_state_history": "reference/functions/langgraph_CompiledStateGraph.getStateHistory.html",
|
||||
"get_stream_writer": "reference/functions/langgraph_config.getStreamWriter.html",
|
||||
"HumanInterrupt": "reference/classes/langgraph_prebuilt.HumanInterrupt.html",
|
||||
"InjectedState": "reference/classes/langgraph_prebuilt.InjectedState.html",
|
||||
"InMemorySaver": "reference/classes/langgraph_checkpoint_memory.InMemorySaver.html",
|
||||
"interrupt": "reference/functions/langgraph.interrupt-2.html",
|
||||
"CompiledStateGraph.invoke": "reference/functions/langgraph_CompiledStateGraph.invoke.html",
|
||||
"JsonPlusSerializer": "reference/classes/langgraph_checkpoint_serde_jsonplus.JsonPlusSerializer.html",
|
||||
"langgraph.json": "reference/configuration.html",
|
||||
"LastValue": "reference/classes/langgraph_channels.LastValue.html",
|
||||
# "MemorySaver": "<insert-ref>",
|
||||
# "messagesStateReducer": "<insert-ref>",
|
||||
"PostgresSaver": "reference/classes/langgraph_checkpoint_postgres.PostgresSaver.html",
|
||||
"Pregel": "reference/classes/langgraph.Pregel.html",
|
||||
"Pregel.stream": "reference/functions/langgraph_Pregel.stream.html",
|
||||
"pre_model_hook": "reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"protocol": "reference/classes/langgraph_checkpoint_serde_base.SerializerProtocol.html",
|
||||
"Send": "reference/classes/langgraph.Send.html",
|
||||
"SerializerProtocol": "reference/classes/langgraph_checkpoint_serde_base.SerializerProtocol.html",
|
||||
"SqliteSaver": "reference/classes/langgraph_checkpoint_sqlite.SqliteSaver.html",
|
||||
"START": "reference/constants.html#START",
|
||||
"CompiledStateGraph.stream": "reference/functions/langgraph_CompiledStateGraph.stream.html",
|
||||
"task": "reference/functions/langgraph_func.task.html",
|
||||
"Topic": "reference/classes/langgraph_channels.Topic.html",
|
||||
"update_state": "reference/functions/langgraph_CompiledStateGraph.updateState.html",
|
||||
}
|
||||
|
||||
# TODO: Allow updating these to localhost for local development
|
||||
PY_REFERENCE_HOST = "https://langchain-ai.github.io/langgraph/"
|
||||
JS_REFERENCE_HOST = "https://langchain-ai.github.io/langgraphjs/"
|
||||
|
||||
for key, value in PYTHON_LINK_MAP.items():
|
||||
# Ensure the link is absolute
|
||||
if not value.startswith("http"):
|
||||
PYTHON_LINK_MAP[key] = f"{PY_REFERENCE_HOST}{value}"
|
||||
|
||||
for key, value in JS_LINK_MAP.items():
|
||||
# Ensure the link is absolute
|
||||
if not value.startswith("http"):
|
||||
JS_LINK_MAP[key] = f"{JS_REFERENCE_HOST}{value}"
|
||||
|
||||
# Global scope is assembled from the Python and JS mappings
|
||||
# Combined mapping by scope
|
||||
SCOPE_LINK_MAPS = {
|
||||
"python": PYTHON_LINK_MAP,
|
||||
"js": JS_LINK_MAP,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ from mkdocs.structure.files import Files, File
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
from _scripts.generate_api_reference_links import update_markdown_with_imports
|
||||
from _scripts.link_map import JS_LINK_MAP
|
||||
from _scripts.handle_auto_links import _replace_autolinks
|
||||
from _scripts.notebook_convert import convert_notebook
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -176,31 +176,7 @@ def _add_path_to_code_blocks(markdown: str, page: Page) -> str:
|
||||
return code_block_pattern.sub(replace_code_block_header, markdown)
|
||||
|
||||
|
||||
def _resolve_cross_references(md_text: str, link_map: dict[str, str]) -> str:
|
||||
"""Replace [title][identifier] with [title](url) using language-specific link_map.
|
||||
|
||||
Args:
|
||||
md_text: The markdown text to process.
|
||||
link_map: mapping of identifier to URL.
|
||||
|
||||
Returns:
|
||||
The processed markdown text with cross-references resolved.
|
||||
"""
|
||||
# Pattern to match [title][identifier]
|
||||
pattern = re.compile(r"\[([^\]]+)\]\[([^\]]+)\]")
|
||||
|
||||
def replace_reference(match: re.Match) -> str:
|
||||
"""Replace the matched reference with the corresponding URL."""
|
||||
title, identifier = match.group(1), match.group(2)
|
||||
url = link_map.get(identifier)
|
||||
|
||||
if url:
|
||||
return f"[{title}]({url})"
|
||||
else:
|
||||
# Leave it unchanged if not found
|
||||
return match.group(0)
|
||||
|
||||
return pattern.sub(replace_reference, md_text)
|
||||
# Compiled regex patterns for better performance and readability
|
||||
|
||||
|
||||
def _apply_conditional_rendering(md_text: str, target_language: str) -> str:
|
||||
@@ -295,7 +271,7 @@ def _highlight_code_blocks(markdown: str) -> str:
|
||||
opening_fence += f" {attributes}"
|
||||
|
||||
if highlighted_lines:
|
||||
opening_fence += f" hl_lines=\"{' '.join(highlighted_lines)}\""
|
||||
opening_fence += f' hl_lines="{" ".join(highlighted_lines)}"'
|
||||
|
||||
return (
|
||||
# The indent and opening fence
|
||||
@@ -325,6 +301,9 @@ def _on_page_markdown_with_config(
|
||||
# logger.info("Processing Jupyter notebook: %s", page.file.src_path)
|
||||
markdown = convert_notebook(page.file.abs_src_path)
|
||||
|
||||
# Apply cross-reference preprocessing to all markdown content
|
||||
markdown = _replace_autolinks(markdown, page.file.src_path)
|
||||
|
||||
# Append API reference links to code blocks
|
||||
if add_api_references:
|
||||
markdown = update_markdown_with_imports(markdown, page.file.abs_src_path)
|
||||
@@ -334,16 +313,6 @@ def _on_page_markdown_with_config(
|
||||
# Apply conditional rendering for code blocks
|
||||
target_language = kwargs.get("target_language", "python")
|
||||
markdown = _apply_conditional_rendering(markdown, target_language)
|
||||
if target_language == "js":
|
||||
markdown = _resolve_cross_references(markdown, JS_LINK_MAP)
|
||||
elif target_language == "python":
|
||||
# Via a dedicated plugin
|
||||
pass
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported target language: {target_language}. "
|
||||
"Supported languages are 'python' and 'js'."
|
||||
)
|
||||
|
||||
# Add file path as an attribute to code blocks that are executable.
|
||||
# This file path is used to associate fixtures with the executable code
|
||||
@@ -358,13 +327,11 @@ def _on_page_markdown_with_config(
|
||||
|
||||
|
||||
def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]):
|
||||
finalized_markdown = (
|
||||
_on_page_markdown_with_config(
|
||||
markdown,
|
||||
page,
|
||||
add_api_references=True,
|
||||
**kwargs,
|
||||
)
|
||||
finalized_markdown = _on_page_markdown_with_config(
|
||||
markdown,
|
||||
page,
|
||||
add_api_references=True,
|
||||
**kwargs,
|
||||
)
|
||||
page.meta["original_markdown"] = finalized_markdown
|
||||
return finalized_markdown
|
||||
@@ -437,6 +404,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
else:
|
||||
return html # fallback if no <body> found
|
||||
|
||||
|
||||
def _inject_markdown_into_html(html: str, page: Page) -> str:
|
||||
"""Inject the original markdown content into the HTML page as JSON."""
|
||||
original_markdown = page.meta.get("original_markdown", "")
|
||||
@@ -469,6 +437,7 @@ def _inject_markdown_into_html(html: str, page: Page) -> str:
|
||||
)
|
||||
return html.replace("</head>", f"{script_content}</head>")
|
||||
|
||||
|
||||
def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
|
||||
"""Inject Google Tag Manager noscript tag immediately after <body>.
|
||||
|
||||
@@ -483,6 +452,7 @@ def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
|
||||
html = _inject_markdown_into_html(html, page)
|
||||
return _inject_gtm(html)
|
||||
|
||||
|
||||
# Create HTML files for redirects after site dir has been built
|
||||
def on_post_build(config):
|
||||
use_directory_urls = config.get("use_directory_urls")
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
[`add_conditional_edges`][langgraph.graph.StateGraph.add_conditional_edges]
|
||||
[add_conditional_edges][langgraph.graph.StateGraph.add_conditional_edges]
|
||||
[`add_edge`][langgraph.graph.StateGraph.add_edge]
|
||||
[add_edge][langgraph.graph.StateGraph.add_edge]
|
||||
[`add_messages`][langgraph.graph.message.add_messages]
|
||||
[add_node][langgraph.graph.StateGraph.add_node]
|
||||
[API reference][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[API reference][toolnode]
|
||||
[`astream()`][langgraph.graph.state.CompiledStateGraph.astream]
|
||||
[`.astream()`][langgraph.pregel.Pregel.astream]
|
||||
[AsyncPostgresSaver][langgraph.checkpoint.postgres.aio.AsyncPostgresSaver]
|
||||
[AsyncSqliteSaver][langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver]
|
||||
[BaseCheckpointSaver][<insert-ref>]
|
||||
[BaseCheckpointSaver][langgraph.checkpoint.base.BaseCheckpointSaver]
|
||||
[BaseStore][langgraph.store.base.BaseStore]
|
||||
[BaseStore.put][<insert-ref>]
|
||||
[BaseStore.put][langgraph.store.base.BaseStore.put]
|
||||
[BinaryOperatorAggregate][<insert-ref>]
|
||||
[BinaryOperatorAggregate][langgraph.channels.BinaryOperatorAggregate]
|
||||
[`CipherProtocol`][langgraph.checkpoint.serde.base.CipherProtocol]
|
||||
[`client.runs.stream`][langgraph_sdk.client.RunsClient.stream]
|
||||
[`client.runs.wait`][langgraph_sdk.client.RunsClient.wait]
|
||||
[`client.threads.get_history`][langgraph_sdk.client.ThreadsClient.get_history]
|
||||
[`client.threads.update_state`][langgraph_sdk.client.ThreadsClient.update_state]
|
||||
[`Command`][<insert-ref>]
|
||||
[`Command`][langgraph.types.Command]
|
||||
[Command][langgraph.types.Command]
|
||||
[CompiledStateGraph][langgraph.graph.state.CompiledStateGraph]
|
||||
[`createReactAgent`][<insert-ref>]
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[`create_supervisor`][langgraph_supervisor.supervisor.create_supervisor]
|
||||
[`EncryptedSerializer`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer]
|
||||
[`entrypoint.final`][langgraph.func.entrypoint.final]
|
||||
[`entrypoint`][<insert-ref>]
|
||||
[entrypoint][<insert-ref>]
|
||||
[`@entrypoint`][langgraph.func.entrypoint]
|
||||
[`entrypoint`][langgraph.func.entrypoint]
|
||||
[entrypoint()][langgraph.func.entrypoint]
|
||||
[entrypoint][langgraph.func.entrypoint]
|
||||
[finalResult['values']['messages']
|
||||
[`from_pycryptodome_aes`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes]
|
||||
[`getContextVariable`][<insert-ref>]
|
||||
[`getStateHistory()`][<insert-ref>]
|
||||
[`get_state_history()`][langgraph.graph.state.CompiledStateGraph.get_state_history]
|
||||
[get_stream_writer][langgraph.config.get_stream_writer]
|
||||
[`HumanInterrupt`][langgraph.prebuilt.interrupt.HumanInterrupt]
|
||||
[`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]
|
||||
[HumanMessage(content=state[\"messages\"][-2]
|
||||
[`InjectedState`][langgraph.prebuilt.InjectedState]
|
||||
[InjectedState][langgraph.prebuilt.InjectedState]
|
||||
[InMemorySaver][langgraph.checkpoint.memory.InMemorySaver]
|
||||
[`interrupt` function][<insert-ref>]
|
||||
[`interrupt` function][langgraph.types.interrupt]
|
||||
[`interrupt()`][langgraph.types.interrupt]
|
||||
[`interrupt`][langgraph.types.interrupt]
|
||||
[interrupt][langgraph.types.interrupt]
|
||||
[`invoke`][<insert-ref>]
|
||||
[`invoke`][langgraph.graph.state.CompiledStateGraph.invoke]
|
||||
[`JsonPlusSerializer`][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]
|
||||
[JsonPlusSerializer][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]
|
||||
[langgraph.json CLI reference][configuration-file]
|
||||
[LastValue][<insert-ref>]
|
||||
[LastValue][langgraph.channels.LastValue]
|
||||
[MemorySaver][<insert-ref>]
|
||||
[`messagesStateReducer`][<insert-ref>]
|
||||
[PostgresSaver][<insert-ref>]
|
||||
[PostgresSaver][langgraph.checkpoint.postgres.PostgresSaver]
|
||||
[Pregel][<insert-ref>]
|
||||
[Pregel][langgraph.pregel.Pregel]
|
||||
[`Pregel`][langgraph.pregel.Pregel.stream]
|
||||
[`pre_model_hook`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[protocol][langgraph.checkpoint.serde.base.SerializerProtocol]
|
||||
[`Send()`][langgraph.types.Send]
|
||||
[`Send`][langgraph.types.Send]
|
||||
[SerializerProtocol][<insert-ref>]
|
||||
[SerializerProtocol][langgraph.checkpoint.serde.base.SerializerProtocol]
|
||||
[SqliteSaver][<insert-ref>]
|
||||
[SqliteSaver][langgraph.checkpoint.sqlite.SqliteSaver]
|
||||
[`START`][langgraph.constants.START]
|
||||
[StateGraph (Graph API)][<insert-ref>]
|
||||
[StateGraph (Graph API)][langgraph.graph.StateGraph]
|
||||
[StateGraph (Graph API)][langgraph.graph.state.StateGraph]
|
||||
[StateGraph][<insert-ref>]
|
||||
[StateGraph][langgraph.graph.StateGraph]
|
||||
[`.stream()`][<insert-ref>]
|
||||
[`stream()`][<insert-ref>]
|
||||
[`stream`][<insert-ref>]
|
||||
[`stream()`][langgraph.graph.state.CompiledStateGraph.stream]
|
||||
[`stream`][langgraph.graph.state.CompiledStateGraph.stream]
|
||||
[`.stream()`][langgraph.pregel.Pregel.stream]
|
||||
[tasks][<insert-ref>]
|
||||
[tasks][langgraph.func.task]
|
||||
[`ToolNode`][<insert-ref>]
|
||||
[`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[ToolNode][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[Topic][<insert-ref>]
|
||||
[Topic][langgraph.channels.Topic]
|
||||
[`updateState`][<insert-ref>]
|
||||
[`update_state`][langgraph.graph.state.CompiledStateGraph.update_state]
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
import glob
|
||||
|
||||
def load_replacement_map():
|
||||
with open('replacement_map.json', 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
def replace_in_file(file_path, replacement_map):
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
original_content = content
|
||||
for key, value in replacement_map.items():
|
||||
content = content.replace(key, value)
|
||||
|
||||
if content != original_content:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
print(f"Updated: {file_path}")
|
||||
return True
|
||||
return False
|
||||
|
||||
def main():
|
||||
replacement_map = load_replacement_map()
|
||||
|
||||
md_files = glob.glob('**/*.md', recursive=True)
|
||||
updated_count = 0
|
||||
|
||||
for file_path in md_files:
|
||||
if replace_in_file(file_path, replacement_map):
|
||||
updated_count += 1
|
||||
|
||||
print(f"Processed {len(md_files)} markdown files")
|
||||
print(f"Updated {updated_count} files")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"[API reference][langgraph.prebuilt.tool_node.ToolNode]": "@[API reference][ToolNode]",
|
||||
"[API reference][toolnode]": "@[API reference][ToolNode]",
|
||||
"[AsyncPostgresSaver][langgraph.checkpoint.postgres.aio.AsyncPostgresSaver]": "@[AsyncPostgresSaver][AsyncPostgresSaver]",
|
||||
"[AsyncSqliteSaver][langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver]": "@[AsyncSqliteSaver][AsyncSqliteSaver]",
|
||||
"[BaseCheckpointSaver][langgraph.checkpoint.base.BaseCheckpointSaver]": "@[BaseCheckpointSaver][BaseCheckpointSaver]",
|
||||
"[BaseStore.put][langgraph.store.base.BaseStore.put]": "@[BaseStore.put][BaseStore.put]",
|
||||
"[BaseStore][langgraph.store.base.BaseStore]": "@[BaseStore][BaseStore]",
|
||||
"[BinaryOperatorAggregate][langgraph.channels.BinaryOperatorAggregate]": "@[BinaryOperatorAggregate][BinaryOperatorAggregate]",
|
||||
"[Command][langgraph.types.Command]": "@[Command][Command]",
|
||||
"[CompiledStateGraph][langgraph.graph.state.CompiledStateGraph]": "@[CompiledStateGraph][CompiledStateGraph]",
|
||||
"[InMemorySaver][langgraph.checkpoint.memory.InMemorySaver]": "@[InMemorySaver][InMemorySaver]",
|
||||
"[InjectedState][langgraph.prebuilt.InjectedState]": "@[InjectedState][InjectedState]",
|
||||
"[JsonPlusSerializer][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]": "@[JsonPlusSerializer][JsonPlusSerializer]",
|
||||
"[LastValue][langgraph.channels.LastValue]": "@[LastValue][LastValue]",
|
||||
"[PostgresSaver][langgraph.checkpoint.postgres.PostgresSaver]": "@[PostgresSaver][PostgresSaver]",
|
||||
"[Pregel][langgraph.pregel.Pregel]": "@[Pregel][Pregel]",
|
||||
"[SerializerProtocol][langgraph.checkpoint.serde.base.SerializerProtocol]": "@[SerializerProtocol][SerializerProtocol]",
|
||||
"[SqliteSaver][langgraph.checkpoint.sqlite.SqliteSaver]": "@[SqliteSaver][SqliteSaver]",
|
||||
"[StateGraph (Graph API)][langgraph.graph.StateGraph]": "@[StateGraph (Graph API)][StateGraph]",
|
||||
"[StateGraph (Graph API)][langgraph.graph.state.StateGraph]": "@[StateGraph (Graph API)][StateGraph]",
|
||||
"[StateGraph][langgraph.graph.StateGraph]": "@[StateGraph][StateGraph]",
|
||||
"[ToolNode][langgraph.prebuilt.tool_node.ToolNode]": "@[ToolNode][ToolNode]",
|
||||
"[Topic][langgraph.channels.Topic]": "@[Topic][Topic]",
|
||||
"[`.astream()`][langgraph.pregel.Pregel.astream]": "@[`.astream()`][Pregel.astream]",
|
||||
"[`.stream()`][langgraph.pregel.Pregel.stream]": "@[`.stream()`][Pregel.stream]",
|
||||
"[`@entrypoint`][langgraph.func.entrypoint]": "@[`@entrypoint`][entrypoint]",
|
||||
"[`CipherProtocol`][langgraph.checkpoint.serde.base.CipherProtocol]": "@[`CipherProtocol`][CipherProtocol]",
|
||||
"[`Command`][langgraph.types.Command]": "@[`Command`][Command]",
|
||||
"[`EncryptedSerializer`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer]": "@[`EncryptedSerializer`][EncryptedSerializer]",
|
||||
"[`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]": "@[`HumanInterrupt` schema][HumanInterrupt]",
|
||||
"[`HumanInterrupt`][langgraph.prebuilt.interrupt.HumanInterrupt]": "@[`HumanInterrupt`][HumanInterrupt]",
|
||||
"[`InjectedState`][langgraph.prebuilt.InjectedState]": "@[`InjectedState`][InjectedState]",
|
||||
"[`JsonPlusSerializer`][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]": "@[`JsonPlusSerializer`][JsonPlusSerializer]",
|
||||
"[`Pregel`][langgraph.pregel.Pregel.stream]": "@[`Pregel`][Pregel.stream]",
|
||||
"[`START`][langgraph.constants.START]": "@[`START`][START]",
|
||||
"[`Send()`][langgraph.types.Send]": "@[`Send()`][Send]",
|
||||
"[`Send`][langgraph.types.Send]": "@[`Send`][Send]",
|
||||
"[`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]": "@[`ToolNode`][ToolNode]",
|
||||
"[`add_conditional_edges`][langgraph.graph.StateGraph.add_conditional_edges]": "@[`add_conditional_edges`][add_conditional_edges]",
|
||||
"[`add_edge`][langgraph.graph.StateGraph.add_edge]": "@[`add_edge`][add_edge]",
|
||||
"[`add_messages`][langgraph.graph.message.add_messages]": "@[`add_messages`][add_messages]",
|
||||
"[`astream()`][langgraph.graph.state.CompiledStateGraph.astream]": "@[`astream()`][CompiledStateGraph.astream]",
|
||||
"[`client.runs.stream`][langgraph_sdk.client.RunsClient.stream]": "@[`client.runs.stream`][client.runs.stream]",
|
||||
"[`client.runs.wait`][langgraph_sdk.client.RunsClient.wait]": "@[`client.runs.wait`][client.runs.wait]",
|
||||
"[`client.threads.get_history`][langgraph_sdk.client.ThreadsClient.get_history]": "@[`client.threads.get_history`][client.threads.get_history]",
|
||||
"[`client.threads.update_state`][langgraph_sdk.client.ThreadsClient.update_state]": "@[`client.threads.update_state`][client.threads.update_state]",
|
||||
"[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]": "@[`create_react_agent`][pre_model_hook]",
|
||||
"[`create_supervisor`][langgraph_supervisor.supervisor.create_supervisor]": "@[`create_supervisor`][create_supervisor]",
|
||||
"[`entrypoint.final`][langgraph.func.entrypoint.final]": "@[`entrypoint.final`][entrypoint.final]",
|
||||
"[`entrypoint`][langgraph.func.entrypoint]": "@[`entrypoint`][entrypoint]",
|
||||
"[`from_pycryptodome_aes`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes]": "@[`from_pycryptodome_aes`][from_pycryptodome_aes]",
|
||||
"[`get_state_history()`][langgraph.graph.state.CompiledStateGraph.get_state_history]": "@[`get_state_history()`][get_state_history]",
|
||||
"[`interrupt()`][langgraph.types.interrupt]": "@[`interrupt()`][interrupt]",
|
||||
"[`interrupt` function][langgraph.types.interrupt]": "@[`interrupt` function][interrupt]",
|
||||
"[`interrupt`][langgraph.types.interrupt]": "@[`interrupt`][interrupt]",
|
||||
"[`invoke`][langgraph.graph.state.CompiledStateGraph.invoke]": "@[`invoke`][CompiledStateGraph.invoke]",
|
||||
"[`pre_model_hook`][langgraph.prebuilt.chat_agent_executor.create_react_agent]": "@[`pre_model_hook`][pre_model_hook]",
|
||||
"[`stream()`][langgraph.graph.state.CompiledStateGraph.stream]": "@[`stream()`][CompiledStateGraph.stream]",
|
||||
"[`stream`][langgraph.graph.state.CompiledStateGraph.stream]": "@[`stream`][CompiledStateGraph.stream]",
|
||||
"[`update_state`][langgraph.graph.state.CompiledStateGraph.update_state]": "@[`update_state`][update_state]",
|
||||
"[add_conditional_edges][langgraph.graph.StateGraph.add_conditional_edges]": "@[add_conditional_edges][add_conditional_edges]",
|
||||
"[add_edge][langgraph.graph.StateGraph.add_edge]": "@[add_edge][add_edge]",
|
||||
"[add_node][langgraph.graph.StateGraph.add_node]": "@[add_node][add_node]",
|
||||
"[create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]": "@[create_react_agent][pre_model_hook]",
|
||||
"[entrypoint()][langgraph.func.entrypoint]": "@[entrypoint()][entrypoint]",
|
||||
"[entrypoint][langgraph.func.entrypoint]": "@[entrypoint][entrypoint]",
|
||||
"[get_stream_writer][langgraph.config.get_stream_writer]": "@[get_stream_writer][get_stream_writer]",
|
||||
"[interrupt][langgraph.types.interrupt]": "@[interrupt][interrupt]",
|
||||
"[langgraph.json CLI reference][configuration-file]": "@[langgraph.json CLI reference][langgraph.json]",
|
||||
"[protocol][langgraph.checkpoint.serde.base.SerializerProtocol]": "@[protocol][SerializerProtocol]",
|
||||
"[tasks][langgraph.func.task]": "@[tasks][task]"
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
"""Unit tests for cross-reference preprocessing functionality."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from _scripts.handle_auto_links import _transform_link, _replace_autolinks
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_link_maps():
|
||||
"""Fixture providing mock link maps for testing."""
|
||||
mock_scope_maps = {
|
||||
"python": {"py-link": "https://example.com/python"},
|
||||
"js": {"js-link": "https://example.com/js"},
|
||||
}
|
||||
|
||||
with patch("_scripts.handle_auto_links.SCOPE_LINK_MAPS", mock_scope_maps):
|
||||
yield mock_scope_maps
|
||||
|
||||
|
||||
def test_transform_link_basic(mock_link_maps) -> None:
|
||||
"""Test basic link transformation."""
|
||||
# Test with a known link
|
||||
result = _transform_link("py-link", "python", "test.md", 1)
|
||||
assert result == "[py-link](https://example.com/python)"
|
||||
|
||||
# Test with an unknown link (returns None)
|
||||
result = _transform_link("unknown-link", "global", "test.md", 1)
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_no_cross_refs(mock_link_maps) -> None:
|
||||
"""Test markdown with no @[references]."""
|
||||
lines = ["# Title\n", "Regular text.\n"]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(["# Title\n", "Regular text.\n"])
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_global_cross_refs(mock_link_maps) -> None:
|
||||
"""Test @[references] in global scope (no conditional blocks)."""
|
||||
lines = ["@[global-link]\n", "Text with @[unknown-link].\n"]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(["@[global-link]\n", "Text with @[unknown-link].\n"])
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_python_conditional_block(mock_link_maps) -> None:
|
||||
"""Test @[references] inside Python conditional block."""
|
||||
lines = [":::python\n", "@[py-link]\n", ":::\n"]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(
|
||||
[":::python\n", "[py-link](https://example.com/python)\n", ":::\n"]
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_js_conditional_block(mock_link_maps) -> None:
|
||||
"""Test @[references] inside JavaScript conditional block."""
|
||||
lines = [":::js\n", "@[js-link]\n", ":::\n"]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join([":::js\n", "[js-link](https://example.com/js)\n", ":::\n"])
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_all_scopes(mock_link_maps) -> None:
|
||||
"""Test @[references] in global, Python, and JavaScript scopes."""
|
||||
lines = [
|
||||
"@[global-link]\n",
|
||||
":::python\n",
|
||||
"@[py-link]\n",
|
||||
":::\n",
|
||||
"@[global-link]\n",
|
||||
":::js\n",
|
||||
"@[js-link]\n",
|
||||
":::\n",
|
||||
"@[global-link]\n",
|
||||
]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(
|
||||
[
|
||||
"@[global-link]\n",
|
||||
":::python\n",
|
||||
"[py-link](https://example.com/python)\n",
|
||||
":::\n",
|
||||
"@[global-link]\n",
|
||||
":::js\n",
|
||||
"[js-link](https://example.com/js)\n",
|
||||
":::\n",
|
||||
"@[global-link]\n",
|
||||
]
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_fence_resets_to_global(mock_link_maps) -> None:
|
||||
"""Test that closing fence resets scope to global."""
|
||||
lines = [":::python\n", "@[py-link]\n", ":::\n", "@[global-link]\n"]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(
|
||||
[
|
||||
":::python\n",
|
||||
"[py-link](https://example.com/python)\n",
|
||||
":::\n",
|
||||
"@[global-link]\n",
|
||||
]
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_indented_conditional_fences(mock_link_maps) -> None:
|
||||
"""Test @[references] inside indented conditional fences (e.g., in tabs or admonitions)."""
|
||||
lines = [
|
||||
"@[global-link]\n",
|
||||
" :::python\n",
|
||||
" @[py-link]\n",
|
||||
" :::\n",
|
||||
"@[global-link]\n",
|
||||
"\t\t:::js\n",
|
||||
"\t\t@[js-link]\n",
|
||||
"\t\t:::\n",
|
||||
"@[global-link]\n",
|
||||
]
|
||||
markdown = "".join(lines)
|
||||
result = _replace_autolinks(markdown, "test.md")
|
||||
expected = "".join(
|
||||
[
|
||||
"@[global-link]\n",
|
||||
" :::python\n",
|
||||
" [py-link](https://example.com/python)\n",
|
||||
" :::\n",
|
||||
"@[global-link]\n",
|
||||
"\t\t:::js\n",
|
||||
"\t\t[js-link](https://example.com/js)\n",
|
||||
"\t\t:::\n",
|
||||
"@[global-link]\n",
|
||||
]
|
||||
)
|
||||
assert result == expected
|
||||
@@ -165,7 +165,7 @@ def patch_config(
|
||||
Defaults to None.
|
||||
recursion_limit: The recursion limit to set.
|
||||
Defaults to None.
|
||||
max_concurrency: The max concurrency to set.
|
||||
max_concurrency: The max number of concurrent steps to run, which also applies to parallelized steps.
|
||||
Defaults to None.
|
||||
run_name: The run name to set. Defaults to None.
|
||||
configurable: The configurable to set.
|
||||
|
||||
Reference in New Issue
Block a user