Metadata-Version: 2.4
Name: hep-llm-helpers
Version: 1.0.0
Summary: Reusable helpers for HEP large-language-model generated analysis code.
Project-URL: Homepage, https://github.com/iris-hep/hep-llm-helpers
Project-URL: Source, https://github.com/iris-hep/hep-llm-helpers
Project-URL: Issues, https://github.com/iris-hep/hep-llm-helpers/issues
Author: IRIS-HEP
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.11
Requires-Dist: func-adl>=3.0
Description-Content-Type: text/markdown

# hep-llm-helpers

Small reusable helpers for HEP analysis code generated with large language models.

## Install

```bash
python -m pip install hep-llm-helpers
```

The xAOD helper module is imported as:

```python
from hep_llm_helpers.xaod_hints import make_a_tool, make_tool_accessor
```

## xAOD tool example

`make_a_tool` adds the C++ tool initialization metadata to a `func_adl` query and
returns a `ToolInfo` handle. Pass that handle to `make_tool_accessor` to expose a
tool operation as a Python function that can be used inside a query. The accessor's
`source_code` is C++ and must assign its result to the variable named `result`.

Here is a complete ATLAS PHYSLITE b-tagging example. It configures the
`BTaggingSelectionTool` at the `FixedCutBEff_77` operating point and returns both a
tag decision and a tag weight:

```python
from func_adl_servicex_xaodr25 import FuncADLQueryPHYSLITE
from func_adl_servicex_xaodr25.xAOD.jet_v1 import Jet_v1

from hep_llm_helpers.xaod_hints import make_a_tool, make_tool_accessor

base_query = FuncADLQueryPHYSLITE()

# The tool name must be unique if a query uses more than one tool instance.
query_with_tool, tag_tool = make_a_tool(
    base_query,
    tool_name="btag_tool",
    tool_type="BTaggingSelectionTool",
    include_files=["xAODBTaggingEfficiency/BTaggingSelectionTool.h"],
    link_libraries=["xAODBTaggingEfficiencyLib"],
    init_lines=[
        'ANA_CHECK(asg::setProperty({tool_name}, "OperatingPoint", "FixedCutBEff_77"));',
        "ANA_CHECK({tool_name}->initialize());",
    ],
)

jet_is_tagged = make_tool_accessor(
    tag_tool,
    function_name="jet_is_tagged",
    source_code=[
        "result = static_cast<bool>({tool_name}->accept(*jet));",
    ],
    arguments=[("jet", Jet_v1)],
    return_type_cpp="bool",
    return_type_python="bool",
)

tag_weight = make_tool_accessor(
    tag_tool,
    function_name="tag_weight",
    source_code=[
        "ANA_CHECK({tool_name}->getTaggerWeight(*jet, result, false));",
    ],
    arguments=[("jet", Jet_v1)],
    return_type_cpp="double",
    return_type_python="float",
)

# Continue building the query from query_with_tool, not base_query, so the
# injected tool metadata is retained during ServiceX translation.
query = query_with_tool.Select(
    lambda event: {
        "jet_is_tagged": event.Jets().Select(lambda jet: jet_is_tagged(jet)),
        "tag_weight": event.Jets().Select(lambda jet: tag_weight(jet)),
    }
)
```

The same pattern applies to other xAOD tools: initialize the tool once with
`make_a_tool`, create one or more accessors from its `ToolInfo`, and call those
accessors only in the query derived from the returned query object. Use a different
`tool_name` for each independently configured tool instance.

## Development

This project uses Hatch:

```bash
hatch run test:run
hatch build
```

The local Hatch environments derive a development version from Git automatically. A
release build derives the package version from the GitHub release tag.

## Releases

Create a draft GitHub release with a tag such as `v0.1.0`, then publish the release.
The `release.yml` workflow builds the distributions and publishes them to PyPI using
GitHub OIDC trusted publishing. The repository must have a protected `pypi` environment
and a matching PyPI trusted publisher configuration before the first release.
