1616
1717def on_page_markdown (markdown : str , page : Page , config : Config , files : Files ) -> str :
1818 """Called on each file after it is read and before it is converted to HTML."""
19- markdown = inject_snippets (markdown , (DOCS_ROOT / page .file .src_uri ).parent )
19+ relative_path_root = (DOCS_ROOT / page .file .src_uri ).parent
20+ markdown = inject_snippets (markdown , relative_path_root )
2021 markdown = replace_uv_python_run (markdown )
2122 markdown = render_examples (markdown )
2223 markdown = render_video (markdown )
23- markdown = create_gateway_toggle (markdown )
24+ markdown = create_gateway_toggle (markdown , relative_path_root )
2425 return markdown
2526
2627
@@ -119,13 +120,13 @@ def sub_cf_video(m: re.Match[str]) -> str:
119120"""
120121
121122
122- def create_gateway_toggle (markdown : str ) -> str :
123+ def create_gateway_toggle (markdown : str , relative_path_root : Path ) -> str :
123124 """Transform Python code blocks with Agent() calls to show both Pydantic AI and Gateway versions."""
124125 # Pattern matches Python code blocks with or without attributes, and optional annotation definitions after
125126 # Annotation definitions are numbered list items like "1. Some text" that follow the code block
126127 return re .sub (
127- r'```python (?:\s+\{ ([^}]*)\})?\n(.*?)\n```(\n\n(?:\d+\..+(?:\n(?: .+|\n))*)+ )?' ,
128- transform_gateway_code_block ,
128+ r'```py (?:thon)?(?: *\{? ([^}\n ]*)\}? )?\n(.*?)\n```(\n\n(?:\d+\..+?\n)+?\n )?' ,
129+ lambda m : transform_gateway_code_block ( m , relative_path_root ) ,
129130 markdown ,
130131 flags = re .MULTILINE | re .DOTALL ,
131132 )
@@ -135,7 +136,7 @@ def create_gateway_toggle(markdown: str) -> str:
135136GATEWAY_MODELS = ('anthropic' , 'openai' , 'openai-responses' , 'openai-chat' , 'bedrock' , 'google-vertex' , 'groq' )
136137
137138
138- def transform_gateway_code_block (m : re .Match [str ]) -> str :
139+ def transform_gateway_code_block (m : re .Match [str ], relative_path_root : Path ) -> str :
139140 """Transform a single code block to show both versions if it contains Agent() calls."""
140141 attrs = m .group (1 ) or ''
141142 code = m .group (2 )
@@ -184,8 +185,18 @@ def replace_agent_model(match: re.Match[str]) -> str:
184185 )
185186
186187 # Build attributes string
188+ docs_path = DOCS_ROOT / 'gateway'
189+ relative_path = docs_path .relative_to (relative_path_root , walk_up = True )
190+ link = f"<a href='{ relative_path } ' style='float: right;'>Learn about Gateway</a>"
191+
187192 attrs_str = f' {{{ attrs } }}' if attrs else ''
188193
194+ if 'title="' in attrs :
195+ gateway_attrs = attrs .replace ('title="' , f'title="{ link } ' , 1 )
196+ else :
197+ gateway_attrs = attrs + f' title="{ link } "'
198+ gateway_attrs_str = f' {{{ gateway_attrs } }}'
199+
189200 # Indent code lines for proper markdown formatting within tabs
190201 # Always add 4 spaces to every line (even empty ones) to preserve annotations
191202 code_lines = code .split ('\n ' )
@@ -197,18 +208,18 @@ def replace_agent_model(match: re.Match[str]) -> str:
197208 # Indent annotation definitions if present (need to be inside tabs for Material to work)
198209 indented_annotations = ''
199210 if annotations :
200- # Remove leading newlines and indent each line with 4 spaces
211+ # Remove surrounding newlines and indent each line with 4 spaces
201212 annotation_lines = annotations .strip ().split ('\n ' )
202- indented_annotations = '\n \n ' + '\n ' .join (' ' + line for line in annotation_lines )
213+ indented_annotations = '\n \n ' + '\n ' .join (' ' + line for line in annotation_lines ) + ' \n \n '
203214
204215 return f"""\
205- === "Pydantic AI Gateway"
216+ === "With Pydantic AI Gateway"
206217
207- ```python{ attrs_str }
218+ ```python{ gateway_attrs_str }
208219{ indented_gateway_code }
209220 ```{ indented_annotations }
210221
211- === "Pydantic AI "
222+ === "Directly to Provider API "
212223
213224 ```python{ attrs_str }
214225{ indented_code }
0 commit comments