Skip to main content

Typed sync and async Python client plus middleware for the Pali memory API.

Project description

Pali Python Client

Typed sync and async Python SDK plus middleware for the Pali memory API.

Pali is very early in development and should not be treated as a complete memory solution yet. Right now the product focus is infrastructure correctness and reliability first.

Middleware is available as an early-stage autopilot helper, not a guaranteed memory optimization system.

Installation

pip install pali-client

Optional extras:

pip install "pali-client[openai]"
pip install "pali-client[dev]"

Environment Variables

The client supports low-priority environment variable fallbacks:

  • PALI_BASE_URL
  • PALI_TOKEN
  • PALI_TIMEOUT

Constructor arguments always win over environment values.

Quickstart

from pali import PaliClient

client = PaliClient("http://127.0.0.1:8080")
client.create_tenant("user:42", name="User 42")
client.store("user:42", "Likes jazz", tags=["music"], kind="observation")
results = client.search("user:42", "music preferences", top_k=3)

for item in results.items:
    print(item.content)

Common Patterns

Store a memory:

from pali import PaliClient

client = PaliClient("http://127.0.0.1:8080", token="jwt-token")
stored = client.store(
    "user:42",
    "Moved to Austin in 2024.",
    tier="episodic",
    kind="event",
    tags=["profile"],
    source="chat_message",
    created_by="user",
)
print(stored.id)

Search memory:

results = client.search(
    "user:42",
    "where does the user live?",
    top_k=5,
    min_score=0.25,
    tiers=["episodic", "semantic"],
    kinds=["event", "observation"],
)

Delete a memory:

client.delete("user:42", "mem_abc123")

Async client:

import asyncio

from pali import PaliAsyncClient


async def main() -> None:
    async with PaliAsyncClient("http://127.0.0.1:8080") as client:
        health = await client.health()
        print(health.status)


asyncio.run(main())

Middleware wrap (experimental autopilot):

from pali import PaliClient, PaliMiddleware

client = PaliClient("http://127.0.0.1:8080")
middleware = PaliMiddleware(client, "user:42")


def llm(messages):
    return "The user likes jazz."


wrapped = middleware.wrap(llm)
reply = wrapped([{"role": "user", "content": "What music do I like?"}])
print(reply)

Auto-mutate memory with explicit opt-in (experimental):

from pali import PaliMiddleware, ReplaceMemoryAction, StoreMemoryRequest


def planner(messages, recalled_memories, result, response_text):
    if recalled_memories and "moved to austin" in response_text.lower():
        return [
            ReplaceMemoryAction(
                memory_id=recalled_memories[0].id,
                request=StoreMemoryRequest(
                    tenant_id="user:42",
                    content="User lives in Austin.",
                    kind="observation",
                    created_by="system",
                ),
            )
        ]
    return []


middleware = PaliMiddleware(
    client,
    "user:42",
    allow_destructive_actions=True,
    action_planner=planner,
)

allow_destructive_actions=False by default. That means auto-add is on, but delete/replace actions are skipped unless the caller opts in.

Middleware hooks:

from pali import PaliClient, PaliMiddleware


def hook(phase: str, payload: dict[str, object]) -> None:
    print(phase, sorted(payload))


client = PaliClient("http://127.0.0.1:8080")
middleware = PaliMiddleware(
    client,
    "user:42",
    hooks={
        "SEARCH": [hook],
        "INJECT": [hook],
        "CALL": [hook],
        "STORE": [hook],
    },
)

Anthropic wrap:

wrapped = middleware.wrap_anthropic(anthropic_client)
response = wrapped.messages.create(
    model="claude-3-7-sonnet-latest",
    max_tokens=256,
    system="Be concise.",
    messages=[{"role": "user", "content": [{"type": "text", "text": "What do I like?"}]}],
)

Configuration Reference

Argument Type Default Env var Notes
base_url str required PALI_BASE_URL Constructor argument wins over env.
token `str None` None PALI_TOKEN
timeout float 15.0 PALI_TIMEOUT Applied per request.
max_retries int 3 none 1 disables retries.
http_client `httpx.Client httpx.AsyncClient None` None

Current API Coverage

Implemented now:

  • health()
  • create_tenant()
  • tenant_stats()
  • store()
  • store_batch()
  • search()
  • delete()

Not implemented because the current Pali server does not expose them as of March 7, 2026:

  • GET /v1/memory/:id
  • PATCH /v1/memory/:id
  • DELETE /v1/tenants/:id
  • cursor-based pagination for memory search
  • streaming search/event feeds

Middleware mutation semantics:

  • Default writeback is add-only.
  • Middleware can now execute store, delete, and replace actions when a custom action_planner is provided.
  • replace is currently executed as delete-plus-store because the server still has no PATCH /v1/memory/:id.
  • Destructive actions require allow_destructive_actions=True.

Error Handling

from pali import NotFoundError, PaliError

try:
    client.delete("user:42", "missing")
except NotFoundError as err:
    print(err.request_id)
except PaliError as err:
    print(err)

Common API errors are raised as typed subclasses:

  • UnauthorizedError
  • ForbiddenError
  • NotFoundError
  • ConflictError
  • RateLimitError
  • APIError
  • ValidationError
  • TransportError

Contributing

See CONTRIBUTING.md.

Examples

See examples/basic.py, examples/async_client.py, and examples/middleware_hooks.py.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pali_client-0.1.0.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pali_client-0.1.0-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file pali_client-0.1.0.tar.gz.

File metadata

  • Download URL: pali_client-0.1.0.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for pali_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f3f4f2759d2e3c35dd42f059995702de7a18a00ba498af321fc701fb62a29aa1
MD5 4fe42b307c203330f6d4f3ae756e590c
BLAKE2b-256 b280267d32a1f79f267a95816306b852a9407c4ec1b4a9f2e546d1f9f4030e82

See more details on using hashes here.

File details

Details for the file pali_client-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pali_client-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for pali_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 886c2a6c8e483c4fabdd634856d868bfed77a0a1b4dd3693affe0b6cfcc504f3
MD5 68d3adc75c90a92d4f66c99e6ea6279f
BLAKE2b-256 58aff064de5889d41d54545b556eb2a6e184398cad5969f36c4d8ce6ab6fdbbb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page