actuent 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- actuent/__init__.py +207 -0
- actuent/langchain.py +44 -0
- actuent/llama_index.py +27 -0
- actuent-0.2.0.dist-info/METADATA +87 -0
- actuent-0.2.0.dist-info/RECORD +8 -0
- actuent-0.2.0.dist-info/WHEEL +5 -0
- actuent-0.2.0.dist-info/licenses/LICENSE +9 -0
- actuent-0.2.0.dist-info/top_level.txt +1 -0
actuent/__init__.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Actuent — the search engine for AI agents.
|
|
2
|
+
|
|
3
|
+
from actuent import Actuent
|
|
4
|
+
client = Actuent() # free tier, or Actuent(api_key="ak_...") for Pro
|
|
5
|
+
results = client.search("barber amsterdam")
|
|
6
|
+
shoes = client.search("running shoes under €100")["products"]
|
|
7
|
+
evening = client.plan("Nørreport, Copenhagen", stops=["dinner", "drinks"])
|
|
8
|
+
fade = client.find_service("skin fade under €30", location="Amsterdam")
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
import urllib.error
|
|
14
|
+
import urllib.parse
|
|
15
|
+
import urllib.request
|
|
16
|
+
from typing import Any, Dict, Optional
|
|
17
|
+
|
|
18
|
+
__version__ = "0.2.0"
|
|
19
|
+
__all__ = ["Actuent", "ActuentError", "RateLimitError"]
|
|
20
|
+
|
|
21
|
+
_USER_AGENT = f"actuent-python/{__version__}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ActuentError(Exception):
|
|
25
|
+
"""An error response from Actuent."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, message: str, status: Optional[int] = None, body: Any = None):
|
|
28
|
+
super().__init__(message)
|
|
29
|
+
self.status = status
|
|
30
|
+
self.body = body
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RateLimitError(ActuentError):
|
|
34
|
+
"""Too many requests. `retry_after` is the number of seconds to wait."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, message: str, retry_after: Optional[int] = None, body: Any = None):
|
|
37
|
+
super().__init__(message, 429, body)
|
|
38
|
+
self.retry_after = retry_after
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Actuent:
|
|
42
|
+
"""Client for the Actuent API (https://docs.actuent.ai).
|
|
43
|
+
|
|
44
|
+
api_key: optional Pro key from actuent.ai. Defaults to the ACTUENT_API_KEY environment variable.
|
|
45
|
+
Without a key you get the free tier (20 requests/minute).
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, api_key: Optional[str] = None, base_url: str = "https://api.actuent.ai",
|
|
49
|
+
agents_url: str = "https://agents.actuent.ai", timeout: float = 60.0):
|
|
50
|
+
self.api_key = api_key if api_key is not None else os.environ.get("ACTUENT_API_KEY")
|
|
51
|
+
self.base_url = base_url.rstrip("/")
|
|
52
|
+
self.agents_url = agents_url.rstrip("/")
|
|
53
|
+
self.timeout = timeout
|
|
54
|
+
self.rate_limit: Dict[str, Optional[int]] = {}
|
|
55
|
+
|
|
56
|
+
def _request(self, method: str, url: str, body: Optional[Dict[str, Any]] = None) -> Any:
|
|
57
|
+
headers = {"Accept": "application/json", "User-Agent": _USER_AGENT}
|
|
58
|
+
data = None
|
|
59
|
+
if body is not None:
|
|
60
|
+
data = json.dumps(body).encode("utf-8")
|
|
61
|
+
headers["Content-Type"] = "application/json"
|
|
62
|
+
if self.api_key:
|
|
63
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
64
|
+
request = urllib.request.Request(url, data=data, headers=headers, method=method)
|
|
65
|
+
try:
|
|
66
|
+
with urllib.request.urlopen(request, timeout=self.timeout) as response:
|
|
67
|
+
self._remember_limits(response.headers)
|
|
68
|
+
return json.loads(response.read().decode("utf-8") or "null")
|
|
69
|
+
except urllib.error.HTTPError as error:
|
|
70
|
+
self._remember_limits(error.headers)
|
|
71
|
+
try:
|
|
72
|
+
payload = json.loads(error.read().decode("utf-8") or "null")
|
|
73
|
+
except ValueError:
|
|
74
|
+
payload = None
|
|
75
|
+
message = (payload or {}).get("error") or (payload or {}).get("message") or f"HTTP {error.code}"
|
|
76
|
+
if error.code == 429:
|
|
77
|
+
retry = error.headers.get("Retry-After")
|
|
78
|
+
raise RateLimitError(message, int(retry) if retry and retry.isdigit() else None, payload) from None
|
|
79
|
+
raise ActuentError(message, error.code, payload) from None
|
|
80
|
+
|
|
81
|
+
def _remember_limits(self, headers: Any) -> None:
|
|
82
|
+
def number(name: str) -> Optional[int]:
|
|
83
|
+
value = headers.get(name) if headers else None
|
|
84
|
+
return int(value) if value and str(value).isdigit() else None
|
|
85
|
+
self.rate_limit = {"limit": number("X-RateLimit-Limit"), "remaining": number("X-RateLimit-Remaining"),
|
|
86
|
+
"reset": number("X-RateLimit-Reset")}
|
|
87
|
+
|
|
88
|
+
def search(self, query: str) -> Dict[str, Any]:
|
|
89
|
+
"""Search by topic, domain or page, in any language. Returns {"results": [...LAWP], "products": [...]}.
|
|
90
|
+
|
|
91
|
+
Examples: "barber amsterdam", "nike.com", "stripe.com/pricing", "running shoes under €100".
|
|
92
|
+
"""
|
|
93
|
+
return self._request("GET", f"{self.base_url}/api/search?q={urllib.parse.quote(query)}")
|
|
94
|
+
|
|
95
|
+
def get_site(self, domain: str) -> Optional[Dict[str, Any]]:
|
|
96
|
+
"""The LAWP for one site (or None if Actuent can't find it)."""
|
|
97
|
+
results = self.search(domain).get("results") or []
|
|
98
|
+
return results[0] if results else None
|
|
99
|
+
|
|
100
|
+
def get_page(self, url: str) -> Optional[Dict[str, Any]]:
|
|
101
|
+
"""The LAWP for one page, e.g. "stripe.com/pricing"."""
|
|
102
|
+
return self.get_site(url)
|
|
103
|
+
|
|
104
|
+
def products(self, query: str) -> list:
|
|
105
|
+
"""Products with prices, e.g. "running shoes under €100"."""
|
|
106
|
+
return self.search(query).get("products") or []
|
|
107
|
+
|
|
108
|
+
def check_site(self, domain: str) -> Dict[str, Any]:
|
|
109
|
+
"""Validate a site's /.well-known/lawp.json and its action endpoints."""
|
|
110
|
+
return self._request("GET", f"{self.agents_url}/api/lawp-check?domain={urllib.parse.quote(domain)}")
|
|
111
|
+
|
|
112
|
+
def register(self, site: Dict[str, Any]) -> Dict[str, Any]:
|
|
113
|
+
"""List or update your own site's LAWP (Pro key, verified domain). See docs.actuent.ai/#sdk."""
|
|
114
|
+
return self._request("POST", f"{self.base_url}/api/register", site)
|
|
115
|
+
|
|
116
|
+
def state(self) -> Dict[str, Any]:
|
|
117
|
+
"""Live "State of the AI web" statistics."""
|
|
118
|
+
return self._request("GET", f"{self.base_url}/api/state")
|
|
119
|
+
|
|
120
|
+
# ----- Tools from the Actuent MCP server (the same ones ChatGPT and Claude use) -----
|
|
121
|
+
|
|
122
|
+
def _tool(self, name: str, arguments: Dict[str, Any]) -> Any:
|
|
123
|
+
args = {k: v for k, v in arguments.items() if v is not None}
|
|
124
|
+
reply = self._request("POST", f"{self.agents_url}/api/mcp",
|
|
125
|
+
{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": name, "arguments": args}})
|
|
126
|
+
if not isinstance(reply, dict) or "result" not in reply:
|
|
127
|
+
raise ActuentError((reply or {}).get("error", {}).get("message", "Unexpected response"), None, reply)
|
|
128
|
+
result = reply["result"]
|
|
129
|
+
text = "".join(part.get("text", "") for part in result.get("content", []) if part.get("type") == "text")
|
|
130
|
+
try:
|
|
131
|
+
data = json.loads(text)
|
|
132
|
+
except ValueError:
|
|
133
|
+
data = text
|
|
134
|
+
if result.get("isError"):
|
|
135
|
+
message = data.get("error") if isinstance(data, dict) else str(data)
|
|
136
|
+
raise ActuentError(message or f"{name} failed", None, data)
|
|
137
|
+
return data
|
|
138
|
+
|
|
139
|
+
def get_actions(self, domain: str) -> Dict[str, Any]:
|
|
140
|
+
"""A site's actions, whether each is executable, and the JSON Schema of each input."""
|
|
141
|
+
return self._tool("actuent_get_actions", {"domain": domain})
|
|
142
|
+
|
|
143
|
+
def ask_site(self, domain: str, question: str) -> Dict[str, Any]:
|
|
144
|
+
"""Answer a question from one site's own pages, e.g. ("nike.com", "free returns?")."""
|
|
145
|
+
return self._tool("actuent_ask_site", {"domain": domain, "question": question})
|
|
146
|
+
|
|
147
|
+
def nearby(self, query: str, location: str, radius_metres: Optional[int] = None, open_now: Optional[bool] = None,
|
|
148
|
+
filters: Optional[list] = None) -> Dict[str, Any]:
|
|
149
|
+
"""Places near a location. filters: vegan, vegetarian, gluten_free, wheelchair, outdoor_seating, wifi, kids, dogs."""
|
|
150
|
+
return self._tool("actuent_nearby", {"query": query, "location": location, "radius_metres": radius_metres,
|
|
151
|
+
"open_now": open_now, "filters": filters})
|
|
152
|
+
|
|
153
|
+
def find_service(self, query: str, location: Optional[str] = None, max_price: Optional[float] = None,
|
|
154
|
+
currency: Optional[str] = None) -> Dict[str, Any]:
|
|
155
|
+
"""A service or dish with its price at local businesses, e.g. "skin fade under €30"."""
|
|
156
|
+
return self._tool("actuent_find_service", {"query": query, "location": location, "max_price": max_price, "currency": currency})
|
|
157
|
+
|
|
158
|
+
def plan(self, location: str, stops: Optional[list] = None, date: Optional[str] = None, start_time: Optional[str] = None,
|
|
159
|
+
cuisine: Optional[str] = None, filters: Optional[list] = None) -> Dict[str, Any]:
|
|
160
|
+
"""A timed outing, e.g. stops=["dinner", "drinks"] from 19:00, with places open when you'd arrive."""
|
|
161
|
+
return self._tool("actuent_plan", {"location": location, "stops": stops, "date": date, "start_time": start_time,
|
|
162
|
+
"cuisine": cuisine, "filters": filters})
|
|
163
|
+
|
|
164
|
+
def trip(self, location: str, days: int = 2, start_date: Optional[str] = None, filters: Optional[list] = None) -> Dict[str, Any]:
|
|
165
|
+
"""A 1–4 day city trip: where to stay and a plan for each day."""
|
|
166
|
+
return self._tool("actuent_trip", {"location": location, "days": days, "start_date": start_date, "filters": filters})
|
|
167
|
+
|
|
168
|
+
def events(self, location: Optional[str] = None, query: Optional[str] = None, date_from: Optional[str] = None,
|
|
169
|
+
date_to: Optional[str] = None) -> Dict[str, Any]:
|
|
170
|
+
"""Upcoming events that websites publish, by city, topic and dates (YYYY-MM-DD)."""
|
|
171
|
+
return self._tool("actuent_events", {"location": location, "query": query, "from": date_from, "to": date_to})
|
|
172
|
+
|
|
173
|
+
def compare_sites(self, domains: list) -> Any:
|
|
174
|
+
"""Compare two or more sites side by side."""
|
|
175
|
+
return self._tool("actuent_compare", {"domains": domains})
|
|
176
|
+
|
|
177
|
+
def compare_products(self, urls: list) -> Dict[str, Any]:
|
|
178
|
+
"""Compare products by URL: price, stock, 90-day price range and cheaper shops."""
|
|
179
|
+
return self._tool("actuent_compare", {"products": urls})
|
|
180
|
+
|
|
181
|
+
def news(self, topic: str) -> Any:
|
|
182
|
+
"""Latest articles on a topic."""
|
|
183
|
+
return self._tool("actuent_news", {"topic": topic})
|
|
184
|
+
|
|
185
|
+
def watch_price(self, url: str, target_price_eur: Optional[float] = None, notify: str = "price",
|
|
186
|
+
webhook_url: Optional[str] = None) -> Dict[str, Any]:
|
|
187
|
+
"""(Pro) Get an email, and optionally a webhook, when a product's price drops or it's back in stock
|
|
188
|
+
(notify="price", "stock" or "both")."""
|
|
189
|
+
return self._tool("actuent_watch_price", {"url": url, "target_price_eur": target_price_eur, "notify": notify, "webhook_url": webhook_url})
|
|
190
|
+
|
|
191
|
+
def price_watches(self) -> Dict[str, Any]:
|
|
192
|
+
"""(Pro) Your price watches."""
|
|
193
|
+
return self._tool("actuent_watch_price", {"action": "list"})
|
|
194
|
+
|
|
195
|
+
def execute_action(self, domain: str, action_id: str, input: Any = None) -> Dict[str, Any]:
|
|
196
|
+
"""(Pro) Perform a site's action. Confirm with your user first."""
|
|
197
|
+
return self._tool("actuent_execute_action", {"domain": domain, "action_id": action_id, "input": input})
|
|
198
|
+
|
|
199
|
+
# ----- Scores and badges -----
|
|
200
|
+
|
|
201
|
+
def score(self, domain: str) -> Dict[str, Any]:
|
|
202
|
+
"""A site's agent-readiness score (0–100), label, category and checks."""
|
|
203
|
+
return self._request("GET", f"{self.base_url}/badge.json?domain={urllib.parse.quote(domain)}")
|
|
204
|
+
|
|
205
|
+
def leaderboard(self) -> Dict[str, Any]:
|
|
206
|
+
"""The 100 sites agents found most often this week."""
|
|
207
|
+
return self._request("GET", f"{self.base_url}/leaderboard")
|
actuent/langchain.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""LangChain tools for Actuent.
|
|
2
|
+
|
|
3
|
+
from actuent.langchain import get_tools
|
|
4
|
+
tools = get_tools() # or get_tools(api_key="ak_...")
|
|
5
|
+
agent = create_react_agent(llm, tools)
|
|
6
|
+
|
|
7
|
+
Requires: pip install "actuent[langchain]"
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from typing import List, Optional, Type
|
|
12
|
+
|
|
13
|
+
from langchain_core.tools import BaseTool
|
|
14
|
+
from pydantic import BaseModel, Field
|
|
15
|
+
|
|
16
|
+
from . import Actuent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _SearchInput(BaseModel):
|
|
20
|
+
query: str = Field(description="What to find: a topic ('barber amsterdam'), a domain ('nike.com'), "
|
|
21
|
+
"a page ('stripe.com/pricing') or a product search ('running shoes under €100').")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ActuentSearchTool(BaseTool):
|
|
25
|
+
"""Search the web as structured data with Actuent."""
|
|
26
|
+
|
|
27
|
+
name: str = "actuent_search"
|
|
28
|
+
description: str = (
|
|
29
|
+
"Search websites and products for the user. Returns each site's pages summarised in plain English, "
|
|
30
|
+
"the actions a visitor can take (book, contact, buy), and for shopping searches, products with prices. "
|
|
31
|
+
"Use it instead of browsing raw web pages. Works in any language; results are in English."
|
|
32
|
+
)
|
|
33
|
+
args_schema: Type[BaseModel] = _SearchInput
|
|
34
|
+
client: Actuent = Field(default_factory=Actuent, exclude=True)
|
|
35
|
+
|
|
36
|
+
model_config = {"arbitrary_types_allowed": True}
|
|
37
|
+
|
|
38
|
+
def _run(self, query: str, run_manager=None) -> str:
|
|
39
|
+
return json.dumps(self.client.search(query), ensure_ascii=False)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_tools(api_key: Optional[str] = None) -> List[BaseTool]:
|
|
43
|
+
"""Actuent tools for a LangChain agent."""
|
|
44
|
+
return [ActuentSearchTool(client=Actuent(api_key=api_key))]
|
actuent/llama_index.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""LlamaIndex tools for Actuent.
|
|
2
|
+
|
|
3
|
+
from actuent.llama_index import get_tools
|
|
4
|
+
agent = ReActAgent.from_tools(get_tools(), llm=llm)
|
|
5
|
+
|
|
6
|
+
Requires: pip install "actuent[llamaindex]"
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from typing import List, Optional
|
|
11
|
+
|
|
12
|
+
from llama_index.core.tools import FunctionTool
|
|
13
|
+
|
|
14
|
+
from . import Actuent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_tools(api_key: Optional[str] = None) -> List[FunctionTool]:
|
|
18
|
+
"""Actuent tools for a LlamaIndex agent."""
|
|
19
|
+
client = Actuent(api_key=api_key)
|
|
20
|
+
|
|
21
|
+
def actuent_search(query: str) -> str:
|
|
22
|
+
"""Search websites and products. Returns each site's pages in plain English, the actions a visitor
|
|
23
|
+
can take (book, contact, buy), and for shopping searches, products with prices. Accepts a topic,
|
|
24
|
+
domain, page (domain/path) or product search like 'running shoes under €100'."""
|
|
25
|
+
return json.dumps(client.search(query), ensure_ascii=False)
|
|
26
|
+
|
|
27
|
+
return [FunctionTool.from_defaults(fn=actuent_search)]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: actuent
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK for Actuent — the search engine for AI agents. Websites and products as structured LAWP, plus LangChain and LlamaIndex tools.
|
|
5
|
+
Author-email: localilabs <support@localilabs.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://actuent.ai
|
|
8
|
+
Project-URL: Documentation, https://docs.actuent.ai
|
|
9
|
+
Project-URL: Source, https://github.com/localilabs/actuent-python
|
|
10
|
+
Keywords: ai,agents,search,lawp,mcp,langchain,llamaindex
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Provides-Extra: langchain
|
|
18
|
+
Requires-Dist: langchain-core>=0.2; extra == "langchain"
|
|
19
|
+
Provides-Extra: llamaindex
|
|
20
|
+
Requires-Dist: llama-index-core>=0.10; extra == "llamaindex"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Actuent for Python
|
|
24
|
+
|
|
25
|
+
Search the web as structured data. [Actuent](https://actuent.ai) is a search engine for AI agents: it returns websites as **LAWP** (clean JSON with each site's pages and the actions a visitor can take) and products with prices, instead of raw HTML.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install actuent
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from actuent import Actuent
|
|
33
|
+
|
|
34
|
+
client = Actuent() # free tier; Actuent(api_key="ak_...") for Pro
|
|
35
|
+
site = client.get_site("stripe.com") # pages + actions for one site
|
|
36
|
+
results = client.search("barber amsterdam")["results"]
|
|
37
|
+
shoes = client.products("running shoes under €100") # products with prices, in English
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Searches work in any language and always come back in English. Free: 20 requests/minute. Pro keys from [actuent.ai](https://actuent.ai): full results and 60/minute. Rate-limit info is in `client.rate_limit`; a `RateLimitError` has `retry_after`.
|
|
41
|
+
|
|
42
|
+
## LangChain
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install "actuent[langchain]"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from actuent.langchain import get_tools
|
|
50
|
+
tools = get_tools() # [ActuentSearchTool]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Plans, services and more (0.2)
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
client.plan("Nørreport, Copenhagen", stops=["dinner", "drinks"], start_time="19:00")
|
|
58
|
+
client.trip("Lisbon", days=3)
|
|
59
|
+
client.find_service("skin fade under €30", location="Amsterdam")
|
|
60
|
+
client.nearby("cafe", "Jordaan, Amsterdam", filters=["vegan", "wifi"], open_now=True)
|
|
61
|
+
client.events(location="Copenhagen", query="jazz")
|
|
62
|
+
client.ask_site("nike.com", "free returns?")
|
|
63
|
+
client.compare_products([url_a, url_b])
|
|
64
|
+
client.score("yoursite.com") # agent-readiness 0–100
|
|
65
|
+
client.watch_price(url, notify="both") # Pro: price drops and back in stock
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## LlamaIndex
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install "actuent[llamaindex]"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from actuent.llama_index import get_tools
|
|
76
|
+
tools = get_tools() # [FunctionTool actuent_search]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## More
|
|
80
|
+
|
|
81
|
+
- `client.check_site("yoursite.com")`: validate your `/.well-known/lawp.json` and action endpoints
|
|
82
|
+
- `client.register({...})`: list your own site (Pro, verified domain)
|
|
83
|
+
- `client.state()`: live "State of the AI web" numbers
|
|
84
|
+
|
|
85
|
+
Docs: [docs.actuent.ai](https://docs.actuent.ai) · MCP server for Claude and ChatGPT: `https://agents.actuent.ai/api/mcp`
|
|
86
|
+
|
|
87
|
+
Made by [localilabs](https://localilabs.com). MIT licensed.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
actuent/__init__.py,sha256=Cy7WFUyfmquhytq8Sq1OBUHaavUvDomSfHbIKk_rkRE,10979
|
|
2
|
+
actuent/langchain.py,sha256=YaBuGH4nY_4_dZDYpBMTpnRskCV5yUC8pO8wFioGcao,1611
|
|
3
|
+
actuent/llama_index.py,sha256=nAYN1EQzjPrYfMvN_YQgHc9Wit6jWQ7CODFV9CCRmKA,935
|
|
4
|
+
actuent-0.2.0.dist-info/licenses/LICENSE,sha256=L4f2H9noHi5v96HErbbs_vfIyTCFL3-Bh5j1_ffVE0g,1067
|
|
5
|
+
actuent-0.2.0.dist-info/METADATA,sha256=LrjubqdBioKqZw7y-Y_clOcIkL0CNrmdwu4IRYj83Kg,3202
|
|
6
|
+
actuent-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
7
|
+
actuent-0.2.0.dist-info/top_level.txt,sha256=ATBdStNCgEYObRjMxY6lZKYD01Hbp2W7K5wDU74-1po,8
|
|
8
|
+
actuent-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 localilabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
actuent
|