Replace XMLListener stub with real foundation
- Minimal, universal base for all capabilities - Required listens_to class attribute - Async handle() with convo_id preservation rule - make_response() helper for thread continuity - Explicit name, config, per-instance logger - Clear documentation and NotImplementedError guard This is the true substrate the entire organism will build on.
This commit is contained in:
parent
4c3a5bad02
commit
f3b90963b8
2 changed files with 94 additions and 13 deletions
|
|
@ -1,11 +1,13 @@
|
||||||
"""
|
"""
|
||||||
Core base class for all listeners in the organism.
|
Core base class for all listeners in the xml-pipeline organism.
|
||||||
|
|
||||||
|
All capabilities — personalities, tools, gateways — inherit from this class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Optional, Dict, Any
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
|
|
@ -17,13 +19,14 @@ class XMLListener:
|
||||||
Base class for all capabilities (personalities, tools, gateways).
|
Base class for all capabilities (personalities, tools, gateways).
|
||||||
|
|
||||||
Subclasses must:
|
Subclasses must:
|
||||||
- Define `listens_to` (list of root tags they handle)
|
- Define `listens_to` as a class attribute (list of root tags they handle)
|
||||||
- Implement `async handle()`
|
- Implement `async handle()` method
|
||||||
|
|
||||||
The `convo_id` received in handle() MUST be preserved in any response payload.
|
The `convo_id` received in handle() MUST be preserved in any response payload
|
||||||
|
(via make_response() helper or manually).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
listens_to: List[str] = [] # Must be overridden in subclass
|
listens_to: List[str] = [] # Must be overridden in subclass — required
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
@ -32,6 +35,11 @@ class XMLListener:
|
||||||
config: Optional[Dict[str, Any]] = None,
|
config: Optional[Dict[str, Any]] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
name: Optional explicit name (defaults to class name)
|
||||||
|
config: Owner-provided configuration from privileged registration
|
||||||
|
"""
|
||||||
self.name = name or self.__class__.__name__
|
self.name = name or self.__class__.__name__
|
||||||
self.config = config or {}
|
self.config = config or {}
|
||||||
self.logger = logging.getLogger(f"{__name__}.{self.name}")
|
self.logger = logging.getLogger(f"{__name__}.{self.name}")
|
||||||
|
|
@ -40,14 +48,14 @@ class XMLListener:
|
||||||
self, msg: etree.Element, convo_id: str
|
self, msg: etree.Element, convo_id: str
|
||||||
) -> Optional[etree.Element]:
|
) -> Optional[etree.Element]:
|
||||||
"""
|
"""
|
||||||
Handle a message whose root tag matches this listener.
|
Process an incoming message whose root tag matches this listener.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
msg: The payload element (repaired and C14N'd)
|
msg: The payload element (already repaired and C14N'd)
|
||||||
convo_id: Thread/conversation UUID — must be preserved in response
|
convo_id: Thread/conversation UUID — must be preserved in any response
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Response payload element with the same convo_id, or None
|
Response payload element (with convo_id preserved), or None if no response
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f"{self.__class__.__name__}.handle() must be implemented"
|
f"{self.__class__.__name__}.handle() must be implemented"
|
||||||
|
|
@ -62,8 +70,9 @@ class XMLListener:
|
||||||
**attribs,
|
**attribs,
|
||||||
) -> etree.Element:
|
) -> etree.Element:
|
||||||
"""
|
"""
|
||||||
Helper to create a response element with a preserved convo_id attribute.
|
Convenience helper to create a response element with preserved convo_id.
|
||||||
Recommended for all listeners.
|
|
||||||
|
Strongly recommended for all listeners to ensure thread continuity.
|
||||||
"""
|
"""
|
||||||
elem = etree.Element(tag, convo_id=convo_id, **attribs)
|
elem = etree.Element(tag, convo_id=convo_id, **attribs)
|
||||||
if text is not None:
|
if text is not None:
|
||||||
|
|
@ -71,4 +80,4 @@ class XMLListener:
|
||||||
return elem
|
return elem
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<{self.__class__.__name__} listens_to={self.listens_to}>"
|
return f"<{self.__class__.__name__} name='{self.name}' listens_to={self.listens_to}>"
|
||||||
72
docs/logic and iteration.md
Normal file
72
docs/logic and iteration.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Executive Summary: Self-Calling Iteration Framework in xml-pipeline
|
||||||
|
|
||||||
|
**Date**: December 29, 2025
|
||||||
|
**Component**: Core reasoning mechanism for LLM personalities
|
||||||
|
|
||||||
|
### Principle
|
||||||
|
|
||||||
|
In xml-pipeline, **multi-step reasoning, planning, tool use, and iteration are implemented through open, auditable self-calls** — not hidden loops or state machines.
|
||||||
|
|
||||||
|
The LLM personality participates in the conversation exactly like any other listener: it can send messages to its own root tag.
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. **Conversation thread = memory**
|
||||||
|
Every message (user, personality, tool) is appended to history keyed by `convo_id`.
|
||||||
|
|
||||||
|
2. **Self-reflection = self-message**
|
||||||
|
To think step-by-step, the LLM emits its own root tag with the same `convo_id`:
|
||||||
|
```xml
|
||||||
|
<ask-grok convo_id="123">
|
||||||
|
First, let's outline the steps...
|
||||||
|
</ask-grok>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **MessageBus routes it back** to the same personality instance.
|
||||||
|
|
||||||
|
4. **Personality appends its own message** to history and calls the LLM again.
|
||||||
|
|
||||||
|
5. **LLM sees full context** — including its previous thoughts — and continues.
|
||||||
|
|
||||||
|
6. **Iteration emerges naturally** from repeated self-calls until final response.
|
||||||
|
|
||||||
|
### Key Properties
|
||||||
|
|
||||||
|
- **No hidden state** — the thread history is the only memory
|
||||||
|
- **No special controller** — MessageBus and `convo_id` do all coordination
|
||||||
|
- **Fully auditable** — every thought, plan, and intermediate step is a logged message
|
||||||
|
- **Tool use fits identically** — tool calls are messages to other root tags
|
||||||
|
- **Termination is natural** — LLM decides when to emit final response tag (e.g., `<grok-response>`)
|
||||||
|
|
||||||
|
### Structured Planning Support
|
||||||
|
|
||||||
|
Personalities are encouraged to use visible structures:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<todo-until condition="all primes under 100 listed">
|
||||||
|
<step done="true">List 2</step>
|
||||||
|
<step done="true">List 3</step>
|
||||||
|
<step done="false">List 5</step>
|
||||||
|
</todo-until>
|
||||||
|
```
|
||||||
|
|
||||||
|
This enables:
|
||||||
|
- Self-coordination (LLM reads its own plan)
|
||||||
|
- GUI progress rendering
|
||||||
|
- Explicit termination conditions
|
||||||
|
|
||||||
|
### Owner Control
|
||||||
|
|
||||||
|
- `iteration-capacity` config (`high`/`medium`/`low`/`none`) tunes how strongly the personality is prompted to iterate
|
||||||
|
- All behavior governed by owner-provided prompts and response templates
|
||||||
|
- No personality can loop indefinitely without owner consent
|
||||||
|
|
||||||
|
### Result
|
||||||
|
|
||||||
|
The framework turns **conversation into computation**.
|
||||||
|
|
||||||
|
Loops, conditionals, and planning become **visible message patterns** rather than hidden code.
|
||||||
|
|
||||||
|
The organism reasons by talking to itself in the open — producing a complete, transparent trace of thought at every step.
|
||||||
|
|
||||||
|
This is the core iteration mechanism for all LLM personalities in xml-pipeline.
|
||||||
Loading…
Reference in a new issue