OSS restructuring for open-core model: - Rename package from agentserver/ to xml_pipeline/ - Update all imports (44 Python files, 31 docs/configs) - Update pyproject.toml for OSS distribution (v0.3.0) - Move prompt_toolkit from core to optional [console] extra - Remove auth/server/lsp from core optional deps (-> Nextra) New console example in examples/console/: - Self-contained demo with handlers and config - Uses prompt_toolkit (optional, falls back to input()) - No password auth, no TUI, no LSP — just the basics - Shows how to use xml-pipeline as a library Import changes: - from agentserver.* -> from xml_pipeline.* - CLI entry points updated: xml_pipeline.cli:main Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.2 KiB
Autonomous Registration & Introspection (v2.1)
Updated: January 10, 2026
In AgentServer v2.1, tool definition is radically simple: one @xmlify dataclass + handler + description. No manual XSDs, no fragile JSON item mappings, no custom prompt engineering. The organism auto-generates everything needed for validation, routing, and LLM wiring.
Manual XSDs, grammars, and tool descriptions are obsolete. Listeners autonomously generate their contracts and metadata at registration time. Introspection is a privileged core facility.
The Developer Experience
Declare your payload contract as an @xmlify dataclass + a pure async handler function that returns HandlerResponse or None. Register with a name and description. That's it.
from xmlable import xmlify
from dataclasses import dataclass
from xml_pipeline.message_bus.message_state import HandlerMetadata, HandlerResponse
@xmlify
@dataclass
class AddPayload:
"""Addition capability."""
a: int = 0 # First operand
b: int = 0 # Second operand
@xmlify
@dataclass
class ResultPayload:
"""Calculation result."""
value: int = 0
async def add_handler(payload: AddPayload, metadata: HandlerMetadata) -> HandlerResponse:
result = payload.a + payload.b
return HandlerResponse.respond(
payload=ResultPayload(value=result)
)
# LLM agent example
async def agent_handler(payload: AgentPayload, metadata: HandlerMetadata) -> HandlerResponse:
# Build prompt with peer schemas
from xml_pipeline.llm import complete
response = await complete(
model="grok-4.1",
messages=[
{"role": "system", "content": metadata.usage_instructions},
{"role": "user", "content": payload.query},
],
agent_id=metadata.own_name,
)
return HandlerResponse(
payload=ThoughtPayload(content=response.content),
to="next_peer",
)
The pump:
- Validates input against the XSD
- Deserializes to typed dataclass instance
- Calls handler with payload + metadata
- Wraps returned payload in envelope with correct
<from>,<to>,<thread> - Re-injects into pipeline for validation and routing
Handler Contract (v2.1)
All handlers must follow this signature:
async def handler(
payload: PayloadDataclass, # XSD-validated, deserialized @xmlify instance
metadata: HandlerMetadata # Trustworthy context from pump
) -> HandlerResponse | None:
...
- Handlers must be async (
async def) - Return
HandlerResponseto send a message - Return
Noneto terminate chain (no message)
See handler-contract-v2.1.md for complete specification.
Autonomous Chain Reaction on Registration
-
XSD Synthesis From
@xmlifypayload_class → generates/cachesschemas/calculator.add/v1.xsd. Namespace:https://xml-pipeline.org/ns/calculator/v1(derived or explicit). Root = lowercase class name. -
Example & Prompt Synthesis From dataclass fields + description:
Tool: calculator.add Description: Adds two integers and returns their sum. Example Input: <add> <a>40</a> <b>2</b> </add> Params: a(int) - First operand, b(int) - Second operand Returns: Typed response payloadAuto-injected into wired agents' system prompts via
metadata.usage_instructions. -
Registry Update Bus catalogs by
nameand(namespace, root). Ready for routing + meta queries.
Usage Instructions (Auto-Generated)
When an agent has declared peers, the pump automatically builds usage_instructions containing peer schemas:
async def agent_handler(payload, metadata):
# metadata.usage_instructions contains:
# """
# You can call the following tools by emitting their XML payloads:
#
# ## calculator.add
# Adds two integers and returns their sum.
#
# ```xml
# <addpayload xmlns="https://xml-pipeline.org/ns/calculator/v1">
# <a>40</a>
# <b>2</b>
# </addpayload>
# ```
# ...
# """
pass
This replaces manual tool prompt engineering.
Introspection: Privileged Meta Facility
Query the core MessageBus via reserved https://xml-pipeline.org/ns/meta/v1:
<message ...>
<payload xmlns="https://xml-pipeline.org/ns/meta/v1">
<request-schema>
<capability>calculator.add</capability>
</request-schema>
</payload>
</message>
Core handler returns XSD bytes, example XML, or prompt fragment.
Controlled per YAML (meta.allow_schema_requests: "admin" etc.). No topology leaks.
Other ops: request-example, request-prompt, list-capabilities.
Key Advantages
- Zero Drift: Edit dataclass → restart/hot-reload → XSD/example/prompt regenerate.
- Attack-Resistant: lxml XSD validation → typed instance → handler.
- Type-Safe Returns: Handlers return typed dataclasses, pump handles envelopes.
- Peer-Aware Agents: Auto-generated
usage_instructionsfrom peer schemas. - Sovereign Wiring: YAML agents get live prompt fragments at startup.
- Discoverable: Namespaces served live at https://xml-pipeline.org/ns/... for tools and federation.
The tool declares its contract and purpose. The organism enforces and describes it exactly.
v2.1 Specification — Updated January 10, 2026