Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install .
- run: python -c "import aingle_sdk; print(aingle_sdk.__version__)"
- run: python -m py_compile src/aingle_sdk/*.py
149 changes: 85 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# AIngle SDK for Python

Official Python SDK for [AIngle](https://apilium.com) - the ultra-light distributed ledger for IoT devices.
Python SDK for [AIngle](https://apilium.com), the verifiable memory cortex for
AI agents. AIngle Cortex is a semantic graph plus vector memory served over a
REST API, so your agents can remember, recall, and reason over durable,
queryable knowledge.

## Installation

Expand All @@ -11,104 +14,122 @@ pip install aingle-sdk
## Quick Start

```python
import asyncio
from aingle_sdk import AIngleClient

async def main():
async with AIngleClient(node_url="http://localhost:8080") as client:
# Create an entry
hash = await client.create_entry({
"type": "sensor_reading",
"value": 23.5,
"unit": "celsius",
})
print(f"Created entry: {hash}")

# Retrieve an entry
entry = await client.get_entry(hash)
print(entry)

# Get node info
info = await client.get_node_info()
print(f"Node version: {info.version}")

asyncio.run(main())
client = AIngleClient() # defaults to http://127.0.0.1:19090

# Remember a note.
saved = client.remember(
"note",
{"text": "Ada prefers dark roast coffee"},
tags=["preference"],
importance=0.7,
)
print("stored id:", saved.id)

# Recall it later by semantic text.
hits = client.recall(text="what coffee does Ada like?", limit=5)
for hit in hits:
print(hit.relevance, hit.data)
```

## Subscribe to Real-time Updates
## Configuration

| Parameter | Type | Default | Description |
|------------|-----------------|-----------------------------|--------------------------------------|
| `base_url` | `str` | `http://127.0.0.1:19090` | AIngle Cortex base URL. |
| `token` | `str` or `None` | `None` | Optional bearer token for a namespace. |
| `timeout` | `float` | `30.0` | Request timeout in seconds. |

Pass a token when a namespace requires authentication:

```python
import asyncio
from aingle_sdk import AIngleClient
client = AIngleClient(base_url="https://cortex.example.com", token="my-token")
```

## API Reference

All methods are synchronous and raise `AIngleError(status, message)` on any
non-2xx response.

### Health and stats

async def main():
client = AIngleClient()
await client.connect()
| Method | Description |
|------------------|----------------------------------------|
| `health()` | Service health and component status. |
| `stats()` | Graph and server statistics. |

def on_entry(entry):
print(f"New entry: {entry.hash}")
### Memory

unsubscribe = await client.subscribe(on_entry)
| Method | Description |
|---------------------------------------------------------|------------------------------------------|
| `remember(entry_type, data, *, tags, importance, embedding)` | Store a memory, returns `{ id }`. |
| `recall(*, text, tags, entry_type, min_importance, limit)` | Recall memories by text or tags. |
| `search(*, embedding, k, min_similarity, entry_type, tags)` | Vector / semantic search. |
| `memory_stats()` | Short and long term memory counts. |
| `forget(id)` | Delete a memory by id. |

# Keep running for 60 seconds
await asyncio.sleep(60)
### Triples (semantic graph)

unsubscribe()
await client.disconnect()
The triple `object` is an untagged value: `str`, `int`, `float`, `bool`, or a
node reference `{"node": "http://example.org/thing"}`. Use the `node_ref`
helper to build a node reference.

asyncio.run(main())
```python
from aingle_sdk import node_ref

client.create_triple("ada", "likes", "coffee")
client.create_triple("ada", "knows", node_ref("http://example.org/grace"))
```

## API Reference
| Method | Description |
|--------------------------------------------------------------|-----------------------------------|
| `create_triple(subject, predicate, object)` | Insert one triple. |
| `list_triples(*, subject, predicate, object, limit, offset)` | List triples with filters. |
| `get_triple(id)` | Fetch a triple by id. |
| `delete_triple(id)` | Delete a triple by id. |

### Query

### AIngleClient
| Method | Description |
|-------------------------------------------------|--------------------------------------|
| `query(*, subject, predicate, object, limit)` | Pattern match over triples. |
| `subjects(*, predicate, limit)` | Distinct subjects, optional filter. |
| `predicates(*, subject, limit)` | Distinct predicates, optional filter. |

| Method | Description |
|--------|-------------|
| `connect()` | Connect to the AIngle node |
| `disconnect()` | Disconnect from the node |
| `create_entry(data)` | Create a new entry |
| `get_entry(hash)` | Retrieve an entry by hash |
| `get_node_info()` | Get node information |
| `subscribe(callback)` | Subscribe to real-time updates |
## Error handling

### Configuration
```python
from aingle_sdk import AIngleClient, AIngleError

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `node_url` | `str` | `http://localhost:8080` | Node URL |
| `ws_url` | `str` | `ws://localhost:8081` | WebSocket URL |
| `timeout` | `float` | `30.0` | Request timeout (seconds) |
| `debug` | `bool` | `False` | Enable debug logging |
client = AIngleClient()
try:
client.get_triple("does-not-exist")
except AIngleError as err:
print(err.status, err.message)
```

## Development

```bash
# Install dev dependencies
# Install dev dependencies.
pip install -e ".[dev]"

# Run tests
# Run tests.
pytest

# Run tests with coverage
pytest --cov=aingle_sdk

# Type checking
# Type checking.
mypy src

# Linting
# Linting.
ruff check src

# Format code
black src
```

## License

Apache-2.0 - see [LICENSE](LICENSE)
Apache-2.0, see [LICENSE](LICENSE).

## Links

- [AIngle Core](https://github.com/ApiliumCode/aingle)
- [Documentation](https://docs.apilium.com)
- [Discord](https://discord.gg/apilium)
10 changes: 4 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ build-backend = "hatchling.build"

[project]
name = "aingle-sdk"
version = "0.1.0"
description = "AIngle SDK for Python - Data science, scripts, backend"
version = "0.2.0"
description = "Python SDK for the AIngle Cortex REST API, the verifiable memory cortex for AI agents."
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.9"
authors = [
{ name = "Apilium Technologies", email = "hello@apilium.com" }
]
keywords = ["aingle", "distributed", "dag", "iot", "blockchain", "p2p", "sdk"]
keywords = ["aingle", "cortex", "memory", "semantic-graph", "ai-agents", "sdk"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
Expand All @@ -23,12 +23,10 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Distributed Computing",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"httpx>=0.27.0",
"websockets>=12.0",
"pydantic>=2.0",
]

[project.optional-dependencies]
Expand Down
53 changes: 43 additions & 10 deletions src/aingle_sdk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,54 @@
"""
AIngle SDK for Python
AIngle SDK for Python.

Official Python SDK for AIngle - the ultra-light distributed ledger for IoT devices.
An HTTP client for the AIngle Cortex REST API, the verifiable memory cortex for
AI agents.
"""

from .client import AIngleClient, AIngleClientConfig
from .types import Entry, EntryHash, NodeInfo, PeerInfo, AIngleError, ErrorCode
from .client import AIngleClient
from .types import (
AIngleError,
BatchInsertResult,
ComponentHealth,
CreateTriple,
GraphStats,
Health,
HealthComponents,
MemoryStats,
PredicatesResult,
QueryResult,
RecallResult,
RememberResponse,
ServerStats,
Stats,
SubjectsResult,
Triple,
TripleList,
Value,
node_ref,
)
from .version import __version__

__all__ = [
"AIngleClient",
"AIngleClientConfig",
"Entry",
"EntryHash",
"NodeInfo",
"PeerInfo",
"AIngleError",
"ErrorCode",
"BatchInsertResult",
"ComponentHealth",
"CreateTriple",
"GraphStats",
"Health",
"HealthComponents",
"MemoryStats",
"PredicatesResult",
"QueryResult",
"RecallResult",
"RememberResponse",
"ServerStats",
"Stats",
"SubjectsResult",
"Triple",
"TripleList",
"Value",
"node_ref",
"__version__",
]
Loading
Loading