Skip to main content

LDP Mode 3 (Semantic Graphs) reference implementation using FlowScript IR

Project description

flowscript-ldp

Tests Python License PyPI

First implementation of LDP Mode 3 (Semantic Graphs) using FlowScript IR.

Reference implementation for Mode 3 of the LLM Delegate Protocol (Prakash, 2026). Mode 3 — "structured relationship representations for planning and formal reasoning" — is specified but not yet evaluated in the paper. This package provides the first working implementation: a queryable semantic graph format for inter-agent communication.

What is FlowScript?

FlowScript is a semantic notation that compiles to a typed intermediate representation (IR). The IR is a graph with three collections:

  • Nodes (12 types): statements, questions, thoughts, decisions, blockers, insights, actions, completions, alternatives, exploring, parking, blocks
  • Relationships (10 types): causes, temporal, derives_from, bidirectional, tension, equivalent, different, alternative, alternative_worse, alternative_better
  • States (4 types): blocked, decided, exploring, parking

Every element has provenance metadata (source file, line number, timestamp) and SHA-256 content-addressed deduplication. This gives you a queryable graph where you can trace causal chains, map tradeoffs, find blockers, and reconstruct decisions computationally — without parsing natural language.

Quick Start

Load a pre-compiled IR graph and start querying — no external tools needed:

import json
from flowscript_ldp import FlowScriptPayload

with open("examples/sample_ir.json") as f:
    ir_data = json.load(f)

payload = FlowScriptPayload.from_dict(ir_data)

# Find all tradeoffs in the graph
tensions = payload.query.tensions()
# → 3 tensions: "cost vs control", "latency vs cost", "performance vs freshness"

# Track blockers with impact scores
blocked = payload.query.blocked()
# → 1 blocker: "add cache hit/miss monitoring to Datadog"

# Trace causal ancestry
node_id = "fdc98c25..."  # "centralized cache invalidation"
why = payload.query.why(node_id, format="minimal")
# → root_cause: "Redis cache layer"

# Encode for LDP transport
envelope = payload.encode()
# → {"ldp_version": "1.0", "payload_mode": 3, "payload_format": "flowscript-ir", ...}

If you have the FlowScript CLI installed, you can also parse .fs files directly:

from flowscript_ldp import ParserBridge, FlowScriptPayload
bridge = ParserBridge()
ir = bridge.parse_file("thinking.fs")
payload = FlowScriptPayload(ir)

Why Mode 3?

The LLM Delegate Protocol defines 6 payload modes (0–5) for inter-agent communication:

Mode Name Status
0 Text Evaluated in paper
1 Semantic Frames Evaluated in paper
2 Embedding Hints Specified, unimplemented
3 Semantic Graphs Specified, first implementation here
4 Latent Capsules Future work
5 Cache Slices Future work

Modes 0–1 pass text or structured JSON between agents. Mode 3 passes queryable graphs — agents can trace causality, find tradeoffs, and reconstruct decisions computationally instead of inferring them from prose. Five operations make the structure computable:

Query What it does Example
why(node_id) Trace causal ancestry backward root_cause: "Redis cache layer"
what_if(node_id) Trace downstream impact forward "affects 4 downstream considerations"
tensions() Extract all tradeoffs "cost vs control", "latency vs cost"
blocked() Find blockers with impact scores "Datadog trial expired" (impact: 0)
alternatives(question_id) Reconstruct decisions 3 options considered, chosen: "Redis"

Each query supports multiple output formats (chain/tree/minimal for why, tree/list/summary for what_if, axis/node/flat for tensions, comparison/tree/simple for alternatives).

Fallback Chain

Per LDP spec, when Mode 3 fails or the receiver doesn't support it, the protocol degrades gracefully:

Mode 3 (Semantic Graph) → Mode 1 (Semantic Frame) → Mode 0 (Natural Language)
from flowscript_ldp import FallbackChain

fallback = FallbackChain(ir)

# Mode 3 → Mode 1: Structured semantic frame
mode1 = fallback.to_mode1()
# → {"task_type": "decision_analysis", "instruction": "caching strategy for...", ...}

# Mode 3 → Mode 0: Natural language prose
mode0 = fallback.to_mode0()
# → "Question: caching strategy for read-heavy API endpoints\n  Option: Redis cache layer\n  ..."

Provenance and Quality

The LDP paper's key finding: noisy provenance degrades synthesis quality below the no-provenance baseline. FlowScript IR's temporal graduation model — observations must survive quality gates to persist — acts as a provenance noise filter. Mode 3 payloads carrying pre-filtered relational structure sidestep the degradation the paper identifies.

JamJet + LDP Integration

As of v0.2.0, flowscript-ldp integrates with both JamJet v0.2.0's ProtocolAdapter interface and the standalone ldp-protocol SDK.

LDP Delegate (server-side)

Run a Mode 3 delegate as an HTTP service that any LDP client can discover, negotiate with, and submit tasks to:

from flowscript_ldp.delegate import FlowScriptMode3Delegate

delegate = FlowScriptMode3Delegate()
delegate.run(port=8090)  # HTTP server with /ldp/identity, /ldp/capabilities, /ldp/messages

The delegate advertises 6 skills (flowscript.tensions, flowscript.blocked, flowscript.why, flowscript.what_if, flowscript.alternatives, flowscript.degrade) and negotiates Mode 3 (Semantic Graph) payloads during session establishment.

