1313
1414import argparse
1515import datetime
16+ import functools
1617import os
1718import re
1819import shlex
3233RERUN_FILE_DEFAULT = ROOT_DIR / ".tmp" / "examples-rerun.txt"
3334DEFAULT_MAIN_LOG = LOG_DIR_DEFAULT / f"main_{ datetime .datetime .now ().strftime ('%Y%m%d-%H%M%S' )} .log"
3435
36+ COMMON_PATH_HINTS = (
37+ Path .home () / ".local" / "bin" ,
38+ Path ("/opt/homebrew/bin" ),
39+ Path ("/opt/homebrew/sbin" ),
40+ Path ("/usr/local/bin" ),
41+ Path ("/usr/local/sbin" ),
42+ )
43+
44+ DISCOVERY_EXCLUDE = {
45+ "examples/run_examples.py" ,
46+ }
47+
3548# Examples that are noisy, require extra credentials, or hang in auto runs.
3649DEFAULT_AUTO_SKIP = {
3750 "examples/agent_patterns/llm_as_a_judge.py" ,
3851 "examples/agent_patterns/routing.py" ,
3952 "examples/customer_service/main.py" ,
4053 "examples/hosted_mcp/connectors.py" ,
4154 "examples/mcp/git_example/main.py" ,
55+ # These are helper daemons or multi-process components exercised by sibling examples.
56+ "examples/mcp/manager_example/app.py" ,
57+ "examples/mcp/manager_example/mcp_server.py" ,
58+ "examples/mcp/prompt_server/server.py" ,
59+ "examples/mcp/sse_example/server.py" ,
60+ "examples/mcp/streamablehttp_custom_client_example/server.py" ,
61+ "examples/mcp/streamablehttp_example/server.py" ,
4262 "examples/model_providers/custom_example_agent.py" ,
4363 "examples/model_providers/custom_example_global.py" ,
4464 "examples/model_providers/custom_example_provider.py" ,
@@ -84,6 +104,63 @@ def normalize_relpath(relpath: str) -> str:
84104 return str (PurePosixPath (normalized ))
85105
86106
107+ def split_path_entries (path_value : str ) -> list [str ]:
108+ return [entry for entry in path_value .split (os .pathsep ) if entry ]
109+
110+
111+ def dedupe_existing_paths (paths : Iterable [str ]) -> list [str ]:
112+ deduped : list [str ] = []
113+ seen : set [str ] = set ()
114+ for entry in paths :
115+ expanded = os .path .expanduser (entry )
116+ if not expanded or expanded in seen :
117+ continue
118+ if not Path (expanded ).exists ():
119+ continue
120+ deduped .append (expanded )
121+ seen .add (expanded )
122+ return deduped
123+
124+
125+ @functools .lru_cache (maxsize = 1 )
126+ def interactive_shell_path () -> str | None :
127+ shell = os .environ .get ("SHELL" )
128+ if not shell :
129+ return None
130+
131+ shell_name = Path (shell ).name
132+ if shell_name not in {"bash" , "zsh" }:
133+ return None
134+
135+ try :
136+ result = subprocess .run (
137+ [shell , "-lic" , 'printf "%s" "$PATH"' ],
138+ capture_output = True ,
139+ check = True ,
140+ cwd = ROOT_DIR ,
141+ text = True ,
142+ )
143+ except (OSError , subprocess .SubprocessError ):
144+ return None
145+
146+ path_value = result .stdout .strip ()
147+ return path_value or None
148+
149+
150+ def build_command_path (base_path : str | None = None ) -> str :
151+ candidates : list [str ] = []
152+ if base_path is None :
153+ base_path = os .environ .get ("PATH" , "" )
154+ candidates .extend (split_path_entries (base_path ))
155+
156+ shell_path = interactive_shell_path ()
157+ if shell_path :
158+ candidates .extend (split_path_entries (shell_path ))
159+
160+ candidates .extend (str (path ) for path in COMMON_PATH_HINTS )
161+ return os .pathsep .join (dedupe_existing_paths (candidates ))
162+
163+
87164def parse_args () -> argparse .Namespace :
88165 parser = argparse .ArgumentParser (description = "Run example scripts sequentially." )
89166 parser .add_argument (
@@ -221,6 +298,10 @@ def discover_examples(filters: Iterable[str]) -> list[ExampleScript]:
221298 if not MAIN_PATTERN .search (source ):
222299 continue
223300
301+ relpath = normalize_relpath (str (path .relative_to (ROOT_DIR )))
302+ if relpath in DISCOVERY_EXCLUDE :
303+ continue
304+
224305 if filters_lower and not any (
225306 f in str (path .relative_to (ROOT_DIR )).lower () for f in filters_lower
226307 ):
@@ -351,6 +432,11 @@ def run_examples(examples: Sequence[ExampleScript], args: argparse.Namespace) ->
351432 buffer_output = not args .no_buffer_output and os .environ .get (
352433 "EXAMPLES_BUFFER_OUTPUT" , "1"
353434 ).lower () not in {"0" , "false" , "no" , "off" }
435+ command_path = build_command_path ()
436+ path_augmented = command_path != os .environ .get ("PATH" , "" )
437+
438+ if path_augmented :
439+ print ("Augmented subprocess PATH using interactive shell/common tool directories." )
354440
355441 def safe_write_main (line : str ) -> None :
356442 with main_log_lock :
@@ -363,6 +449,7 @@ def run_single(example: ExampleScript) -> ExampleResult:
363449 ensure_dirs (log_path , is_file = True )
364450
365451 env = os .environ .copy ()
452+ env ["PATH" ] = command_path
366453 if auto_mode :
367454 env ["EXAMPLES_INTERACTIVE_MODE" ] = "auto"
368455 env ["APPLY_PATCH_AUTO_APPROVE" ] = "1"
@@ -441,6 +528,7 @@ def run_single(example: ExampleScript) -> ExampleResult:
441528 safe_write_main (f"# logs_dir: { logs_dir } " )
442529 safe_write_main (f"# jobs: { jobs } " )
443530 safe_write_main (f"# buffer_output: { buffer_output } " )
531+ safe_write_main (f"# path_augmented: { path_augmented } " )
444532
445533 run_list : list [ExampleScript ] = []
446534
0 commit comments