AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Mercury Composable polyglot functions for Python — a lightweight Event-over-HTTP function host and client: write functions here, let the Java/Rust engines orchestrate them from Event Script flows and
개발 도구Python · JavaScriptGitHub @Accenture온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Python language pack for Intent-Driven Development, Composability and Active Knowledge Graph
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Mercury Composable — polyglot functions for Python
Write decoupled functions in Python and let Mercury Composable
engines (Java, and the official Rust port) orchestrate
them from Event Script flows and MiniGraph knowledge graphs — with no orchestration code in
Python at all.
This package is a deliberately lightweight wrapper of the Event-over-HTTP protocol:README 전문 보기 ↗Write decoupled functions in Python and let Mercury Composable engines (Java, and the official Rust port) orchestrate them from Event Script flows and MiniGraph knowledge graphs — with no orchestration code in Python at all.
This package is a deliberately lightweight wrapper of the Event-over-HTTP protocol:
POST /api/event) that dispatches incoming event envelopes to your
registered functions,PostOffice) to call functions on peer applications the same way,instances worker tasks, andotel.forwarding=true): the host's trace spans
exported over OTLP/HTTP to Dynatrace, Splunk or a collector — no SDK, no new dependency.Orchestration deliberately stays in the engines. Functions written here are addressed by
route name through the engines' declarative yaml.event.over.http map, so a flow or a
graph task calls a Python function exactly as if it were local.
Documentation: https://accenture.github.io/mercury-python/ — including the AI Agent Guide for deterministic function generation.
Status: v4.12.21 is on PyPI —
pip install mercury-composable. This repository was repurposed in August 2026 for the polyglot initiative. The legacy Mercury language-pack implementation remains in git history.
# app.py
from mercury_composable import AppException, Body, platform, preload
@preload(route="hello.python", instances=10)
def handle_event(headers: dict[str, str], body: Body):
if not isinstance(body, dict) or "text" not in body:
raise AppException(400, "missing 'text'")
return {"text": str(body["text"]).upper(), "language": "python"}
if __name__ == "__main__":
platform.run() # port from rest.server.port (default 8085)
Run it:
pip install mercury-composable
mercury-serve app.py -Drest.server.port=8086
Call it from a Mercury engine application with two configuration entries and no code —
application.properties:
yaml.event.over.http=classpath:/event-over-http.yaml
event-over-http.yaml:
event.http:
- route: 'hello.python'
target: 'http://127.0.0.1:8086/api/event'
Any Event Script task or MiniGraph graph.task node that names the route hello.python
now executes the Python function, with trace context carried end to end.
A handler receives the same two-part input as an engine TypedLambdaFunction —
(headers: dict[str, str], body: Body) — Body is any MsgPack value — and returns the reply body (or an EventEnvelope for full
control of status and reply headers). Both async def and plain def handlers are
first-class, because Python has two library ecosystems and a polyglot function must be
able to wrap either:
def — for the synchronous world: requests (one of the most popular HTTP
clients), NumPy/pandas and most ML inference stacks, database drivers. These handlers
run in a thread-pool executor, so a blocking call can never stall the event loop that
hosts every other function. This is the Python analog of the Java engine's virtual
threads: write sequential blocking-style code and the platform makes it safe.async def — for asyncio-native I/O and for composing sibling functions with
await po.request(...).The style is detected automatically (no flag to set), and trace context, instances,
envelopes and telemetry behave identically in both. Rule of thumb: wrapping a blocking
library → plain def; composing functions or async I/O → async def.
AppException(status, message) for intentional errors — it becomes the portable
error contract on the wire (envelope status + message), handled by the calling flow's
exception handler or the graph's error.* contract.get_trace() exposes trace_id / trace_path / cid; annotate_trace(k, v) sends an
annotation back on the reply envelope.trace_context(trace_id, trace_path)
establishes the context your PostOffice calls inherit — the node runWithTrace twin.PostOffice without an endpoint delivers through this application's own event bus —
the engines' semantics for an in-app po call:
private=True means exactly what it means in the engines: callable in-app only.
Local calls reach private and public routes alike; the HTTP host keeps answering 403
for private targets from the wire.instances is faithful: each route has one FIFO mailbox consumed by that many worker
tasks. RPC waits are bounded by timeout_ms (the standard 408 envelope on breach), and
a queued call whose caller already timed out is skipped, never wastefully executed.po.request_sync(...) / po.send_sync(...) run the
same call on the host loop while blocking only the handler's own worker thread — the
trace chain rides across the bridge unbroken. Calling the sync bridge from async code
is refused with a teaching error (await po.request(...) is the async way), and using
it outside a hosted function tells you to use asyncio.run(po.request(...)) instead.Local eventing is for simple leaf-side composition. Workflow processing belongs in Event Script and Knowledge Graph on the engines — that boundary is the architecture.
The same conventions as the engines, so a polyglot installation stays uniform:
| Key | Meaning | Default |
|---|---|---|
application.name | application identity in logs | application |
rest.server.port | Event API port | 8085 |
log.format | text, json (pretty-printed) or compact (single-line JSONL) | text |
log.level | log level (LOG_LEVEL env var wins) | INFO |
Configuration lives in the resources folder next to the application file, mirroring the
engines' classpath resources: resources/application.yml (or .yaml / .properties) beside
the file mercury-serve is given, or beside the script python app.py ran — never the working
directory, so the configuration does not depend on where the app is launched from — or an
explicit --config path; see
examples/demo-app/resources/application.yml for a worked
sample. Values support ${ENV_VAR:default} substitution. Runtime parameter overrides use the
same -D syntax as the Java engine and the Rust port — checked first on every read
(AppConfig.set(key, value) does the same programmatically, the f:setConfig analog):
mercury-serve app.py -Drest.server.port=8086 -Dlog.format=json
Log lines follow the Java reference engine's pattern for one-aggregation consistency:
2026-08-22 10:15:30.123 INFO my_app:42 - Loaded PUBLIC hello.python, instances=10
The host serves the engines' operational endpoints on the same port as /api/event, so
Kubernetes probes and dashboards treat a Python app exactly like a Java or Rust engine app:
| Endpoint | Purpose |
|---|---|
GET / | minimal index page linking the endpoints below |
GET /info | app identity, runtime, origin id, start time, uptime |
GET /info/routes | registered routes split by visibility, with instance counts |
GET /env | selected environment variables and configuration parameters |
GET /health | dependency health checks — UP (HTTP 200) or DOWN (HTTP 400) |
GET /livenessprobe | OK while the last health outcome was good, else HTTP 400 |
Configuration keys carry the engines' names: info.app.version, info.app.description,
show.env.variables and show.application.properties (opt-in lists — secrets are never
dumped wholesale), and mandatory.health.dependencies / optional.health.dependencies
(routes of health check functions; optional ones never change the overall status). A
health check function is a normal registered function — usually private — speaking the
engines' interface contract, called through the event bus:
@preload("demo.health", private=True)
async def health(headers: dict[str, str], _body: Body) -> Body:
if headers.get("type") == "info":
return {"service": "demo.service", "href": "http://127.0.0.1"}
return "demo.service is running fine" # a non-200 reply marks it down
JSON responses are pretty-printed — the engines' default-serializer presentation — and
unknown paths answer the engines' error shape
({"status": 404, "message": "Resource not found", "type": "error"}).
Kubernetes wiring: point livenessProbe at /livenessprobe and readinessProbe at
/health.
The codec implements the
Event Envelope Wire Format
(standard format) and is verified against the golden conformance vectors shared by the
Java and Rust engines (tests/vectors/vectors.json). The classic compact format is
detected and rejected with a teaching error — engines default to the standard format for
Event over HTTP.
Serialization notes: integers and floats follow MsgPack's natural widths (the same
long/integer care as the engines applies); timestamps travel as ISO-8601 UTC strings with
millisecond precision; binary payloads use MsgPack bin.
This package intentionally contains no orchestration: no flows, no graphs, no persistence, no pub/sub broadcast — those live in the engines. What it does carry is deliberately minimal: functions, a primitive in-process event bus (route mailboxes + workers, RPC and drop-n-forget — nothing more), and the minimalist foundation utilities, keeping Python fast to prototype with while the composable core guarantees the architecture.
uv venv .venv && uv pip install -e '.[dev]' # environment (uv-managed python)
.venv/bin/pytest -q # tests
uvx ruff check . # lint (config in pyproject.toml)
uvx basedpyright # type check (config in pyproject.toml)
PyCharm: use interpreter type uv pointing at the project .venv, and set
Settings → Tools → Python Integrated Tools → Package requirements file to
pyproject.toml so the requirements inspection reads [project.dependencies].
Apache 2.0 — see LICENSE.txt.