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
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,30 @@ The agentmemory entry is the **same MCP server block** across every host that us

**Sandboxed MCP clients** (Flatpak / Snap / restrictive containers) that can't reach the host's `localhost`: also set `"AGENTMEMORY_FORCE_PROXY": "1"` in the `env` block, and point `AGENTMEMORY_URL` at a route the sandbox can actually reach (e.g. your LAN IP). See [#234](https://github.com/rohitg00/agentmemory/issues/234) for the diagnostic walkthrough.

### Programmatic access (Python / Rust / Node)

agentmemory registers its core operations as iii functions (`mem::remember`, `mem::observe`, `mem::context`, `mem::smart-search`, `mem::forget`). Any language with an iii SDK can call them directly over `ws://localhost:49134` — no separate REST client per language.

```bash
pip install iii-sdk # Python
cargo add iii-sdk # Rust
npm install iii-sdk # Node
```

```python
from iii import register_worker

iii = register_worker("ws://localhost:49134")
iii.connect()

iii.trigger({
"function_id": "mem::smart-search",
"payload": {"project": "demo", "query": "how do tokens refresh"},
})
```

Worked example: [`examples/python/`](examples/python/) (quickstart + observation/recall flow). REST on `:3111` remains available for hosts without an iii runtime.

### From source

```bash
Expand Down
71 changes: 71 additions & 0 deletions examples/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Python usage via `iii-sdk`

agentmemory registers its core operations as iii functions (`mem::remember`,
`mem::observe`, `mem::context`, `mem::smart-search`, `mem::forget`). Any
language with an iii SDK can call them directly over the WebSocket transport
on `ws://localhost:49134` — no separate REST client needed.

This example uses the official Python SDK.

## Install

```bash
pip install iii-sdk
```

## Quickstart

Start the agentmemory daemon (defaults to `ws://localhost:49134`, REST on
`:3111`):

```bash
npx -y @agentmemory/agentmemory
```

Then from Python:

```python
from iii import register_worker

iii = register_worker("ws://localhost:49134")
iii.connect()

iii.trigger({
"function_id": "mem::remember",
"payload": {
"project": "demo",
"title": "auth-stack",
"content": "Service uses HMAC bearer tokens; refresh every 24h.",
"concepts": ["auth", "hmac", "refresh"],
},
})

hits = iii.trigger({
"function_id": "mem::smart-search",
"payload": {"project": "demo", "query": "how do tokens refresh", "limit": 5},
})
print(hits)
```

## Functions exposed

| Function id | Purpose | Required payload |
|---|---|---|
| `mem::remember` | Save a memory | `project`, `title`, `content` |
| `mem::observe` | Hook-driven observation ingest | `hookType`, `sessionId`, `project`, `cwd`, `timestamp` |
| `mem::context` | Render context for a session under a token budget | `sessionId`, `project`, optional `budget` |
| `mem::smart-search` | Hybrid BM25 + vector + concept recall | `project`, `query`, optional `limit` |
| `mem::forget` | Delete a memory by id | `id` |

The HTTP-trigger wrappers under `api::*` (callable via REST on `:3111`) exist
for the same operations if you need to reach the daemon from a host without an
iii runtime. Inside the iii ecosystem, calling the `mem::*` functions directly
is lower latency.

## Files

- `quickstart.py` — minimal save-then-search loop.
- `observe_and_recall.py` — observation ingest + context rendering at a token
budget.

Both scripts assume the daemon is already running.
67 changes: 67 additions & 0 deletions examples/python/observe_and_recall.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Observation ingest + context rendering at a token budget.

Pattern: send hook-style observations during a coding session, then ask
agentmemory to render the most relevant context back at a fixed token budget.

Prerequisites:
pip install iii-sdk
npx -y @agentmemory/agentmemory

Run:
python examples/python/observe_and_recall.py
"""

from datetime import datetime, timezone
from iii import register_worker


SESSION_ID = "py-example-session-001"
PROJECT = "demo"
Comment on lines +18 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a unique session id per run to keep the example deterministic.

A fixed session id makes repeated runs bleed context across executions, which can confuse quick verification.

Suggested patch
 from datetime import datetime, timezone
+from uuid import uuid4
 from iii import register_worker
 
 
-SESSION_ID = "py-example-session-001"
+SESSION_ID = f"py-example-session-{uuid4().hex[:8]}"
 PROJECT = "demo"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/python/observe_and_recall.py` around lines 18 - 19, The SESSION_ID
constant is hard-coded to "py-example-session-001", causing context to persist
across runs; update the code that sets SESSION_ID to generate a unique ID per
execution (e.g., combine a timestamp or UUID) so each run uses a distinct
session identifier; locate the SESSION_ID symbol in the example (and any places
that reference it) and replace the fixed string with a runtime-generated unique
value.



def now_iso() -> str:
return datetime.now(timezone.utc).isoformat()


def main() -> None:
iii = register_worker("ws://localhost:49134")
iii.connect()

observations = [
("PreToolUse", {"tool": "Bash", "command": "cargo test"}),
("PostToolUse", {"tool": "Bash", "exit_code": 0}),
("UserPromptSubmit", {"prompt": "refactor auth middleware to use HMAC"}),
]

for hook_type, data in observations:
iii.trigger(
{
"function_id": "mem::observe",
"payload": {
"hookType": hook_type,
"sessionId": SESSION_ID,
"project": PROJECT,
"cwd": "/home/user/service",
"timestamp": now_iso(),
"data": data,
},
}
)

context = iii.trigger(
{
"function_id": "mem::context",
"payload": {
"sessionId": SESSION_ID,
"project": PROJECT,
"budget": 2000,
},
}
)

print(f"Rendered context ({context.get('token_count', 0)} tokens):\n")
print(context.get("text", ""))


if __name__ == "__main__":
main()
46 changes: 46 additions & 0 deletions examples/python/quickstart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Minimal agentmemory usage via iii-sdk.

Prerequisites:
pip install iii-sdk
npx -y @agentmemory/agentmemory # daemon at ws://localhost:49134

Run:
python examples/python/quickstart.py
"""

from iii import register_worker


def main() -> None:
iii = register_worker("ws://localhost:49134")
iii.connect()

iii.trigger(
{
"function_id": "mem::remember",
"payload": {
"project": "demo",
"title": "auth-stack",
"content": "Service uses HMAC bearer tokens; refresh every 24h.",
"concepts": ["auth", "hmac", "refresh"],
},
}
)

hits = iii.trigger(
{
"function_id": "mem::smart-search",
"payload": {
"project": "demo",
"query": "how do tokens refresh",
"limit": 5,
},
}
)

for memory in hits.get("results", []):
print(f"[{memory.get('score', 0):.3f}] {memory.get('title')}: {memory.get('content')}")


if __name__ == "__main__":
main()
Loading