openliate 0.1.0__tar.gz
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.
- openliate-0.1.0/.gitignore +55 -0
- openliate-0.1.0/PKG-INFO +81 -0
- openliate-0.1.0/README.md +57 -0
- openliate-0.1.0/pyproject.toml +40 -0
- openliate-0.1.0/src/openliate/__init__.py +10 -0
- openliate-0.1.0/src/openliate/client.py +127 -0
- openliate-0.1.0/src/openliate/om.py +102 -0
- openliate-0.1.0/tests/test_om.py +81 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
.pnp
|
|
4
|
+
.pnp.js
|
|
5
|
+
|
|
6
|
+
# Environment variables
|
|
7
|
+
.env
|
|
8
|
+
.env.local
|
|
9
|
+
.env.development.local
|
|
10
|
+
.env.test.local
|
|
11
|
+
.env.production.local
|
|
12
|
+
.npmrc
|
|
13
|
+
|
|
14
|
+
# Build outputs
|
|
15
|
+
dist/
|
|
16
|
+
bin/
|
|
17
|
+
pkg/
|
|
18
|
+
build/
|
|
19
|
+
out/
|
|
20
|
+
*.exe
|
|
21
|
+
*.wasm
|
|
22
|
+
*.tsbuildinfo
|
|
23
|
+
|
|
24
|
+
# Runtime Agent Sessions & State
|
|
25
|
+
sessions/
|
|
26
|
+
.openliate/
|
|
27
|
+
|
|
28
|
+
# Python artifacts
|
|
29
|
+
__pycache__/
|
|
30
|
+
*.py[cod]
|
|
31
|
+
*$py.class
|
|
32
|
+
*.egg-info/
|
|
33
|
+
.pytest_cache/
|
|
34
|
+
|
|
35
|
+
# Fern docs local cache
|
|
36
|
+
.fern/
|
|
37
|
+
|
|
38
|
+
# Logs
|
|
39
|
+
npm-debug.log*
|
|
40
|
+
yarn-debug.log*
|
|
41
|
+
yarn-error.log*
|
|
42
|
+
bun.lockb
|
|
43
|
+
pnpm-debug.log*
|
|
44
|
+
|
|
45
|
+
# OS Files
|
|
46
|
+
.DS_Store
|
|
47
|
+
Thumbs.db
|
|
48
|
+
.neon
|
|
49
|
+
|
|
50
|
+
# Scratch & Local Probing Scripts
|
|
51
|
+
scripts/test-*
|
|
52
|
+
scripts/probe-*
|
|
53
|
+
scripts/inspect-*
|
|
54
|
+
scripts/create-*
|
|
55
|
+
*.local.*
|
openliate-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: openliate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Open Source Backend Layer for AI Agents — Built for Sovereign AI Agents From India to the World
|
|
5
|
+
Project-URL: Homepage, https://openliate.tech
|
|
6
|
+
Project-URL: Repository, https://github.com/openliate/openliate
|
|
7
|
+
Project-URL: Documentation, https://docs.openliate.tech
|
|
8
|
+
Project-URL: Issues, https://github.com/openliate/openliate/issues
|
|
9
|
+
Author-email: OpenLiate <vinod@openliate.tech>, Vinod Hatti <gitdevinod@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: agent,aum,autonomous-agents,liate,mcp,om,sarvamai,sovereign-ai
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Requires-Dist: httpx>=0.24.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# OpenLiate — Python SDK
|
|
26
|
+
|
|
27
|
+
### Sovereign AI Agents in 5 Lines: Class is an Agent.
|
|
28
|
+
`L[LM] · I[ntegration] · A[gent] · T[ools] · E[nvironment]`
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install openliate
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quickstart (`agent.py`)
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from openliate import liate
|
|
44
|
+
|
|
45
|
+
class HelloAgent(liate):
|
|
46
|
+
L = "sarvam/sarvam-105b"
|
|
47
|
+
I = {"memory": "sessions/hello-agent"}
|
|
48
|
+
A = {"name": "hello_agent", "intent": "Autonomous Assistant"}
|
|
49
|
+
T = ["fetch"]
|
|
50
|
+
E = {"SARVAM_API_KEY": "$SARVAM_API_KEY"}
|
|
51
|
+
|
|
52
|
+
agent = HelloAgent()
|
|
53
|
+
|
|
54
|
+
# 1. Inspect declarative AUM manifest
|
|
55
|
+
print(agent.to_manifest())
|
|
56
|
+
|
|
57
|
+
# 2. Run agent via OpenLiate engine
|
|
58
|
+
result = agent.run("Namaste world!")
|
|
59
|
+
print(result.response)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Architecture: AUM & OM
|
|
65
|
+
|
|
66
|
+
Every agent declares the 5 orthogonal layers according to the **Agent Unified Manifest (AUM)** standard:
|
|
67
|
+
|
|
68
|
+
- **`L` (Model):** Sovereign LLM provider and model (e.g., Sarvam 105B).
|
|
69
|
+
- **`I` (Integration):** Memory retention, Postgres, and knowledge repositories.
|
|
70
|
+
- **`A` (Agent / Harness):** Agent name, intent, and reasoning loop.
|
|
71
|
+
- **`T` (Tools):** Anthropic Model Context Protocol (MCP) and custom tools.
|
|
72
|
+
- **`E` (Environment):** Secrets and guardrails.
|
|
73
|
+
|
|
74
|
+
Execution is powered by the **Orchestration Module (OM)** connecting locally or to deployed cloud endpoints.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT © [OpenLiate](https://openliate.tech)
|
|
81
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# OpenLiate — Python SDK
|
|
2
|
+
|
|
3
|
+
### Sovereign AI Agents in 5 Lines: Class is an Agent.
|
|
4
|
+
`L[LM] · I[ntegration] · A[gent] · T[ools] · E[nvironment]`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install openliate
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quickstart (`agent.py`)
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from openliate import liate
|
|
20
|
+
|
|
21
|
+
class HelloAgent(liate):
|
|
22
|
+
L = "sarvam/sarvam-105b"
|
|
23
|
+
I = {"memory": "sessions/hello-agent"}
|
|
24
|
+
A = {"name": "hello_agent", "intent": "Autonomous Assistant"}
|
|
25
|
+
T = ["fetch"]
|
|
26
|
+
E = {"SARVAM_API_KEY": "$SARVAM_API_KEY"}
|
|
27
|
+
|
|
28
|
+
agent = HelloAgent()
|
|
29
|
+
|
|
30
|
+
# 1. Inspect declarative AUM manifest
|
|
31
|
+
print(agent.to_manifest())
|
|
32
|
+
|
|
33
|
+
# 2. Run agent via OpenLiate engine
|
|
34
|
+
result = agent.run("Namaste world!")
|
|
35
|
+
print(result.response)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Architecture: AUM & OM
|
|
41
|
+
|
|
42
|
+
Every agent declares the 5 orthogonal layers according to the **Agent Unified Manifest (AUM)** standard:
|
|
43
|
+
|
|
44
|
+
- **`L` (Model):** Sovereign LLM provider and model (e.g., Sarvam 105B).
|
|
45
|
+
- **`I` (Integration):** Memory retention, Postgres, and knowledge repositories.
|
|
46
|
+
- **`A` (Agent / Harness):** Agent name, intent, and reasoning loop.
|
|
47
|
+
- **`T` (Tools):** Anthropic Model Context Protocol (MCP) and custom tools.
|
|
48
|
+
- **`E` (Environment):** Secrets and guardrails.
|
|
49
|
+
|
|
50
|
+
Execution is powered by the **Orchestration Module (OM)** connecting locally or to deployed cloud endpoints.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT © [OpenLiate](https://openliate.tech)
|
|
57
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "openliate"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Open Source Backend Layer for AI Agents — Built for Sovereign AI Agents From India to the World"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "OpenLiate", email = "vinod@openliate.tech" },
|
|
14
|
+
{ name = "Vinod Hatti", email = "gitdevinod@gmail.com" }
|
|
15
|
+
]
|
|
16
|
+
keywords = ["liate", "agent", "autonomous-agents", "sovereign-ai", "mcp", "sarvamai", "aum", "om"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"httpx>=0.24.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://openliate.tech"
|
|
34
|
+
Repository = "https://github.com/openliate/openliate"
|
|
35
|
+
Documentation = "https://docs.openliate.tech"
|
|
36
|
+
Issues = "https://github.com/openliate/openliate/issues"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/openliate"]
|
|
40
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenLiate Python SDK — Built for Sovereign AI Agents From India to the World
|
|
3
|
+
Class is an Agent: 1 Class = 5 Properties (L · I · A · T · E)
|
|
4
|
+
"""
|
|
5
|
+
from .om import liate
|
|
6
|
+
from .client import LapiClient, AgentRunResult
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
__all__ = ["liate", "LapiClient", "AgentRunResult"]
|
|
10
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenLiate Python LAPI Client
|
|
3
|
+
Connects to OpenLiate Orchestration Module (OM) via standard LAPI /run protocol.
|
|
4
|
+
"""
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
import json
|
|
8
|
+
import urllib.request
|
|
9
|
+
import urllib.error
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class AgentRunResult:
|
|
14
|
+
"""
|
|
15
|
+
Standard OpenLiate execution response object.
|
|
16
|
+
"""
|
|
17
|
+
response: str
|
|
18
|
+
steps: List[Dict[str, Any]] = field(default_factory=list)
|
|
19
|
+
execution_time_ms: float = 0.0
|
|
20
|
+
session_id: Optional[str] = None
|
|
21
|
+
agent: Optional[str] = None
|
|
22
|
+
raw: Dict[str, Any] = field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
return self.response
|
|
26
|
+
|
|
27
|
+
class LapiClient:
|
|
28
|
+
"""
|
|
29
|
+
HTTP client for communicating with OpenLiate LAPI endpoint.
|
|
30
|
+
Supports both standard library urllib (zero dependencies) and httpx (async).
|
|
31
|
+
"""
|
|
32
|
+
def __init__(self, endpoint: str = "http://localhost:7071"):
|
|
33
|
+
self.endpoint = endpoint.rstrip("/")
|
|
34
|
+
|
|
35
|
+
def run(self, manifest: Dict[str, Any], prompt: str, session_id: Optional[str] = None) -> AgentRunResult:
|
|
36
|
+
"""
|
|
37
|
+
Synchronous run via standard urllib.
|
|
38
|
+
"""
|
|
39
|
+
url = f"{self.endpoint}/run"
|
|
40
|
+
payload = {
|
|
41
|
+
"manifest": manifest,
|
|
42
|
+
"prompt": prompt
|
|
43
|
+
}
|
|
44
|
+
if session_id:
|
|
45
|
+
payload["sessionId"] = session_id
|
|
46
|
+
|
|
47
|
+
data = json.dumps(payload).encode("utf-8")
|
|
48
|
+
req = urllib.request.Request(
|
|
49
|
+
url,
|
|
50
|
+
data=data,
|
|
51
|
+
headers={"Content-Type": "application/json"}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
start_time = time.time()
|
|
55
|
+
try:
|
|
56
|
+
with urllib.request.urlopen(req, timeout=120) as resp:
|
|
57
|
+
status = resp.status
|
|
58
|
+
body = json.loads(resp.read().decode("utf-8"))
|
|
59
|
+
except urllib.error.HTTPError as e:
|
|
60
|
+
err_body = e.read().decode("utf-8")
|
|
61
|
+
try:
|
|
62
|
+
err_json = json.loads(err_body)
|
|
63
|
+
err_msg = err_json.get("error", err_body)
|
|
64
|
+
except Exception:
|
|
65
|
+
err_msg = err_body
|
|
66
|
+
raise RuntimeError(f"[OpenLiate LAPI Error HTTP {e.code}]: {err_msg}") from e
|
|
67
|
+
except urllib.error.URLError as e:
|
|
68
|
+
raise ConnectionError(
|
|
69
|
+
f"[OpenLiate Connection Error]: Unable to reach LAPI engine at {self.endpoint}. "
|
|
70
|
+
f"Ensure the OpenLiate engine is running (e.g. `openliate serve` or deployed URL)."
|
|
71
|
+
) from e
|
|
72
|
+
|
|
73
|
+
duration_ms = (time.time() - start_time) * 1000.0
|
|
74
|
+
|
|
75
|
+
return AgentRunResult(
|
|
76
|
+
response=body.get("text", body.get("response", body.get("output", ""))),
|
|
77
|
+
steps=body.get("steps", []),
|
|
78
|
+
execution_time_ms=body.get("latencyMs", body.get("executionTimeMs", duration_ms)),
|
|
79
|
+
session_id=body.get("sessionId", session_id),
|
|
80
|
+
agent=body.get("agent", manifest.get("A", {}).get("name", "agent")),
|
|
81
|
+
raw=body
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
async def arun(self, manifest: Dict[str, Any], prompt: str, session_id: Optional[str] = None) -> AgentRunResult:
|
|
85
|
+
"""
|
|
86
|
+
Asynchronous run via httpx.
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
import httpx
|
|
90
|
+
except ImportError:
|
|
91
|
+
raise ImportError(
|
|
92
|
+
"httpx is required for asynchronous arun(). Install with: pip install httpx"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
url = f"{self.endpoint}/run"
|
|
96
|
+
payload = {
|
|
97
|
+
"manifest": manifest,
|
|
98
|
+
"prompt": prompt
|
|
99
|
+
}
|
|
100
|
+
if session_id:
|
|
101
|
+
payload["sessionId"] = session_id
|
|
102
|
+
|
|
103
|
+
start_time = time.time()
|
|
104
|
+
async with httpx.AsyncClient(timeout=120.0) as client:
|
|
105
|
+
try:
|
|
106
|
+
resp = await client.post(url, json=payload)
|
|
107
|
+
resp.raise_for_status()
|
|
108
|
+
body = resp.json()
|
|
109
|
+
except httpx.HTTPStatusError as e:
|
|
110
|
+
raise RuntimeError(f"[OpenLiate LAPI Error HTTP {e.response.status_code}]: {e.response.text}") from e
|
|
111
|
+
except httpx.RequestError as e:
|
|
112
|
+
raise ConnectionError(
|
|
113
|
+
f"[OpenLiate Connection Error]: Unable to reach LAPI engine at {self.endpoint}. "
|
|
114
|
+
f"Ensure OpenLiate is running (`openliate serve` or cloud endpoint)."
|
|
115
|
+
) from e
|
|
116
|
+
|
|
117
|
+
duration_ms = (time.time() - start_time) * 1000.0
|
|
118
|
+
|
|
119
|
+
return AgentRunResult(
|
|
120
|
+
response=body.get("text", body.get("response", body.get("output", ""))),
|
|
121
|
+
steps=body.get("steps", []),
|
|
122
|
+
execution_time_ms=body.get("latencyMs", body.get("executionTimeMs", duration_ms)),
|
|
123
|
+
session_id=body.get("sessionId", session_id),
|
|
124
|
+
agent=body.get("agent", manifest.get("A", {}).get("name", "agent")),
|
|
125
|
+
raw=body
|
|
126
|
+
)
|
|
127
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core Engine: OM (Orchestration Module)
|
|
3
|
+
Matches AUM (Agent Unified Manifest) specification across 5 orthogonal layers:
|
|
4
|
+
L[LM] · I[ntegration] · A[gent] · T[ools] · E[nvironment]
|
|
5
|
+
"""
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
import os
|
|
8
|
+
from .client import LapiClient, AgentRunResult
|
|
9
|
+
|
|
10
|
+
class liate:
|
|
11
|
+
"""
|
|
12
|
+
OM (Orchestration Module) — Python OOP Base Class for AI Agents.
|
|
13
|
+
Supports pure LIATE authoring across 3 styles:
|
|
14
|
+
1. Shorthand: L · I · A · T · E
|
|
15
|
+
2. Full Name: LLM · Integration · Agent · Tools · Environment
|
|
16
|
+
3. Lowercase: llm · integration · agent · tools · environment
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
```python
|
|
20
|
+
from openliate import liate
|
|
21
|
+
|
|
22
|
+
class HelloAgent(liate):
|
|
23
|
+
LLM = "sarvam/sarvam-105b"
|
|
24
|
+
Integration = {"memory": "sessions/hello-agent"}
|
|
25
|
+
Agent = {"name": "hello_agent"}
|
|
26
|
+
Tools = ["fetch"]
|
|
27
|
+
Environment = {"SARVAM_API_KEY": "$SARVAM_API_KEY"}
|
|
28
|
+
|
|
29
|
+
agent = HelloAgent()
|
|
30
|
+
result = agent.run("Namaste world!")
|
|
31
|
+
print(result)
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
# 1. Shorthand
|
|
35
|
+
L: Optional[Union[str, Dict[str, Any]]] = None
|
|
36
|
+
I: Optional[Dict[str, Any]] = None
|
|
37
|
+
A: Optional[Union[str, Dict[str, Any]]] = None
|
|
38
|
+
T: Optional[List[Any]] = None
|
|
39
|
+
E: Optional[Dict[str, str]] = None
|
|
40
|
+
|
|
41
|
+
# 2. Full Name
|
|
42
|
+
LLM: Optional[Union[str, Dict[str, Any]]] = None
|
|
43
|
+
Integration: Optional[Dict[str, Any]] = None
|
|
44
|
+
Agent: Optional[Union[str, Dict[str, Any]]] = None
|
|
45
|
+
Tools: Optional[List[Any]] = None
|
|
46
|
+
Environment: Optional[Dict[str, str]] = None
|
|
47
|
+
|
|
48
|
+
# 3. Lowercase
|
|
49
|
+
llm: Optional[Union[str, Dict[str, Any]]] = None
|
|
50
|
+
integration: Optional[Dict[str, Any]] = None
|
|
51
|
+
agent: Optional[Union[str, Dict[str, Any]]] = None
|
|
52
|
+
tools: Optional[List[Any]] = None
|
|
53
|
+
environment: Optional[Dict[str, str]] = None
|
|
54
|
+
|
|
55
|
+
def __init__(self, endpoint: Optional[str] = None):
|
|
56
|
+
self._endpoint = endpoint or os.environ.get("OPENLIATE_ENDPOINT", "http://localhost:7071")
|
|
57
|
+
self._client = LapiClient(endpoint=self._endpoint)
|
|
58
|
+
|
|
59
|
+
def to_manifest(self) -> Dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Exports the declarative AUM (Agent Unified Manifest) dictionary.
|
|
62
|
+
"""
|
|
63
|
+
l_val = self.L if self.L is not None else (self.LLM if self.LLM is not None else self.llm)
|
|
64
|
+
i_val = self.I if self.I is not None else (self.Integration if self.Integration is not None else self.integration)
|
|
65
|
+
a_val = self.A if self.A is not None else (self.Agent if self.Agent is not None else self.agent)
|
|
66
|
+
t_val = self.T if self.T is not None else (self.Tools if self.Tools is not None else self.tools)
|
|
67
|
+
e_val = self.E if self.E is not None else (self.Environment if self.Environment is not None else self.environment)
|
|
68
|
+
|
|
69
|
+
if not l_val:
|
|
70
|
+
raise ValueError(
|
|
71
|
+
f"[OpenLiate Error]: Missing required Layer [L] (LLM) in class '{self.__class__.__name__}'. "
|
|
72
|
+
f"Declare 'L', 'LLM', or 'llm' on your class. "
|
|
73
|
+
f"OpenLiate never hardcodes or falls back to silent model defaults."
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
name = self.__class__.__name__
|
|
77
|
+
agent_a = a_val or {"name": name}
|
|
78
|
+
if isinstance(agent_a, str):
|
|
79
|
+
agent_a = {"name": agent_a}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
"L": l_val,
|
|
83
|
+
"I": i_val or {},
|
|
84
|
+
"A": agent_a,
|
|
85
|
+
"T": t_val or [],
|
|
86
|
+
"E": e_val or {}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def run(self, prompt: str, session_id: Optional[str] = None) -> AgentRunResult:
|
|
90
|
+
"""
|
|
91
|
+
Executes the agent via OpenLiate LAPI.
|
|
92
|
+
"""
|
|
93
|
+
manifest = self.to_manifest()
|
|
94
|
+
return self._client.run(manifest=manifest, prompt=prompt, session_id=session_id)
|
|
95
|
+
|
|
96
|
+
async def arun(self, prompt: str, session_id: Optional[str] = None) -> AgentRunResult:
|
|
97
|
+
"""
|
|
98
|
+
Asynchronously executes the agent via OpenLiate LAPI.
|
|
99
|
+
"""
|
|
100
|
+
manifest = self.to_manifest()
|
|
101
|
+
return await self._client.arun(manifest=manifest, prompt=prompt, session_id=session_id)
|
|
102
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Add src to sys.path
|
|
6
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
|
|
7
|
+
|
|
8
|
+
from openliate import liate, AgentRunResult
|
|
9
|
+
|
|
10
|
+
class TestOpenLiatePythonSDK(unittest.TestCase):
|
|
11
|
+
def test_class_is_an_agent_5_properties(self):
|
|
12
|
+
class GreetingAgent(liate):
|
|
13
|
+
L = "sarvam/sarvam-105b"
|
|
14
|
+
I = {"memory": "sessions/test-python"}
|
|
15
|
+
A = {"name": "greeting_agent", "intent": "Friendly assistant"}
|
|
16
|
+
T = ["fetch"]
|
|
17
|
+
E = {"SARVAM_API_KEY": "test_key_python"}
|
|
18
|
+
|
|
19
|
+
agent = GreetingAgent()
|
|
20
|
+
manifest = agent.to_manifest()
|
|
21
|
+
|
|
22
|
+
self.assertEqual(manifest["L"], "sarvam/sarvam-105b")
|
|
23
|
+
self.assertEqual(manifest["I"], {"memory": "sessions/test-python"})
|
|
24
|
+
self.assertEqual(manifest["A"]["name"], "greeting_agent")
|
|
25
|
+
self.assertEqual(manifest["A"]["intent"], "Friendly assistant")
|
|
26
|
+
self.assertEqual(manifest["T"], ["fetch"])
|
|
27
|
+
self.assertEqual(manifest["E"]["SARVAM_API_KEY"], "test_key_python")
|
|
28
|
+
|
|
29
|
+
def test_strict_layer_l_enforcement(self):
|
|
30
|
+
class IncompleteAgent(liate):
|
|
31
|
+
A = {"name": "no_model"}
|
|
32
|
+
|
|
33
|
+
agent = IncompleteAgent()
|
|
34
|
+
with self.assertRaises(ValueError) as ctx:
|
|
35
|
+
agent.to_manifest()
|
|
36
|
+
self.assertIn("Missing required Layer [L]", str(ctx.exception))
|
|
37
|
+
|
|
38
|
+
def test_full_name_liate_properties(self):
|
|
39
|
+
class FullNameAgent(liate):
|
|
40
|
+
LLM = "sarvam/sarvam-105b"
|
|
41
|
+
Integration = {"memory": "sessions/python-full"}
|
|
42
|
+
Agent = {"name": "full_python_agent"}
|
|
43
|
+
Tools = ["fetch"]
|
|
44
|
+
Environment = {"SARVAM_API_KEY": "py_key"}
|
|
45
|
+
|
|
46
|
+
agent = FullNameAgent()
|
|
47
|
+
manifest = agent.to_manifest()
|
|
48
|
+
self.assertEqual(manifest["L"], "sarvam/sarvam-105b")
|
|
49
|
+
self.assertEqual(manifest["I"]["memory"], "sessions/python-full")
|
|
50
|
+
self.assertEqual(manifest["A"]["name"], "full_python_agent")
|
|
51
|
+
self.assertEqual(manifest["T"], ["fetch"])
|
|
52
|
+
|
|
53
|
+
def test_lowercase_liate_properties(self):
|
|
54
|
+
class LowercaseAgent(liate):
|
|
55
|
+
llm = "sarvam/sarvam-105b"
|
|
56
|
+
integration = {"memory": "sessions/python-lower"}
|
|
57
|
+
agent = {"name": "lower_python_agent"}
|
|
58
|
+
tools = ["fetch"]
|
|
59
|
+
environment = {"SARVAM_API_KEY": "py_key"}
|
|
60
|
+
|
|
61
|
+
agent = LowercaseAgent()
|
|
62
|
+
manifest = agent.to_manifest()
|
|
63
|
+
self.assertEqual(manifest["L"], "sarvam/sarvam-105b")
|
|
64
|
+
self.assertEqual(manifest["I"]["memory"], "sessions/python-lower")
|
|
65
|
+
self.assertEqual(manifest["A"]["name"], "lower_python_agent")
|
|
66
|
+
self.assertEqual(manifest["T"], ["fetch"])
|
|
67
|
+
|
|
68
|
+
def test_agent_run_result_dataclass(self):
|
|
69
|
+
res = AgentRunResult(
|
|
70
|
+
response="Hello world",
|
|
71
|
+
steps=[{"thought": "test"}],
|
|
72
|
+
execution_time_ms=12.5,
|
|
73
|
+
session_id="session-123"
|
|
74
|
+
)
|
|
75
|
+
self.assertEqual(str(res), "Hello world")
|
|
76
|
+
self.assertEqual(res.execution_time_ms, 12.5)
|
|
77
|
+
self.assertEqual(res.session_id, "session-123")
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
unittest.main()
|
|
81
|
+
|