from ldp_protocol import LdpClient

async with LdpClient() as client:
    # Discover delegate capabilities
    identity = await client.discover("http://localhost:8090")

    # Submit a query task
    result = await client.submit_task(
        "http://localhost:8090",
        skill="flowscript.tensions",
        input_data={"ir": ir_json},
    )
    # → {"output": {"tensions": [...], "metadata": {...}}, "provenance": {...}}

JamJet ProtocolAdapter (client-side)

Register flowscript-ldp with JamJet's protocol registry so workflows can route to LDP delegates via ldp:// URLs:

from flowscript_ldp.adapter import FlowScriptLdpAdapter

FlowScriptLdpAdapter.register()  # registers for ldp:// and ldp+flowscript:// URL prefixes

JamJet @tool integration

FlowScript query operations are also available as JamJet-compatible @tool functions for use in agent workflows:

from jamjet import Agent
from flowscript_ldp import get_jamjet_tools

agent = Agent(
    "analyst",
    model="claude-haiku-4-5-20251001",
    tools=get_jamjet_tools(),  # 6 async tools: tensions, blocked, why, what_if, alternatives, degrade
    instructions="Analyze the semantic graph for tradeoffs and blockers.",
)
result = await agent.run(f"Analyze this: {ir_json}")

Standalone use

The sync query functions and adapter work without JamJet or ldp-protocol:

from flowscript_ldp.adapter import flowscript_tensions, FlowScriptMode3Adapter

# Direct function call
result = flowscript_tensions(ir_data)

# Adapter with query dispatch
adapter = FlowScriptMode3Adapter()
result = adapter.invoke(envelope, query="tensions", fallback_mode=1)

See examples/standalone_demo.py for a runnable demo of all 5 queries.

CLI

flowscript-ldp info graph.json                              # IR statistics
flowscript-ldp query tensions graph.json                    # Find tradeoffs
flowscript-ldp query blocked graph.json                     # Find blockers
flowscript-ldp query why <node_id> graph.json               # Trace causes
flowscript-ldp query what-if <node_id> graph.json           # Impact analysis
flowscript-ldp query alternatives <question_id> graph.json  # Decision reconstruction
flowscript-ldp encode graph.json                            # Wrap in Mode 3 envelope
flowscript-ldp degrade graph.json --mode 0                  # Degrade to natural language

Installation

pip install flowscript-ldp              # core (IR, queries, payload, fallback, CLI)
pip install flowscript-ldp[ldp]         # + LDP delegate (ldp-protocol SDK)
pip install flowscript-ldp[jamjet]      # + JamJet ProtocolAdapter
pip install flowscript-ldp[all]         # everything

From source:

pip install git+https://github.com/phillipclapham/flowscript-ldp.git

Core dependency: pydantic>=2.0. JamJet and ldp-protocol are optional — the core package (IR models, query engine, payload, fallback, adapter, CLI) works standalone. The ParserBridge optionally requires the FlowScript CLI for parsing .fs text files into IR.

Architecture

flowscript_ldp/
├── ir.py              # Pydantic models for FlowScript IR schema
├── parser_bridge.py   # Subprocess bridge to FlowScript CLI (optional)
├── query.py           # 5 query operations, 3 formats each (Python port of TypeScript engine)
├── payload.py         # Mode 3 payload encode/decode/envelope
├── fallback.py        # Mode 3 → Mode 1 → Mode 0 degradation
├── adapter.py         # Sync tools + get_jamjet_tools() + FlowScriptLdpAdapter(ProtocolAdapter)
├── delegate.py        # FlowScriptMode3Delegate(LdpDelegate) — LDP server
├── round_trip.py      # Round-trip verification utilities
└── cli.py             # Command-line interface

168 tests covering IR models, all 5 query operations with all format variants (edge cases: cycles, diamond graphs, empty graphs, depth limiting), payload round-trips, fallback chain, adapter dispatch, JamJet tool integration, LDP delegate skills/identity/negotiation, ProtocolAdapter client-side bridge, and full HTTP integration round-trips (delegate server + LdpClient + adapter).

References

License

MIT

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

flowscript_ldp-0.2.1.tar.gz (61.4 kB view details)

Uploaded Source

Built Distribution

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

flowscript_ldp-0.2.1-py3-none-any.whl (35.2 kB view details)

Uploaded Python 3

File details

Details for the file flowscript_ldp-0.2.1.tar.gz.

File metadata

  • Download URL: flowscript_ldp-0.2.1.tar.gz
  • Upload date:
  • Size: 61.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for flowscript_ldp-0.2.1.tar.gz
Algorithm Hash digest
SHA256 0491e8828381864decbfaa381d122da2e4d55ef863c289aeb1ec6a56b18ebb39
MD5 cf043895f2ed425e44b902e541393cc3
BLAKE2b-256 39ef7b463c99b98ae548cd8ef1e54e52b7d9844b9a88ec7175b16ff45935adfb

See more details on using hashes here.

File details

Details for the file flowscript_ldp-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: flowscript_ldp-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 35.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for flowscript_ldp-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6702203b4df62f559b99e63e9c6ce1bc4d5eddfe3126892b440e25ce93a7a4ce
MD5 98ae444127e3eef6decbe7b32573ea1f
BLAKE2b-256 09939251e70581459248c77601c1cad90986216b10e54a4c8afddc71c3c98d53

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