Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
found and `AppConfig.resources_dir` names the folder; the startup log reports `Configuration: <path>`.
**Upgrade note:** an application that kept `resources/` in the working directory with its application file elsewhere
passes `--config`, or moves the folder next to the file.
2. **The LLM helper graduates from an example to an extension: `extensions/llm-helper/`.** It is no longer a sample to copy
but a function host an installation runs to give its engines an LLM, so it moves out of `examples/`, which keeps the
demo app. The files, the routes, the contract and the configuration keys are unchanged; the sdist ships the new folder.
**Upgrade note:** start it as `mercury-serve extensions/llm-helper/llm_helper.py` (or
`python extensions/llm-helper/llm_helper.py`); a script or a deployment that names the old path changes it.

## Version 4.12.21, 10/7/2026

Expand Down
4 changes: 2 additions & 2 deletions docs/test-reports/llm-helper-certification.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ keywords: [llm helper, llm.chat, llm.stream, claude, anthropic, streaming, certi
pairs, the three layers, the progressive-rendering evidence and the findings — is the
[engine report](https://accenture.github.io/mercury-composable/test-reports/llm-helper-certification/), which the
Rust engine's docs carry too. The helper is
[`examples/llm-helper`](https://github.com/Accenture/mercury-python/tree/main/examples/llm-helper); its README holds the contract.*
[`extensions/llm-helper`](https://github.com/Accenture/mercury-python/tree/main/extensions/llm-helper); its README holds the contract.*

## Verified without a credential

Expand Down Expand Up @@ -100,7 +100,7 @@ model generation. The full account of the surfaces and the gates is Finding 7 of
pip install -e '.[dev]'
pytest tests/test_llm_helper.py # token-free
export ANTHROPIC_API_KEY=... # live: the credential reaches the helper only
mercury-serve examples/llm-helper/llm_helper.py -Dlog.format=compact -Dllm.log.batches=true
mercury-serve extensions/llm-helper/llm_helper.py -Dlog.format=compact -Dllm.log.batches=true
```

The commands for the engines, the deploy folder and the `curl` calls for each layer are in the
Expand Down
4 changes: 2 additions & 2 deletions examples/demo-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The minimal polyglot function host: seven small functions that show what a Mercury engine can reach
over Event-over-HTTP and what a function host does with a call. Run it to watch a Python function
answer an engine, and copy it as the starting point for your own app. It never calls a model and needs
no credential; the LLM routes are a separate app, [`llm-helper`](../llm-helper/README.md).
no credential; the LLM routes are a separate app, [`llm-helper`](../../extensions/llm-helper/README.md).

```text
caller ── REST ──> Java or Rust engine ── Event-over-HTTP ──> demo app
Expand All @@ -26,7 +26,7 @@ Either way the app reads `resources/application.yml` next to `demo_app.py`, whic
command runs from.

The app listens on port 8086 (`rest.server.port` in `resources/application.yml`; `-Drest.server.port=8090`
overrides it). The [LLM helper](../llm-helper/README.md) defaults to 8086 as well, so give one of the two
overrides it). The [LLM helper](../../extensions/llm-helper/README.md) defaults to 8086 as well, so give one of the two
another port when you run both on one machine. Map a route from the engine's `event-over-http.yaml`:

```yaml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ speaks the same contract. Both run one shared vector file, so they cannot drift
```bash
pip install 'mercury-composable[llm]' # the SDK is this app's one dependency
export ANTHROPIC_API_KEY=... # from the environment, never from a config file
mercury-serve examples/llm-helper/llm_helper.py
python examples/llm-helper/llm_helper.py # the same without mercury-serve
mercury-serve extensions/llm-helper/llm_helper.py
python extensions/llm-helper/llm_helper.py # the same without mercury-serve
```

Either way the helper reads `resources/application.yml` next to `llm_helper.py`, whichever directory the
Expand All @@ -33,15 +33,15 @@ AWS credential chain, and a region is required:
```bash
pip install 'mercury-composable[llm,bedrock]'
export AWS_REGION=us-east-1 # or llm.aws.region; the AWS credential chain signs each call
mercury-serve examples/llm-helper/llm_helper.py -Dllm.backend=bedrock
mercury-serve extensions/llm-helper/llm_helper.py -Dllm.backend=bedrock
```

If the account is enabled for Bedrock's classic runtime and not for its Anthropic-shaped endpoint (the default
surface answers `403 ... not available for this account` on a model the console's playground runs), switch the
surface and name the model as an inference profile id, exactly as the account lists it:

```bash
mercury-serve examples/llm-helper/llm_helper.py -Dllm.backend=bedrock -Dllm.aws.api=runtime \
mercury-serve extensions/llm-helper/llm_helper.py -Dllm.backend=bedrock -Dllm.aws.api=runtime \
-Dllm.model=us.anthropic.claude-haiku-4-5-20251001-v1:0
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
control flow while the LLM advises within it.

Run: pip install 'mercury-composable[llm]'
mercury-serve examples/llm-helper/llm_helper.py
mercury-serve extensions/llm-helper/llm_helper.py

The credential comes from the environment, never from a config file: ANTHROPIC_API_KEY for
the Claude API, the AWS credential chain (or AWS_BEARER_TOKEN_BEDROCK) for AWS Bedrock.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# resources folder next to the application file (this one), never from the working directory.
# Any key can be overridden at
# run time with the engines' -D syntax, e.g.:
# mercury-serve examples/llm-helper/llm_helper.py -Dllm.model=claude-haiku-4-5
# mercury-serve extensions/llm-helper/llm_helper.py -Dllm.model=claude-haiku-4-5

application.name: 'llm-helper'
info.app.description: 'Mercury Composable LLM helper (llm.chat / llm.stream on the Anthropic SDK)'
Expand Down
5 changes: 3 additions & 2 deletions memory/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ the engines by design. The legacy pre-composable language pack lives in git hist
`cli.py` (`mercury-serve`); `py.typed` ships type information.
- `tests/` — pytest suite; `tests/vectors/vectors.json` holds the **golden conformance
vectors shared with the Java and Rust engines** (the wire-compatibility proof).
- `examples/demo-app/demo_app.py` — the minimal runnable function app (README and `resources/` beside it);
`examples/llm-helper/llm_helper.py` — the LLM helper app (`llm.chat`, `llm.stream`, `llm.health` on the Anthropic SDK).
- `examples/demo-app/demo_app.py` — the minimal runnable function app (README and `resources/` beside it).
- `extensions/llm-helper/llm_helper.py` — the LLM helper (`llm.chat`, `llm.stream`, `llm.health` on the
Anthropic SDK), graduated from `examples/` to an extension on 2026-11-02 (Eric).
- Root `README.md` — the consumer-facing guide (quick start, function contract,
configuration, wire compatibility); the root `AGENTS.md` fork routes consumers there.

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Repository = "https://github.com/Accenture/mercury-python"
Changelog = "https://github.com/Accenture/mercury-python/blob/main/CHANGELOG.md"

[project.optional-dependencies]
# the LLM helper app (examples/llm-helper) - the package itself stays SDK-free
# the LLM helper (extensions/llm-helper) - the package itself stays SDK-free
llm = ["anthropic>=1,<2"]
# AWS Bedrock as the helper's backend (llm.backend: bedrock) - boto3 signs each call with the
# AWS credential chain; the Claude API install stays lean without it
Expand All @@ -58,6 +58,7 @@ only-include = [
"src/mercury_composable",
"tests",
"examples",
"extensions",
"README.md",
"CHANGELOG.md",
"LICENSE.txt",
Expand All @@ -81,7 +82,7 @@ extend-select = ["I"]
# by agent-memory and excluded.
typeCheckingMode = "standard"
reportMissingParameterType = "error"
include = ["src", "examples", "tests"]
include = ["src", "examples", "extensions", "tests"]
exclude = ["agent-skills", ".venv"]

[tool.pytest.ini_options]
Expand Down
1 change: 1 addition & 0 deletions system/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ wrapper's docs cover only the Python function surface.
|------|------|
| `src/` | the `mercury_composable` package — Event API host, `PostOffice`, envelope codec, actuators |
| `examples/` | runnable reference functions |
| `extensions/` | function hosts that add a capability to an installation — the LLM helper (`llm.chat`, `llm.stream`) |
| `docs/` | the MkDocs guide site source |
| `tests/` | unit and integration tests |

Expand Down
4 changes: 2 additions & 2 deletions tests/test_llm_helper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""The LLM helper (examples/llm-helper/llm_helper.py) - token-free.
"""The LLM helper (extensions/llm-helper/llm_helper.py) - token-free.

One shared contract file, tests/vectors/llm-helper-vectors.json (byte-identical in
mercury-nodejs), drives every case below against a fake of the Anthropic SDK: the exact SDK
Expand Down Expand Up @@ -29,7 +29,7 @@
from mercury_composable import AppException

_TESTS = Path(__file__).resolve().parent
_HELPER = _TESTS.parent / "examples" / "llm-helper" / "llm_helper.py"
_HELPER = _TESTS.parent / "extensions" / "llm-helper" / "llm_helper.py"
_VECTORS = _TESTS / "vectors" / "llm-helper-vectors.json"
# the Node.js twin pins the same digest: change the file in both packs or in neither
_VECTORS_SHA256 = "7bfffbf36c52488c246f250f36afc4e8012f119fd56c93e9de1cbe93bf5988b6"
Expand Down
Loading