Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.

Observability Server

The observability server maintains a dependency graph of all agent messages in Neo4j, enabling graph-based policy evaluation, auditing, and analysis.

Design

The primary function of the server is event recording: it accepts message and OpenTelemetry events from instrumented applications and stores them with their dependencies in Neo4j.

In addition, it provides APIs for graph queries, forward and backward slices in particular.

The server also includes an updates server that streams graph changes in real-time to downstream consumers (e.g., the policy engine) via a gRPC API.

┌─────────────────┐     gRPC      ┌─────────────────────┐
│  Instrumented   │──────────────▶│  Observability      │
│  Application    │               │  Server (10085)     │
└─────────────────┘               └──────────┬──────────┘
                                             │
                                             ▼
                                  ┌─────────────────────┐
                                  │      Neo4j          │
                                  │  (Message Graph)    │
                                  └──────────┬──────────┘
                                             │ APOC Triggers
                                             ▼
                                  ┌─────────────────────┐     gRPC
                                  │   Updates Server    │────────────▶ Policy Engine
                                  │      (10086)        │
                                  └─────────────────────┘

Running

Generally start via docker compose. To run manually:

# Set required environment variables
NEO4J_URI=bolt://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=your-password

# Start the observability server
uv run python -m observability.server

Python API

import observability

# Configure client
observability.configure(
    server_url="localhost:10085",
    auth_hook=my_auth_hook,
)

# Record an event
observability.record_event(
    id="msg-123",
    content="Hello, world!",
    role="user",
    agent="MyAgent",
    parent_ids=["msg-122"],
)

# Register additional dependencies
observability.register_dependencies(
    id="msg-124",
    parent_ids=["msg-120", "msg-121"],
)

# Query the graph
backward = observability.backward_slice("msg-124")  # Returns NetworkX DiGraph
forward = observability.forward_slice("msg-100")

Updates Server

The updates server streams graph changes to consumers via SSE. Changes are captured by Neo4j APOC triggers and pushed to connected clients.

Endpoints

Endpoint Method Description
/state GET Current graph state (nodes, edges, sequence)
/updates/{from_position} GET SSE stream of graph changes
/ack/{client_id}/{position} POST Acknowledge receipt of updates
/notify POST Push notification from APOC triggers
/health GET Health check

Event Types

event: node_created
data: {"id": "msg-123", "content": "...", "role": "user", ...}

event: edge_created
data: {"source": "msg-123", "destination": "msg-122"}

event: node_deleted
data: {"id": "msg-123"}

event: edge_deleted
data: {"source": "msg-123", "destination": "msg-122"}

event: full_state
data: {"nodes": [...], "edges": [...], "sequence": 42}

event: heartbeat
data: {"sequence": 42}

Neo4j Schema

The graph contains two node types with DEPENDS_ON relationships:

// Message node - represents agent/user/system messages
(:Message {
    id: "msg-123",
    content: "Hello, world!",
    role: "user",
    agent: "MyAgent",
    timestamp: datetime(),
    tools: [...],
})

// Computation node - represents OTel spans (LLM calls, tool executions, etc.)
(:Computation {
    id: "span-456",
    trace_id: "abc123",
    span_id: "def456",
    name: "llm_response",
    start_time_ns: ...,
    end_time_ns: ...,
    attributes: {...},
})

// Message dependencies
(:Message)-[:DEPENDS_ON]->(:Message)

// Computation relationships
(:Computation)-[:CHILD_OF]->(:Computation)   // Span hierarchy (child -> parent)
(:Computation)-[:PRODUCES]->(:Message)       // Span outputs a message
(:Computation)-[:CONSUMES]->(:Message)       // Span uses a message as input

gRPC API

Defined in proto/observability.proto. These require

Recording messages and dependencies

These require observability-writer privileges. To record a message event in the graph:

rpc RegisterEvents (Events) returns (IDs)

message Events {
    repeated Event events = 1;
}

message Event {
    optional string text = 1;
    optional string agent = 2;
    optional Role role = 3;
    optional string id = 4;
    repeated Tool tools = 5;
    // If this message is a tool result, the tool it was derived from
    optional Tool derived_from = 6;
}

message IDs {
    repeated string ids = 1;
}

To register additional dependencies between existing messages:

rpc RegisterDependencies (Dependencies) returns (Response)

message Dependencies {
    repeated Edge edges = 1;
}

message Edge {
    string source = 1;
    string destination = 2;
    optional uint32 message_index = 3;
    optional bool proximal = 4;
}

BackwardSlice / ForwardSlice

Query the dependency graph for message provenance or impact.

rpc BackwardSlice (SliceRequest) returns (Graph) {}
rpc ForwardSlice (SliceRequest) returns (Graph) {}

message SliceRequest {
    optional string event_id = 1;   // Starting message ID
    optional uint32 max_depth = 2;  // Maximum traversal depth
}

message Graph {
    repeated Event nodes = 1;
    repeated Edge edges = 2;
}

Code Structure

File Description
observability/server.py gRPC server implementation
observability/updates_server.py SSE updates server
observability/api.py Python client API
observability/graph.py Neo4j graph operations
observability/triggers.py APOC trigger management
observability/utils.py Type conversions

Metadata

Release files for sasy-observability 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sasy-observability 0.0.1
File Size Uploaded
sasy_observability-0.0.1.tar.gz 27.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sasy-observability 0.0.1
File Interpreter ABI Platform
sasy_observability-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 57.0 kB

Release files / sasy_observability-0.0.1.tar.gz

Download URL sasy_observability-0.0.1.tar.gz
Size 27.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1994c5b9ab78bcee17e61bf691f6e27290bf790ff10de39b828e695e69d74558
BLAKE2b-256 checksum
How to use checksums
df4113d44a84aeba0d4f7366b5581a11312d6641717bd6123355ac4c1ce0a3ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.8

Release files / sasy_observability-0.0.1-py3-none-any.whl

Download URL sasy_observability-0.0.1-py3-none-any.whl
Size 29.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
feb84cda8d29ec7b8492226a689699970143d93ee7b2e6c82b2508dbcd8b8740
BLAKE2b-256 checksum
How to use checksums
d4bac36502519de9035f8e6e7bc8e8ceec2831a497ab89edf351621a8a4d602f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.5.8

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page