fix(prompts): a keyword-only argument is advertised as one everywhere

The general Python extractor dropped the bare `*` the same way the datatable one
did, so every keyword-only signature it emits — `datatable`, `task` and the rest
— told an agent to pass those arguments positionally, which is a TypeError.
Regenerated: the script prompt, the Python skill and the CLI guidance carry the
separator now.

The fork dialog says both outcomes where the permission check did not answer:
what the backend does with the data table is decided by the config, so a label
promising the original is kept is a promise it cannot make.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S5arH3G2Sa1Qqm32veJQ1n
This commit is contained in:
Diego Imbert
2026-09-04 16:59:07 +02:00
co-authored by Claude Opus 5
parent b1474820b5
commit 8a40ff46fd
7 changed files with 33 additions and 26 deletions
+5 -5
View File
@@ -4410,7 +4410,7 @@ def send_teams_message(conversation_id: str, text: str, success: bool = True, ca
#
# Returns:
# DataTableClient instance
def datatable(name: str = 'main', role: Optional[str] = None)
def datatable(name: str = 'main', *, role: Optional[str] = None)
# Get a DuckLake client for DuckDB queries.
#
@@ -4601,7 +4601,7 @@ def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
#
# @task(path="f/external_script", timeout=600, tag="gpu")
# async def run_external(x: int): ...
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task(_func = None, *, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill script.
#
@@ -4612,7 +4612,7 @@ def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, ti
# @workflow
# async def main():
# data = await extract(url="https://...")
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_script(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill flow.
#
@@ -4623,7 +4623,7 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
# @workflow
# async def main():
# result = await pipeline(input=data)
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_flow(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Decorator marking an async function as a workflow-as-code entry point.
#
@@ -4684,7 +4684,7 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_
# ...
#
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
async def parallel(items, fn, *, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
@@ -216,9 +216,12 @@
items={[
{
value: 'keep_original',
// What the backend does is decided by the config, not by this
// label, so where the check did not answer the label says both
// outcomes rather than promising the one it cannot know.
label:
dt.permissioned === undefined
? 'Keep original (permissions unknown)'
? 'Keep original unless permissioned (check failed)'
: dt.permissioned
? 'Not shared (permissions enabled)'
: 'Keep original'
+5 -5
View File
@@ -2373,7 +2373,7 @@ def send_teams_message(conversation_id: str, text: str, success: bool = True, ca
#
# Returns:
# DataTableClient instance
def datatable(name: str = 'main', role: Optional[str] = None)
def datatable(name: str = 'main', *, role: Optional[str] = None)
# Get a DuckLake client for DuckDB queries.
#
@@ -2564,7 +2564,7 @@ def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
#
# @task(path="f/external_script", timeout=600, tag="gpu")
# async def run_external(x: int): ...
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task(_func = None, *, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill script.
#
@@ -2575,7 +2575,7 @@ def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, ti
# @workflow
# async def main():
# data = await extract(url="https://...")
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_script(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill flow.
#
@@ -2586,7 +2586,7 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
# @workflow
# async def main():
# result = await pipeline(input=data)
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_flow(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Decorator marking an async function as a workflow-as-code entry point.
#
@@ -2647,7 +2647,7 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_
# ...
#
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
async def parallel(items, fn, *, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
+5 -5
View File
@@ -2530,7 +2530,7 @@ def send_teams_message(conversation_id: str, text: str, success: bool = True, ca
#
# Returns:
# DataTableClient instance
def datatable(name: str = 'main', role: Optional[str] = None)
def datatable(name: str = 'main', *, role: Optional[str] = None)
# Get a DuckLake client for DuckDB queries.
#
@@ -2721,7 +2721,7 @@ def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
#
# @task(path="f/external_script", timeout=600, tag="gpu")
# async def run_external(x: int): ...
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task(_func = None, *, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill script.
#
@@ -2732,7 +2732,7 @@ def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, ti
# @workflow
# async def main():
# data = await extract(url="https://...")
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_script(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill flow.
#
@@ -2743,7 +2743,7 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
# @workflow
# async def main():
# result = await pipeline(input=data)
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_flow(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Decorator marking an async function as a workflow-as-code entry point.
#
@@ -2804,7 +2804,7 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_
# ...
#
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
async def parallel(items, fn, *, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
+5 -5
View File
@@ -474,7 +474,7 @@ def send_teams_message(conversation_id: str, text: str, success: bool = True, ca
#
# Returns:
# DataTableClient instance
def datatable(name: str = 'main', role: Optional[str] = None)
def datatable(name: str = 'main', *, role: Optional[str] = None)
# Get a DuckLake client for DuckDB queries.
#
@@ -665,7 +665,7 @@ def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
#
# @task(path="f/external_script", timeout=600, tag="gpu")
# async def run_external(x: int): ...
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task(_func = None, *, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill script.
#
@@ -676,7 +676,7 @@ def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, ti
# @workflow
# async def main():
# data = await extract(url="https://...")
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_script(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill flow.
#
@@ -687,7 +687,7 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
# @workflow
# async def main():
# result = await pipeline(input=data)
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_flow(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Decorator marking an async function as a workflow-as-code entry point.
#
@@ -748,7 +748,7 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_
# ...
#
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
async def parallel(items, fn, *, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
@@ -659,7 +659,7 @@ def send_teams_message(conversation_id: str, text: str, success: bool = True, ca
#
# Returns:
# DataTableClient instance
def datatable(name: str = 'main', role: Optional[str] = None)
def datatable(name: str = 'main', *, role: Optional[str] = None)
# Get a DuckLake client for DuckDB queries.
#
@@ -850,7 +850,7 @@ def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
#
# @task(path="f/external_script", timeout=600, tag="gpu")
# async def run_external(x: int): ...
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task(_func = None, *, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill script.
#
@@ -861,7 +861,7 @@ def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, ti
# @workflow
# async def main():
# data = await extract(url="https://...")
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_script(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Create a task that dispatches to a separate Windmill flow.
#
@@ -872,7 +872,7 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
# @workflow
# async def main():
# result = await pipeline(input=data)
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
def task_flow(path: str, *, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
# Decorator marking an async function as a workflow-as-code entry point.
#
@@ -933,7 +933,7 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_
# ...
#
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
async def parallel(items, fn, *, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
+4
View File
@@ -222,6 +222,10 @@ def extract_py_functions(content: str) -> list[dict]:
# Handle *args
if args.vararg:
params.append(f"*{args.vararg.arg}")
elif args.kwonlyargs:
# The bare separator is part of the signature: without it the advertised
# call is positional, and an agent following it gets a TypeError.
params.append('*')
# Handle keyword-only args
for i, arg in enumerate(args.kwonlyargs):