InputSpec
from hypergraph import node, Graph
@node(output_name="embedding")
def embed(text: str) -> list[float]:
return [0.1, 0.2, 0.3]
@node(output_name="docs")
def retrieve(embedding: list[float], top_k: int = 5) -> list[str]:
return ["doc1", "doc2"]
@node(output_name="answer")
def generate(docs: list[str], query: str) -> str:
return f"Answer based on {len(docs)} docs"
g = Graph([embed, retrieve, generate])
# Full graph: all inputs
print(g.inputs.required) # ('text', 'query')
print(g.inputs.optional) # ('top_k',)
# Entrypoint narrows from the front
g2 = g.with_entrypoint("retrieve")
print(g2.inputs.required) # ('embedding', 'query') - text no longer needed
# Select narrows from the back
g3 = g.select("docs")
print(g3.inputs.required) # ('text',) - query no longer needed
# Bind pre-fills a value
g4 = g.bind(query="What is RAG?")
print(g4.inputs.required) # ('text',)
# All four compose
configured = g.with_entrypoint("retrieve").select("answer").bind(top_k=10)
print(configured.inputs.required) # ('embedding', 'query')
print(configured.inputs.optional) # ('top_k',)The InputSpec Dataclass
required: tuple[str, ...]
required: tuple[str, ...]optional: tuple[str, ...]
optional: tuple[str, ...]entrypoints: dict[str, tuple[str, ...]]
entrypoints: dict[str, tuple[str, ...]]bound: dict[str, Any]
bound: dict[str, Any]How Categories Are Determined
Condition
Category
Edge Cancels Default
Cycles Require Entrypoint At Construction
Scope Narrowing (Entrypoint and Select)
Accessing InputSpec
From a Graph
Getting All Input Names
Iteration
DAG Slicing Matrix
Examples
Simple Graph: Required and Optional
Bound Values
Graph with Cycles
Multiple Nodes Sharing a Parameter
Design Decisions
Canonical Scope
Value Resolution Order
Complete Example
Last updated