added rant

This commit is contained in:
dullfig 2026-01-04 22:22:17 -08:00
parent a1ad8b843f
commit 67c77d568e
3 changed files with 104 additions and 73 deletions

View file

@ -11,6 +11,16 @@ These principles are the single canonical source of truth for the project. All d
- Exclusive C14N on ingress and egress.
- Malformed XML repaired on ingress; repairs logged in `<huh/>` metadata.
## Identity Injection & Handler Purity
- Handlers are pure, stateless functions with no knowledge of routing, thread context, or their own registered name.
- On ingress (external or gateway messages): <from> is provided and authenticated by the client/gateway (enforced by envelope validation).
- On response generation (after handler execution and multi-payload extraction):
- The dispatcher injects <from> using the executing listener's registered name (e.g., "calculator.add" or "researcher").
- For meta/primitive responses: <from> is injected as "core".
- <thread> is inherited from the incoming message (or assigned/updated for primitives like spawn-thread).
- <to> remains optional and rarely used.
- This ensures every enveloped message has a trustworthy, auditable <from> without handler involvement, preventing spoofing and keeping capability code minimal/testable.
## Configuration & Composition
- YAML file (`organism.yaml`) is the bootstrap source of truth, loaded at startup.
- Defines initial listeners, agents, gateways, meta privileges, and OOB channel configuration.
@ -46,6 +56,7 @@ These principles are the single canonical source of truth for the project. All d
- Subthreading natively supported via hierarchical thread IDs and primitives (e.g., reserved payload to spawn "parent.sub1").
- Optional structured constructs like `<todo-until/>` for visible planning.
- No hidden loops or state machines; all reasoning steps are visible messages.
- Thread management follows the dynamic call tracing model (see thread-management.md). Paths are built by appending target listener names on emission, with automatic popping on responses. Agents remain oblivious, enabling natural delegation and parallelism.
## Security & Sovereignty
- Privileged messages (per `privileged-msg.xsd`) handled exclusively on dedicated OOB channel.
@ -73,4 +84,9 @@ These principles are the single canonical source of truth for the project. All d
- Single process, async non-blocking.
- XML is the sovereign wire format; everything else is implementation detail.
## Scheduled Computation
- Timers and delays implemented as normal listeners using async sleeps.
- Caller idles naturally; wakeup messages bubble back via standard tracing.
- Enables recurrent tasks (e.g., periodic monitoring) without blocking or external schedulers.
These principles are now locked. All existing docs will be updated to match this file exactly. Future changes require explicit discussion and amendment here first.

View file

@ -4,25 +4,56 @@ The AgentServer message pump processes individual messages through a single, lin
```mermaid
flowchart TD
A["WebSocket Ingress\n(enqueue to thread buffer)"] --> B["Dispatcher Loop:\nSelect next message\n(per thread_scheduling strategy)"]
B --> C["Repair + Exclusive C14N"]
C --> D["Envelope Validation (lxml)"]
D --> E["Extract Payload Tree"]
E --> F{"Payload Namespace?"}
F -->|meta/v1| G["Core Meta Handler\n(introspection & reserved primitives)"]
F -->|capability| H["Route by (namespace, root)"]
H --> I["Validate Payload vs Listener XSD (lxml)"]
I --> J["Deserialize to Dataclass Instance (xmlable)"]
J --> K["Call handler(instance) → raw bytes"]
K --> L["Wrap bytes in <dummy></dummy>"]
L --> M["Repair/Parse → Extract all top-level payloads"]
M --> N["Wrap each payload in separate envelope\n(enqueue to target thread buffers)"]
G --> N
N --> O["Exclusive C14N + Sign"]
O --> P["WebSocket Egress\n(sequential per connection)"]
P --> B["Continue dispatcher loop if buffers non-empty"]
subgraph MessagePump
subgraph Init
start([Start])
raw[/Optional<br>Raw Bytes/]
wrapstart["Wrap<br>&ltstart&gt{...}&lt/start&gt"]
end
enq1([QUEUE 1])
rawwaiting{Raw<br>Msg<br>Waiting?}
waitRaw([Wait])
subgraph Process
extract["Extract<br>Tree"]
split["Split<br>Tree"]
subgraph foreach [For Each Message]
getmsg[Get Msg]
badTo{&ltTo&gt Missing?}
endnoto([Discard])
addfrom["Add .from"]
repair[Repair + C14N]
validate[Validate]
invalidMsg{Bad<br>Message?}
badmsg([Discard])
more{More?}
end
enqueue([QUEUE 2])
xmlWaiting{XML<br>Waiting?}
waitXml([Wait])
subgraph Async
lookup[Lookup Listener]
route[Route]
wait[await Response]
wrap["Wrap<br>&ltfrom&gt{...}&lt/from&gt"]
end
end
end
start --> raw --> wrapstart --> enq1 --> rawwaiting
rawwaiting --> |NO| waitRaw
rawwaiting ---> |YES| extract
extract --> split --> foreach
getmsg --> badTo
badTo --> |YES| endnoto
badTo --> |NO| addfrom --> repair --> validate --> invalidMsg
invalidMsg ---> |NO| more --> |Yes| getmsg
invalidMsg --> |YES| badmsg
more --> |NO| enqueue
enqueue --> xmlWaiting
xmlWaiting --> |NO| waitXml
xmlWaiting ---> |YES| lookup --> route --> wait --> wrap --> enq1
```
## Detailed Stages (Per-Message)
1. **Ingress/Enqueue**: Raw bytes → repair → preliminary tree → enqueue to target thread buffer.

