diff --git a/langchain-paid-agent-py/.env.example b/langchain-paid-agent-py/.env.example index 26e58f9..4e38170 100644 --- a/langchain-paid-agent-py/.env.example +++ b/langchain-paid-agent-py/.env.example @@ -20,3 +20,22 @@ OPENAI_API_KEY=sk-your-openai-key # Optional query override. # QUERY=What's the market insight on electric vehicles? + +# --- Observability (optional) ------------------------------------------- +# Uncomment the LANGSMITH_* vars below to send traces to LangSmith. With +# tracing enabled, `@requires_payment` automatically emits dedicated +# `nvm:verify` and `nvm:settlement` child spans nested under the tool +# span, carrying nvm.* attributes (credits_redeemed, tx_hash, balance, +# duration_ms, …). Get an API key at https://smith.langchain.com +# → Settings → API keys. Requires `payments-py[langsmith]`. +# LANGSMITH_TRACING=true +# LANGSMITH_API_KEY=lsv2_pt_your_key +# LANGSMITH_PROJECT=nvm-langchain-sprint-1 +# Region-dependent endpoint — only needed if your LangSmith account is +# NOT in GCP US (the default). 403 Forbidden on /runs/multipart means +# you're hitting the wrong region. +# GCP US (default): https://api.smith.langchain.com +# GCP EU: https://eu.api.smith.langchain.com +# GCP APAC: https://apac.api.smith.langchain.com +# AWS US: https://aws.api.smith.langchain.com +# LANGSMITH_ENDPOINT=https://eu.api.smith.langchain.com diff --git a/langchain-paid-agent-py/README.md b/langchain-paid-agent-py/README.md index bde2428..97ca79a 100644 --- a/langchain-paid-agent-py/README.md +++ b/langchain-paid-agent-py/README.md @@ -107,6 +107,54 @@ Expected output (truncated): payer: 0x... ``` +## Observability with LangSmith (optional) + +The tutorial works as-is without any observability, but every paid tool call can also surface as structured spans in [LangSmith](https://smith.langchain.com) — no code changes required. + +### 1. Install with the LangSmith extra + +The pyproject already pulls in `payments-py[langchain,langsmith]`, so a fresh `poetry install` is all that's needed. The `[langsmith]` extra adds the `langsmith` Python package and activates the span-emission bridge inside `@requires_payment`. + +### 2. Enable tracing + +In your `.env`, uncomment the LangSmith block (see [`.env.example`](./.env.example)): + +```bash +LANGSMITH_TRACING=true +LANGSMITH_API_KEY=lsv2_pt_your-key +LANGSMITH_PROJECT=nvm-langchain-sprint-1 +# Only needed if your LangSmith account is NOT in GCP US: +# LANGSMITH_ENDPOINT=https://eu.api.smith.langchain.com +``` + +Get an API key at https://smith.langchain.com → Settings → API keys. Pick the matching `LANGSMITH_ENDPOINT` if your account isn't on GCP US — without it, the SDK posts to the wrong region and you'll see `403 Forbidden` on `/runs/multipart` (the payment flow still succeeds; only the trace upload fails). + +### 3. Re-run + +```bash +poetry run buyer +``` + +### 4. What you should see + +Open the trace in the LangSmith UI. Under the tool span you'll find two dedicated Nevermined child spans: + +```text +LangGraph +└── tools + └── get_market_insight + ├── nvm:verify 0.28s ← around payments.facilitator.verify_permissions + └── nvm:settlement 1.88s ← around payments.facilitator.settle_permissions +``` + +Each carries `nvm.*` metadata: `nvm.plan_ids`, `nvm.scheme`, `nvm.payer`, `nvm.payment_token` (abbreviated), `nvm.credits_redeemed`, `nvm.tx_hash`, `nvm.balance.after`, `nvm.network`, `nvm.verify.duration_ms`, `nvm.settle.duration_ms`. The same metadata is also attached to the parent tool span so cmd-F finds it from either level. + +The **failed discovery probe** (the first invocation without a token) also produces an `nvm:verify` span — marked failed by the raised `PaymentRequiredError`, but carrying the static `nvm.plan_ids` / `nvm.scheme` / `nvm.network`. So in the LangSmith UI it's still filterable as "verify failure for plan X", not an opaque LangChain crash. + +### Privacy note + +The full x402 access token the buyer passes through `config["configurable"]["payment_token"]` is normally captured by LangChain into the parent tool span's metadata. `@requires_payment` proactively strips it before opening any `nvm:*` span, so the full credential never reaches a Nevermined-emitted attribute. Only an abbreviated `nvm.payment_token` (``) remains, for correlation purposes. For blanket coverage across other channels (custom callbacks, tool args, etc.), set `LANGSMITH_HIDE_INPUTS=true`. + ## Code walkthrough ### Seller: protect the tool (`src/agent.py`) diff --git a/langchain-paid-agent-py/pyproject.toml b/langchain-paid-agent-py/pyproject.toml index f4b4494..ed74a24 100644 --- a/langchain-paid-agent-py/pyproject.toml +++ b/langchain-paid-agent-py/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-paid-agent-py" -version = "1.0.0" +version = "1.1.0" description = "Minimal LangChain agent with a Nevermined-protected tool" authors = ["Nevermined "] license = "MIT" @@ -13,7 +13,7 @@ python-dotenv = "^1.0.0" langchain-core = "^0.3.0" langchain-openai = "^0.3.0" langgraph = "^0.6.0" -payments-py = {version = "^1.7.0", extras = ["langchain"]} +payments-py = {version = "^1.8.0", extras = ["langchain", "langsmith"]} [tool.poetry.scripts] buyer = "src.buyer:main"