Skip to content
Open
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
13 changes: 12 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@ Thanks for considering a contribution. Adrian is open-source under the [Apache 2

## Local dev setup

The Python SDK lives at `sdk/python/` (the TypeScript SDK lives at `sdk/typescript/`). From the repo root:
The Python SDK lives at `sdk/python/`. From the repo root:

```sh
make sdk-install # creates .venv and installs sdk + dev deps via uv
source .venv/bin/activate
pre-commit install # wires the git hook
```

The TypeScript SDK lives at `sdk/typescript/` as an npm workspace with two packages (`core`, `openai`). From that directory:

```sh
cd sdk/typescript
npm install
npm run build
npm test
```

Provider packages include `@secureagentics/adrian` as a dependency and re-export `init`, `shutdown`, and other core APIs — users install one package (e.g. `@secureagentics/adrian-openai openai`) and import everything from it. See [`sdk/typescript/README.md`](sdk/typescript/README.md) for usage examples.

After `pre-commit install`, every `git commit` runs the configured hooks on
staged files: `ruff format`, `ruff check --fix`, `basedpyright` on
`sdk/python/adrian/`, plus the standard whitespace / YAML / TOML checks. Hooks that
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Adrian OSS — top-level developer Makefile
#
# Local-dev convention: every Python entry point goes through the
# project-local ``.venv`` so the bundled ``sdk/python/`` install (``pip
# install -e ./sdk/python``) cannot collide with a system-wide
# ``adrian-sdk`` wheel from PyPI. ``make sdk-install`` creates the venv
# and the editable install in one shot.
# project-local ``.venv`` so the bundled Python SDK install (``pip
# install -e ./sdk/python``) cannot collide with a system-wide ``adrian-sdk``
# wheel from PyPI. ``make sdk-install`` creates the venv and the
# editable install in one shot.

.PHONY: sdk-install sdk-test sdk-clean help

Expand All @@ -24,7 +24,7 @@ endif
@echo "Or run anything via uv: 'uv run python ...'"

sdk-test: ## Run the bundled SDK test suite
uv run --project ./sdk/python pytest sdk/python/tests
uv run --project ./sdk/python --extra dev pytest sdk/python/tests

sdk-clean: ## Remove .venv and SDK build artefacts
rm -rf .venv sdk/python/.venv sdk/python/dist sdk/python/build sdk/python/*.egg-info
Expand Down
4 changes: 2 additions & 2 deletions backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ clean:
# the Go bindings. Strips the buf.validate import and field annotations
# (see proto/README.md). Requires protoc + protoc-gen-go on PATH.
proto-sync:
@echo "Syncing proto/event.proto from ../proto/..."
@echo "Syncing proto/event.proto from sdk/python/adrian/proto/..."
@sed \
-e '/^import "buf\/validate\/validate.proto";$$/d' \
-e 's| \[(buf\.validate\.field)[^]]*\]||g' \
-e '/^package adrian\.core_api\.v1;$$/a\option go_package = "github.com/secureagentics/Adrian/backend/internal/proto;proto";' \
../proto/event.proto > proto/event.proto
../sdk/python/adrian/proto/event.proto > proto/event.proto
@$(MAKE) proto-regen

# Regenerate Go bindings from proto/event.proto.
Expand Down
Binary file added backend/data/adrian.db
Binary file not shown.
4 changes: 2 additions & 2 deletions backend/proto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The wire schema for SDK <-> backend WebSocket frames.

## Layout

- `event.proto` is the Go-side copy of the wire schema. The single source of truth is `proto/event.proto` at the repo root.
- `event.proto` is the Go-side copy of the wire schema. The single source of truth is `sdk/python/adrian/proto/event.proto` at the repo root.
- The Go-side copy is **stripped** of the `buf.validate` import and field annotations:
- The `import "buf/validate/validate.proto";` line is removed.
- Every `[(buf.validate.field).*]` annotation is removed.
Expand All @@ -15,7 +15,7 @@ The wire schema for SDK <-> backend WebSocket frames.

When the wire schema changes:

1. Edit `proto/event.proto` (the source of truth).
1. Edit `sdk/python/adrian/proto/event.proto` (the source of truth).
2. Regenerate the SDK's Python bindings: `cd sdk/python && uv run bash tools/regen-proto.sh`.
3. Sync the backend copy and regenerate the Go bindings: `cd backend && make proto-sync`.
4. Commit both.
Expand Down
17 changes: 14 additions & 3 deletions sdk/python/adrian/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@

import asyncio
import atexit
import importlib
import logging
import os
from pathlib import Path
from typing import Any
from typing import Any, cast
from uuid import uuid4

from langchain_core.callbacks.manager import CallbackManager
Expand Down Expand Up @@ -679,10 +680,15 @@ def _patch_langgraph() -> None:
top-level call so all sub-agent events share the same ID.
"""
try:
from langgraph.pregel import Pregel
pregel_mod = importlib.import_module("langgraph.pregel")
except ImportError:
return

Pregel = cast("Any", getattr(pregel_mod, "Pregel", None))

if Pregel is None:
return

if getattr(Pregel, "_adrian_pregel_patched", False):
return

Expand Down Expand Up @@ -864,10 +870,15 @@ def _patch_tool_node() -> None:
tools. On timeout it fails open.
"""
try:
from langgraph.prebuilt import ToolNode
prebuilt_mod = importlib.import_module("langgraph.prebuilt")
except ImportError:
return

ToolNode = cast("Any", getattr(prebuilt_mod, "ToolNode", None))

if ToolNode is None:
return

if getattr(ToolNode, "_adrian_tool_node_patched", False):
return

Expand Down
5 changes: 3 additions & 2 deletions sdk/python/adrian/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from __future__ import annotations

import contextlib
import importlib
import logging
import sys
from collections.abc import Mapping
Expand Down Expand Up @@ -179,11 +180,11 @@ def _patch_mcp_adapter() -> None: # pyright: ignore[reportUnusedFunction]
def _patch_langchain_mcp_adapters() -> None:
"""Patch ``MultiServerMCPClient.__init__`` to snapshot declarations."""
try:
from langchain_mcp_adapters import client as client_mod
client_mod = importlib.import_module("langchain_mcp_adapters.client")
except ImportError:
return

cls = getattr(client_mod, "MultiServerMCPClient", None)
cls = cast("Any", getattr(client_mod, "MultiServerMCPClient", None))

if cls is None or getattr(cls, "_adrian_mcp_patched", False):
return
Expand Down
6 changes: 6 additions & 0 deletions sdk/python/adrian/proto/buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: v2
plugins:
- remote: buf.build/protocolbuffers/python
out: .
- remote: buf.build/protocolbuffers/pyi
out: .
6 changes: 6 additions & 0 deletions sdk/python/adrian/proto/buf.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Generated by buf. DO NOT EDIT.
version: v2
deps:
- name: buf.build/bufbuild/protovalidate
commit: 50325440f8f24053b047484a6bf60b76
digest: b5:74cb6f5c0853c3c10aafc701614194bbd63326bdb8ef4068214454b8894b03ba4113e04b3a33a8321cdf05336e37db4dc14a5e2495db8462566914f36086ba31
5 changes: 5 additions & 0 deletions sdk/python/adrian/proto/buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version: v2
modules:
- path: .
deps:
- buf.build/bufbuild/protovalidate
File renamed without changes.
102 changes: 101 additions & 1 deletion sdk/python/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions sdk/typescript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
coverage/
.vite/
.env
Loading
Loading