View file

@ -1,65 +1,49 @@
# Thread Management in AgentServer v2.0
**January 03, 2026**
**January 04, 2026**
This document clarifies the thread ID system, subthreading mechanics, and internals. It supplements the Core Architectural Principles — hierarchical dot notation examples there reflect the wire format.
## Overview
Thread IDs are dynamic hierarchical paths that trace the exact call chain through the organism. The message pump builds and maintains them automatically.
Agents, tools, and handlers are **completely oblivious** to thread IDs — they never read, copy, or emit them.
## Wire Format: Hierarchical String IDs
- Mandatory `<thread/>` contains a **server-assigned** hierarchical string (dot notation, e.g., "root", "root.research", "root.research.images").
- Root IDs: Short, opaque, server-generated (e.g., "sess-abcd1234").
- Sub-IDs: Relative extensions for readability.
- Benefits: LLM/human-friendly copying, natural tree structure for logs/GUI.
No explicit spawn primitives are required. Topology emerges solely from the shape (single vs multiple) and targets of emitted payloads.
## Server Assignment Only
The organism assigns all final IDs — agents never invent them.
## Wire Format
- Mandatory `<thread/>` contains a readable dot-notation string (e.g., `sess-abcd1234.researcher.search.calc`).
- Root segment is an opaque server-generated session identifier.
- Subsequent segments are registered listener short names appended during routing.
- **Root initiation**: Client suggests or server auto-generates on first message; uniqueness enforced.
- **Subthread spawning**: Explicit reserved payload for intent clarity:
```xml
<spawn-thread suggested_sub_id="research"> <!-- optional relative label -->
<initial-payload> <!-- optional bootstrap fragment -->
<!-- any valid payload -->
</initial-payload>
</spawn-thread>
```
Core handler:
- Appends label (or auto-short if omitted).
- Resolves uniqueness conflicts (append "-1" etc.).
- Creates queue + seeds bootstrap.
- **Always responds** in current thread:
```xml
<thread-spawned
assigned_id="root.research"
parent_id="root"
message="Thread spawned successfully."/>
```
## Dynamic Call Tracing Rules
1. **Emission** (from current path `parent.path`):
- After handler execution and multi-payload extraction:
- For each payload, determine target listener name.
- Append that name → new path = `parent.path.target_name`.
- Single payload → sequential delegation (one deepened path).
- Multiple payloads → parallel forks (one deepened path per target, each with its own queue).
## Error Handling (No Silent Failure)
- Unknown `<thread/>` ID → no implicit creation.
- **Always inject** system error into parent thread (or root):
```xml
<system-thread-error
unknown_id="root.badname"
code="unknown_thread"
message="Unknown thread; emit <spawn-thread/> to create or correct ID."/>
```
- LLM sees error immediately, retries without hanging.
- Logs warning for monitoring.
2. **Response Bubbling**:
- On emission from path `parent.path.listener_name`:
- Pump removes the last segment.
- Routes all response payloads to `parent.path`.
- Injects `<from>` as the responding listeners registered name.
- Replies land directly in the immediate parents history.
## Internals
- Per-thread queues: dict[str, Queue].
- Scheduling via `organism.yaml`:
```yaml
thread_scheduling: "breadth-first" # or "depth-first" (default: breadth-first)
```
- Depth from dot count.
- Optional hidden UUID mapping for extra safety (implementation detail).
3. **Broadcast**:
- Single payload to a capability with multiple gateways → fanned out.
- All responses pop to the same parent path, distinguished by their individual `<from>` values.
## Design Rationale
- Explicit spawn = clear intent + bootstrap hook.
- Mandatory feedback = no LLM limbo.
- Readable IDs = easy copying without UUID mangling.
- Server control = sovereignty + no collisions.
4. **Internal Uniqueness**:
- Readable paths are mapped to UUIDs via a bidirectional resolver.
- New unique logical path → new UUID and queue.
- Ensures collision-free scheduling while keeping wire paths clean and meaningful.
Future: Alias registry, thread metadata primitives.
## Termination
- Paths become idle when their queues empty.
- Detection of `<final-answer>` (meta namespace) in the root path triggers terminal egress to the originating client.
The organism branches reliably, visibly, and recoverably.
## Key Advantages
- Complete thread obliviousness eliminates prompt bloat and copy errors.
- Natural sequential delegation and parallelism without manual management.
- Full provenance via trustworthy `<from>` injection.
- Audit trails are self-documenting call traces built from registered capability names.
The organism owns memory and topology. Threads are the living, transparent traces of computation.