From 52326c0e5b899c17fe05bd3721658478c4618c7f Mon Sep 17 00:00:00 2001 From: Alex Jean-Baptiste Jr Date: Fri, 19 Dec 2025 02:01:15 -0500 Subject: [PATCH] Fix metadata passing from dataset to prompts in init_function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running experiments via SDK, metadata from dataset records was not being passed through to prompt templates. This fix modifies init_function() to accept and extract metadata from the hooks parameter when called as a task, and properly pass it to the invoke() call. The function now: - Accepts exactly 2 parameters (input, hooks) to match framework requirements - Extracts metadata from hooks.metadata when present - Passes metadata to invoke() for proper template substitution - Maintains backward compatibility for both task and scorer modes This ensures mustache template variables like {{metadata.fieldName}} are correctly rendered with dataset metadata values during SDK experiments. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- py/src/braintrust/functions/invoke.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/py/src/braintrust/functions/invoke.py b/py/src/braintrust/functions/invoke.py index 9bd0a41a8..e473870ee 100644 --- a/py/src/braintrust/functions/invoke.py +++ b/py/src/braintrust/functions/invoke.py @@ -211,13 +211,20 @@ def init_function(project_name: str, slug: str, version: Optional[str] = None): :return: A function that can be used as a task or scorer. """ - def f(*args: Any, **kwargs: Any) -> Any: - if len(args) > 0: - # Task. - return invoke(project_name=project_name, slug=slug, version=version, input=args[0]) + def f(input, hooks=None): + # When used as a task, hooks may be provided with metadata + # When used as a scorer, all args come via kwargs in the input dict + if hooks is not None and not isinstance(hooks, str): + # Task mode with hooks object + metadata = hooks.metadata if hasattr(hooks, 'metadata') else None + return invoke(project_name=project_name, slug=slug, version=version, input=input, metadata=metadata) + elif isinstance(input, dict) and ('output' in input or 'expected' in input or 'metadata' in input): + # Scorer mode - input is a dict with scorer args + metadata = input.get('metadata') + return invoke(project_name=project_name, slug=slug, version=version, input=input, metadata=metadata) else: - # Scorer. - return invoke(project_name=project_name, slug=slug, version=version, input=kwargs) + # Task mode without hooks (backward compatibility) or hooks is not actually hooks + return invoke(project_name=project_name, slug=slug, version=version, input=input) f.__name__ = f"init_function-{project_name}-{slug}-{version or 'latest'}" return f