Metadata-Version: 2.5
Name: anlyon-langchain
Version: 0.3.1
Summary: LangChain integration for Anlyon: actions as tools, and chains and agents traced as Anlyon runs
Project-URL: Homepage, https://anlyon.com
Project-URL: Documentation, https://docs.anlyon.com
Project-URL: Repository, https://github.com/AnlyonHQ/anlyon-platform
Project-URL: Issues, https://github.com/AnlyonHQ/anlyon-platform/issues
Author-email: Anlyon <support@anlyon.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agent-actions,ai-agents,anlyon,langchain,observability,runs,sdk,tools,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: anlyon>=0.5.0
Requires-Dist: langchain-core>=1.6.6
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Description-Content-Type: text/markdown

# anlyon-langchain

LangChain integration for [Anlyon](https://anlyon.com). `action_tools` turns Anlyon actions into LangChain tools. `AnlyonTracer` records a chain or agent invocation as an Anlyon run with nested spans.

## Actions as tools

```python
from anlyon import Client
from anlyon_langchain import action_tools

client = Client(api_key="anlyon_live_...")

# Declare once, from an operator key. This makes the action governed.
client.actions.declare(
    "send-email",
    impact={"dimension": "emails", "amount": "count(input.to)", "bound": "exact"},
    verify={"url": "https://api.example.com/v1/messages/{{response.id}}", "status": 200},
)

tools = action_tools(client)  # one tool per enabled action
send_email = next(tool for tool in tools if tool.name == "send-email")

print(send_email.description)
# Sends an email. Declared impact: emails. Each call counts toward any shared limit set for this environment.

result = send_email.invoke({"to": ["a@example.com"], "subject": "Hi"})
print(result["grade"])  # "confirmed", "acknowledged", "unknown", "failed", "refused", "denied" or "pending"
```

Each tool calls `client.actions.invoke()`. Anlyon holds the credential, evaluates policy and makes the call. A tool your own code calls directly is not routed through Anlyon and is not governed by it. The description carries the declared impact when the action declares one. It says what one call counts. It does not say a limit is configured. The result is the invocation as a dict. `grade` is the receipt grade of a governed action, and `None` for an action that is not governed. A gated action comes back with `pendingApproval` and an `approvalId`.

Pass `names=[...]` to keep a subset. Bind the tools to a model with `model.bind_tools(tools)`.

## Trace a LangChain invocation

```python
from anlyon import Client
from anlyon_langchain import AnlyonTracer

client = Client(api_key="anlyon_live_...")
tracer = AnlyonTracer(client, application="support-agent")

# Pass the callback to any LangChain runnable/agent invocation.
result = chain.invoke({"question": "Where is my order?"}, config={"callbacks": [tracer]})
```

The handler creates one Anlyon run for the root callback and parent-linked
`workflow_step`, `model_call`, and `tool_call` spans for nested callbacks. It is
best-effort: Anlyon transport failures never change the application result.

## Installation

```bash
pip install anlyon-langchain
```

See the [Anlyon docs](https://docs.anlyon.com) for the full guide.

## License

MIT

Earlier namespaces remain available through the API for existing workspaces. See the [billing docs](https://docs.anlyon.com/account/billing).
