diff --git a/packages/docs/v4/basics/act.mdx b/packages/docs/v4/basics/act.mdx index 30dd339c4..b05596a78 100644 --- a/packages/docs/v4/basics/act.mdx +++ b/packages/docs/v4/basics/act.mdx @@ -520,7 +520,7 @@ if (action?.method === "click") { ```python -result = await stagehand.observe(instruction="click the login button") +result = await stagehand.observe("click the login button") if result.data and result.data[0].method == "click": # No inference: Stagehand replays the observed action @@ -764,7 +764,7 @@ except Exception as error: raise # Observe the same prompt to get the planned action - observed = await stagehand.observe(instruction=prompt) + observed = await stagehand.observe(prompt) action = observed.data[0] if observed.data else None if action is not None and action.method == expected_method: @@ -930,7 +930,7 @@ except Exception: await page.wait_for_load_state("domcontentloaded") # Use observe to check element state - observed = await stagehand.observe(instruction="find the submit button") + observed = await stagehand.observe("find the submit button") if observed.data: print("Element found, trying more specific instruction") @@ -1013,7 +1013,7 @@ await stagehand.act("click the red 'Delete' button next to the user John Smith") # Or preview with observe first: observed = await stagehand.observe( - instruction="click the submit button in the checkout form" + "click the submit button in the checkout form" ) if observed.data and "checkout" in observed.data[0].description: await stagehand.act(observed.data[0]) diff --git a/packages/docs/v4/basics/extract.mdx b/packages/docs/v4/basics/extract.mdx index 6347354a2..30f08aa67 100644 --- a/packages/docs/v4/basics/extract.mdx +++ b/packages/docs/v4/basics/extract.mdx @@ -21,8 +21,8 @@ class Repository(BaseModel): await stagehand.extract( - instruction="extract the name of the repository", - schema=Repository, + "extract the name of the repository", + Repository, ) ``` @@ -93,8 +93,8 @@ class Product(BaseModel): result = await stagehand.extract( - instruction="extract product details", - schema=Product, + "extract product details", + Product, ) ``` @@ -188,8 +188,8 @@ class Apartments(BaseModel): result = await stagehand.extract( - instruction="extract all apartment listings", - schema=Apartments, + "extract all apartment listings", + Apartments, ) ``` @@ -298,8 +298,8 @@ class Price(BaseModel): result = await stagehand.extract( - instruction="extract the price", - schema=Price, + "extract the price", + Price, ) ``` @@ -371,8 +371,8 @@ class ContactLink(BaseModel): result = await stagehand.extract( - instruction="extract the contact page link", - schema=ContactLink, + "extract the contact page link", + ContactLink, ) ``` @@ -429,8 +429,8 @@ const result = await stagehand.extract( from stagehand import ModelConfig result = await stagehand.extract( - instruction="extract the repository name", - schema=Repository, + "extract the repository name", + Repository, model=ModelConfig.model_validate({ "model_name": "anthropic/claude-sonnet-4-6", "api_key": os.environ["ANTHROPIC_API_KEY"], @@ -516,8 +516,8 @@ stagehand = Stagehand( # Or disable it for a single call result = await stagehand.extract( - instruction="extract the repository name", - schema=Repository, + "extract the repository name", + Repository, cache=False, ) @@ -589,8 +589,8 @@ class TableRow(BaseModel): table_data = (await stagehand.extract( - instruction="Extract the values of the third row", - schema=TableRow, + "Extract the values of the third row", + TableRow, # xPath or CSS selector selector="xpath=/html/body/div/table/", )).data @@ -650,8 +650,8 @@ class Article(BaseModel): article = (await stagehand.extract( - instruction="extract the article title and body", - schema=Article, + "extract the article title and body", + Article, ignore_selectors=[".ad", ".newsletter-modal", "nav.related-posts"], )).data ``` @@ -717,8 +717,8 @@ class SaleBadge(BaseModel): sale_badge = (await stagehand.extract( - instruction="extract the text shown in the visible sale badge", - schema=SaleBadge, + "extract the text shown in the visible sale badge", + SaleBadge, screenshot=True, )).data ``` @@ -796,11 +796,11 @@ class Apartments(BaseModel): result = await stagehand.extract( - instruction=( + ( "Extract ALL the apartment listings and their details, " "including address, price, and square feet." ), - schema=Apartments, + Apartments, ) ``` @@ -879,8 +879,8 @@ class ContactLink(BaseModel): result = await stagehand.extract( - instruction="extract the link to the 'contact us' page", - schema=ContactLink, + "extract the link to the 'contact us' page", + ContactLink, ) print("the link to the contact us page is: ", result.data.contact_link) @@ -973,8 +973,8 @@ class Products(BaseModel): result = await stagehand.extract( - instruction="extract all product names and prices", - schema=Products, + "extract all product names and prices", + Products, ) ``` @@ -1120,7 +1120,7 @@ const { data } = await stagehand.extract( ```python # First observe to understand the page structure -observed = await stagehand.observe(instruction="find all product listings") +observed = await stagehand.observe("find all product listings") print("Found elements:", [element.description for element in observed.data]) @@ -1135,8 +1135,8 @@ class Products(BaseModel): result = await stagehand.extract( - instruction="extract name and price from each product listing shown on the page", - schema=Products, + "extract name and price from each product listing shown on the page", + Products, ) ``` @@ -1247,8 +1247,8 @@ for page_num in page_numbers: await stagehand.act(f"navigate to page {page_num}") result = await stagehand.extract( - instruction="extract product data from the current page only", - schema=Products, + "extract product data from the current page only", + Products, timeout=60000, # 60 second timeout ) diff --git a/packages/docs/v4/basics/observe.mdx b/packages/docs/v4/basics/observe.mdx index 743fc62e9..d127bd17c 100644 --- a/packages/docs/v4/basics/observe.mdx +++ b/packages/docs/v4/basics/observe.mdx @@ -13,7 +13,7 @@ await stagehand.observe("find the login button"); ```python -await stagehand.observe(instruction="find the login button") +await stagehand.observe("find the login button") ``` @@ -66,7 +66,7 @@ page = await stagehand.context.active_page() if page is None: raise RuntimeError("Stagehand initialized without an active page") await page.goto("https://example.com") -result = await stagehand.observe(instruction="find the learn more button") +result = await stagehand.observe("find the learn more button") ``` @@ -173,10 +173,10 @@ await stagehand.observe("find the delete account button in settings"); ```python # Clear and specific await stagehand.observe( - instruction="find the primary call-to-action button in the hero section" + "find the primary call-to-action button in the hero section" ) -await stagehand.observe(instruction="find all input fields in the checkout form") -await stagehand.observe(instruction="find the delete account button in settings") +await stagehand.observe("find all input fields in the checkout form") +await stagehand.observe("find the delete account button in settings") ``` @@ -217,10 +217,10 @@ await stagehand.observe("what is the page title?"); ```python # Too vague -await stagehand.observe(instruction="find buttons") +await stagehand.observe("find buttons") # Use extract() for data instead -await stagehand.observe(instruction="what is the page title?") +await stagehand.observe("what is the page title?") ``` @@ -266,7 +266,7 @@ from stagehand import ModelConfig # Custom model configuration result = await stagehand.observe( - instruction="find navigation links", + "find navigation links", model=ModelConfig.model_validate({ "model_name": "openai/gpt-5.4-mini", "api_key": os.environ["OPENAI_API_KEY"], @@ -320,7 +320,7 @@ const { data: actions } = await stagehand.observe("find the main call-to-action ```python result = await stagehand.observe( - instruction="find the main call-to-action buttons", + "find the main call-to-action buttons", ignore_selectors=[ "//aside[contains(@class, 'promo-rail')]", "//div[@id='floating-chat-launcher']", @@ -380,7 +380,7 @@ if (emailField && passwordField) { ```python observed = await stagehand.observe( - instruction="find the login form fields", + "find the login form fields", variables={ "username": {"value": "user@example.com", "description": "The login email"}, "password": { @@ -503,7 +503,7 @@ stagehand = Stagehand( ) # Or disable it for a single call -result = await stagehand.observe(instruction="find the login button", cache=False) +result = await stagehand.observe("find the login button", cache=False) ``` @@ -575,7 +575,7 @@ await products_page.goto("https://www.example.com/products") # Use observe with that specific page result = await stagehand.observe( - instruction="find all product cards", + "find all product cards", page=products_page, ) ``` @@ -647,7 +647,7 @@ for (const field of formFields) { ```python -observed = await stagehand.observe(instruction="find all form input fields") +observed = await stagehand.observe("find all form input fields") for field in observed.data: # No LLM call: Stagehand replays the observed action @@ -717,11 +717,11 @@ class Pricing(BaseModel): tiers: list[PricingTier] -observed = await stagehand.observe(instruction="find the pricing table") +observed = await stagehand.observe("find the pricing table") pricing = (await stagehand.extract( - instruction="extract all pricing tiers", - schema=Pricing, + "extract all pricing tiers", + Pricing, selector=observed.data[0].selector, )).data @@ -813,7 +813,7 @@ if (deleteButton?.method === "click") { ```python -observed = await stagehand.observe(instruction="find the delete account button") +observed = await stagehand.observe("find the delete account button") delete_button = observed.data[0] if observed.data else None if delete_button is not None and delete_button.method == "click": @@ -874,7 +874,7 @@ async def cached_observe(instruction: str) -> list[Action]: if instruction in action_cache: return action_cache[instruction] - observed = await stagehand.observe(instruction=instruction) + observed = await stagehand.observe(instruction) action_cache[instruction] = observed.data return observed.data ``` @@ -942,12 +942,12 @@ if page is None: raise RuntimeError("Stagehand initialized without an active page") await page.wait_for_load_state("domcontentloaded") -observed = await stagehand.observe(instruction="find the submit button") +observed = await stagehand.observe("find the submit button") if not observed.data: print("No elements found, trying alternative instruction") alt = await stagehand.observe( - instruction="find the button at the bottom of the form" + "find the button at the bottom of the form" ) ``` @@ -1006,11 +1006,11 @@ await stagehand.observe("find the red 'Delete' button in the user settings panel ```python # More specific instructions improve accuracy # Instead of: -await stagehand.observe(instruction="find the button") +await stagehand.observe("find the button") # Use context: await stagehand.observe( - instruction="find the red 'Delete' button in the user settings panel" + "find the red 'Delete' button in the user settings panel" ) ``` @@ -1058,7 +1058,7 @@ if (action && validMethods.includes(action.method || "")) { ```python -observed = await stagehand.observe(instruction="find the submit button") +observed = await stagehand.observe("find the submit button") action = observed.data[0] if observed.data else None # Validate method before acting diff --git a/packages/docs/v4/configuration/models.mdx b/packages/docs/v4/configuration/models.mdx index cea4b1d92..f6f89c883 100644 --- a/packages/docs/v4/configuration/models.mdx +++ b/packages/docs/v4/configuration/models.mdx @@ -1312,8 +1312,8 @@ await stagehand.act("click the login button") # Uses a stronger model for one hard extraction data = (await stagehand.extract( - instruction="summarize the pricing table", - schema=Pricing, + "summarize the pricing table", + Pricing, model=ModelConfig.model_validate({ "model_name": "anthropic/claude-sonnet-4-6", "api_key": os.environ["ANTHROPIC_API_KEY"], diff --git a/packages/docs/v4/configuration/observability.mdx b/packages/docs/v4/configuration/observability.mdx index 225078797..ff64ba8e5 100644 --- a/packages/docs/v4/configuration/observability.mdx +++ b/packages/docs/v4/configuration/observability.mdx @@ -354,7 +354,7 @@ if page is None: raise RuntimeError("Stagehand initialized without an active page") await page.goto("https://example.com") await stagehand.act("click button") -await stagehand.extract(instruction="get data", schema=Data) +await stagehand.extract("get data", Data) final_metrics = await stagehand.metrics() execution_time = (perf_counter() - start_time) * 1000 @@ -703,7 +703,7 @@ if page is None: raise RuntimeError("Stagehand initialized without an active page") await page.goto("https://example.com") await stagehand.act("click the login button") -data = (await stagehand.extract(instruction="extract user info", schema=User)).data +data = (await stagehand.extract("extract user info", User)).data print(f"Extracted {data.name} <{data.email}>") final_metrics = await stagehand.metrics() diff --git a/packages/docs/v4/first-steps/ai-rules.mdx b/packages/docs/v4/first-steps/ai-rules.mdx index ba08930cc..ddaee8026 100644 --- a/packages/docs/v4/first-steps/ai-rules.mdx +++ b/packages/docs/v4/first-steps/ai-rules.mdx @@ -399,7 +399,8 @@ The main class can be imported as `Stagehand` from `stagehand`. There is no `agent` API in v4. Compose `observe`, `act`, and `extract` in your own control flow instead. -All Stagehand methods are async. `observe` and `extract` take keyword-only arguments. +All Stagehand methods are async. `act`, `observe`, and `extract` take `instruction` (and, for +`extract`, `schema`) positionally; every other argument is keyword-only. ## Initialize @@ -471,7 +472,7 @@ await stagehand.act( `act` accepts either a string instruction or an `Action` returned by `observe`. Use `observe` to inspect the candidate action, then pass it back to `act` for deterministic replay with no inference: ```python -result = await stagehand.observe(instruction="Click the sign in button") +result = await stagehand.observe("Click the sign in button") action = result.data[0] if result.data else None if action is not None and action.method == "click": @@ -482,7 +483,7 @@ To target a specific page: ```python result = await stagehand.observe( - instruction="select blue as the favorite color", + "select blue as the favorite color", page=page2, ) await stagehand.act(result.data[0], page=page2) @@ -510,8 +511,8 @@ class Listings(BaseModel): result = await stagehand.extract( - instruction="extract all apartment listings with prices and addresses", - schema=Listings, + "extract all apartment listings with prices and addresses", + Listings, ) print(result.data.listings) @@ -527,8 +528,8 @@ class ButtonText(BaseModel): result = await stagehand.extract( - instruction="extract the sign in button text", - schema=ButtonText, + "extract the sign in button text", + ButtonText, ) print(result.data.button_text) # "Sign in" @@ -544,8 +545,8 @@ class Reason(BaseModel): result = await stagehand.extract( - instruction="extract the reason why script injection fails", - schema=Reason, + "extract the reason why script injection fails", + Reason, selector="#main-content", ignore_selectors=["nav", ".cookie-banner"], ) @@ -564,8 +565,8 @@ class Links(BaseModel): result = await stagehand.extract( - instruction="extract all navigation links", - schema=Links, + "extract all navigation links", + Links, ) ``` @@ -577,8 +578,8 @@ class Placeholder(BaseModel): result = await stagehand.extract( - instruction="extract the placeholder text on the name field", - schema=Placeholder, + "extract the placeholder text on the name field", + Placeholder, page=page2, ) ``` @@ -591,8 +592,8 @@ class Title(BaseModel): result = await stagehand.extract( - instruction="extract the page title", - schema=Title, + "extract the page title", + Title, ) print(result.data.title) @@ -605,7 +606,7 @@ print(result.metadata.cache_status) # "HIT", "MISS", or None Plan actions before executing them. Candidate actions are returned on `data`: ```python -result = await stagehand.observe(instruction="Click the sign in button") +result = await stagehand.observe("Click the sign in button") action = result.data[0] if result.data else None if action is not None: @@ -616,7 +617,7 @@ Observing on a specific page: ```python result = await stagehand.observe( - instruction="find the next page button", + "find the next page button", page=page2, ) await stagehand.act(result.data[0], page=page2) @@ -646,7 +647,7 @@ await page2.goto("https://example2.com") # Act/extract/observe operate on the current active page by default # Pass page= to target a specific page await stagehand.act("click button", page=page1) -await stagehand.extract(instruction="get title", schema=Title, page=page2) +await stagehand.extract("get title", Title, page=page2) ``` ### Caching diff --git a/packages/docs/v4/first-steps/installation.mdx b/packages/docs/v4/first-steps/installation.mdx index 614c723dc..e2ee5d940 100644 --- a/packages/docs/v4/first-steps/installation.mdx +++ b/packages/docs/v4/first-steps/installation.mdx @@ -202,8 +202,8 @@ async def main() -> None: # Extract structured data result = await stagehand.extract( - instruction="extract the description", - schema=Description, + "extract the description", + Description, ) print(result.data.description) diff --git a/packages/docs/v4/first-steps/introduction.mdx b/packages/docs/v4/first-steps/introduction.mdx index c706899a6..08b4da917 100644 --- a/packages/docs/v4/first-steps/introduction.mdx +++ b/packages/docs/v4/first-steps/introduction.mdx @@ -56,13 +56,13 @@ class Price(BaseModel): price: float result = await stagehand.extract( - instruction="extract the price", - schema=Price, + "extract the price", + Price, ) price = result.data.price # Observe: discover available actions -actions = (await stagehand.observe(instruction="find submit buttons")).data +actions = (await stagehand.observe("find submit buttons")).data ``` diff --git a/packages/docs/v4/first-steps/quickstart.mdx b/packages/docs/v4/first-steps/quickstart.mdx index e4155e1e2..473502307 100644 --- a/packages/docs/v4/first-steps/quickstart.mdx +++ b/packages/docs/v4/first-steps/quickstart.mdx @@ -120,14 +120,14 @@ async def main() -> None: await page.goto("https://stagehand.dev") extract_result = await stagehand.extract( - instruction="Extract the value proposition from the page.", - schema=ValueProposition, + "Extract the value proposition from the page.", + ValueProposition, ) print("Extract result:\n", extract_result.data) await stagehand.act("Click the 'Evals' button.") - observe_result = await stagehand.observe(instruction="What can I click on this page?") + observe_result = await stagehand.observe("What can I click on this page?") print("Observe result:\n", observe_result.data) finally: # Always release the session, even when a step above raises diff --git a/packages/docs/v4/reference/stagehand.mdx b/packages/docs/v4/reference/stagehand.mdx index afd42357c..a88ac5ee5 100644 --- a/packages/docs/v4/reference/stagehand.mdx +++ b/packages/docs/v4/reference/stagehand.mdx @@ -829,7 +829,7 @@ result = await stagehand.act("Click the sign in button") Find candidate actions on the page from an optional instruction. ```python -actions = await stagehand.observe(instruction="Find the sign in button") +actions = await stagehand.observe("Find the sign in button") ``` @@ -957,7 +957,7 @@ actions = await stagehand.observe(instruction="Find the sign in button") Extract structured data from the page. ```python -product = await stagehand.extract(instruction="Extract the product", schema=Product) +product = await stagehand.extract("Extract the product", Product) print(product.data, product.metadata.cache_status) ``` diff --git a/packages/sdk-python/README.md b/packages/sdk-python/README.md index 34b73f6c8..d32d9a94d 100644 --- a/packages/sdk-python/README.md +++ b/packages/sdk-python/README.md @@ -17,7 +17,7 @@ async def main() -> None: if page is None: raise RuntimeError("Stagehand initialized without an active page") await page.goto("https://example.com") - await stagehand.observe(instruction="Find the more information link") + await stagehand.observe("Find the more information link") print(await page.title()) finally: await stagehand.close() diff --git a/packages/sdk-python/examples/caching.py b/packages/sdk-python/examples/caching.py index 0a4c590a2..77c9382b4 100644 --- a/packages/sdk-python/examples/caching.py +++ b/packages/sdk-python/examples/caching.py @@ -42,11 +42,11 @@ async def main() -> None: async def extract_companies() -> tuple[ExtractResult[Companies], int]: start = perf_counter() result = await stagehand.extract( - instruction=( + ( "Extract the names and descriptions of the first five companies " "listed on the page" ), - schema=Companies, + Companies, page=page, cache=True, ) diff --git a/packages/sdk-python/examples/custom_llm.py b/packages/sdk-python/examples/custom_llm.py index e007f55f4..f63fd129c 100644 --- a/packages/sdk-python/examples/custom_llm.py +++ b/packages/sdk-python/examples/custom_llm.py @@ -46,11 +46,11 @@ async def main() -> None: await page.goto("https://example.com") page_info = await stagehand.extract( - instruction="Extract the page heading and description", - schema=PageInfo, + "Extract the page heading and description", + PageInfo, ) actions = await stagehand.observe( - instruction="Find the link that provides more information about Example Domain", + "Find the link that provides more information about Example Domain", ) action_result = await stagehand.act( "Click the link that provides more information about Example Domain" diff --git a/packages/sdk-python/examples/custom_logging.py b/packages/sdk-python/examples/custom_logging.py index b03ad07e3..114b1fb77 100644 --- a/packages/sdk-python/examples/custom_logging.py +++ b/packages/sdk-python/examples/custom_logging.py @@ -28,7 +28,7 @@ async def main() -> None: raise RuntimeError await page.goto("https://example.com") - print(await stagehand.observe(instruction="Find the Learn more link")) + print(await stagehand.observe("Find the Learn more link")) finally: await stagehand.close() finally: diff --git a/packages/sdk-python/examples/extract.py b/packages/sdk-python/examples/extract.py index 5ce135403..4c61c957c 100644 --- a/packages/sdk-python/examples/extract.py +++ b/packages/sdk-python/examples/extract.py @@ -31,8 +31,8 @@ async def main() -> None: await page.goto("https://example.com") page_info = await stagehand.extract( - instruction="Extract the page heading and description", - schema=PageInfo, + "Extract the page heading and description", + PageInfo, ) print(json.dumps(page_info.model_dump(mode="json"), indent=2)) diff --git a/packages/sdk-python/examples/model_gateway.py b/packages/sdk-python/examples/model_gateway.py index b9ba73f47..2ba874b99 100644 --- a/packages/sdk-python/examples/model_gateway.py +++ b/packages/sdk-python/examples/model_gateway.py @@ -32,8 +32,8 @@ async def main() -> None: await page.goto("https://example.com") page_info = await stagehand.extract( - instruction="Extract the page heading and the domain this page says it is for", - schema=PageInfo, + "Extract the page heading and the domain this page says it is for", + PageInfo, ) print(json.dumps(page_info.model_dump(mode="json"), indent=2)) diff --git a/packages/sdk-python/examples/observe.py b/packages/sdk-python/examples/observe.py index fbf8c727e..3e46d61a9 100644 --- a/packages/sdk-python/examples/observe.py +++ b/packages/sdk-python/examples/observe.py @@ -24,7 +24,7 @@ async def main() -> None: await page.goto("https://example.com") actions = await stagehand.observe( - instruction="Find the link that provides more information about Example Domain", + "Find the link that provides more information about Example Domain", ) print( diff --git a/packages/sdk-python/src/stagehand/stagehand.py b/packages/sdk-python/src/stagehand/stagehand.py index 4823a41bd..d46b8770b 100644 --- a/packages/sdk-python/src/stagehand/stagehand.py +++ b/packages/sdk-python/src/stagehand/stagehand.py @@ -239,8 +239,8 @@ async def act( async def observe( self, - *, instruction: str | None = None, + *, page: Page | None = None, model: ModelConfig | None = None, variables: Variables | None = None, @@ -274,9 +274,9 @@ async def observe( async def extract( self, - *, instruction: str, schema: builtins.type[ResultModel], + *, page: Page | None = None, model: ModelConfig | None = None, timeout: float | None = None, diff --git a/packages/sdk-python/tests/test_stagehand.py b/packages/sdk-python/tests/test_stagehand.py index e5cc1c54a..0faab0ef7 100644 --- a/packages/sdk-python/tests/test_stagehand.py +++ b/packages/sdk-python/tests/test_stagehand.py @@ -2,6 +2,7 @@ import asyncio import importlib +import inspect import json from collections.abc import Awaitable, Callable from typing import TypeVar, cast, overload @@ -569,10 +570,10 @@ async def test_stagehand_routes_metrics_and_ai_methods( locator=locator, cache=CacheOptions(threshold=1), ) - observed = await stagehand.observe(instruction="Find the link", model=model, locator=locator) + observed = await stagehand.observe("Find the link", model=model, locator=locator) extracted = await stagehand.extract( - instruction="Extract the heading", - schema=PageInfo, + "Extract the heading", + PageInfo, page=page, model=model, screenshot=True, @@ -620,3 +621,25 @@ async def test_stagehand_ai_methods_require_an_active_page( with pytest.raises(RuntimeError, match="no active page"): await stagehand.act("Click the link") + + +@pytest.mark.parametrize( + ("method", "positional"), + [ + ("act", ["instruction"]), + ("observe", ["instruction"]), + ("extract", ["instruction", "schema"]), + ], +) +def test_semantic_arguments_stay_positional(method: str, positional: list[str]) -> None: + """TS and Go take these positionally; Python must match, with options keyword-only.""" + parameters = list(inspect.signature(getattr(Stagehand, method)).parameters.values()) + assert [ + parameter.name + for parameter in parameters[1:] + if parameter.kind is inspect.Parameter.POSITIONAL_OR_KEYWORD + ] == positional + assert all( + parameter.kind is inspect.Parameter.KEYWORD_ONLY + for parameter in parameters[1 + len(positional) :] + )