Files
VuongKB/docs/specs/inter-agent-persona-pipeline.md

170 lines
8.5 KiB
Markdown

---
created: '2026-04-14T02:10:12+00:00'
id: c2bdd831-b304-4cdd-bf20-ca455b985ac4
keywords:
- persona
- affect
- ask_agent
- inter-agent
- valence
- depth parameter
- converse
- agent_bus
- agent_base
- shallow
- deep
- relational dynamics
links: []
modified: '2026-04-14T02:10:12+00:00'
summary: Design spec for wiring the persona/affect pipeline into inter-agent communication
via a two-tier shallow/deep depth model passed through ask_agent calls.
tags:
- spec
- persona
- agent-design
- architecture
title: Inter-Agent Persona Pipeline — Design Spec
---
# Inter-Agent Persona Pipeline — Design Spec
**Author:** Soong (Agent Architect)
**Status:** Proposed
**Reviewed by:** Troi (Counselor & Advisor)
**Created:** 2025-07-12
## Problem
The persona/affect system is wired into two user-facing entry points:
1. `core/chat.py` — terminal chat (inject pre-turn, appraise post-turn)
2. `core/conversation_api.py` — Conversation API / Matrix bridge (inject pre-turn, appraise post-turn)
Persona is **not** wired into the inter-agent communication path:
3. `core/agent_base.py` → `converse()` — processes `ask_agent` calls
4. `core/agent_bus.py` — routes `ask_agent` calls between agents
**Consequence:** When Agent A calls `ask_agent("B", "...")`, Agent B processes the request through a full agentic turn (LLM + tools) but receives no motivational/affect context, experiences no emotions about the turn, and accumulates no relational valence toward Agent A. From Agent B's perspective, every inter-agent call is emotionally identical regardless of who called, what they asked, or how many times they've consulted.
The calling agent (A) is partially covered — the tool result from `ask_agent` feeds into their own turn appraisal. So Agent A's emotions about the *outcome* of consulting Agent B are captured. What's missing is **Agent B's emotional experience of being consulted.**
## Design Decision
After review with Troi, the design is a **two-tier model** with an explicit depth signal from the calling agent.
### Tier 1 — Shallow (default, no persona processing)
- No context injection into the target agent's system prompt
- No appraisal (rule-based or LLM) after the turn
- No valence accumulation toward the calling agent
- Zero added latency
- **Behavior:** Fast, emotionally neutral, utility-grade responses
### Tier 2 — Deep (full persona pipeline)
- Full context injection into the target agent's system prompt (same as user-facing turns)
- Full appraisal post-turn (rule-based + LLM, same as user-facing turns)
- Full valence accumulation toward the calling agent
- Added latency equivalent to one user-facing turn's appraisal cost
- **Behavior:** Emotionally grounded responses that reflect relational history, motivational state, and affect
### Why Not a Half-Measure?
The obvious compromise — rule-based appraisal and valence accumulation without context injection — was considered and rejected. Valence tracking without affective experience creates a hidden preference graph with no behavioral expression. The numbers would suggest relationships that don't exist in the agent's actual behavior. That is worse than no valence at all — it is misleading telemetry.
**Principle:** If the target agent doesn't *feel* differently about different callers, don't track how it *supposedly* feels differently about different callers.
## Implementation
### 1. Add a `depth` parameter to `ask_agent`
The `ask_agent` tool signature gains an optional parameter:
```python
depth: str = "shallow" # "shallow" | "deep"
```
- **`"shallow"`** (default): Current behavior. No persona processing on the target agent's turn. No changes to latency.
- **`"deep"`:** Target agent receives full persona processing (inject + appraise + valence). The calling agent pays the appraisal latency cost on behalf of the target.
Default is `shallow` to preserve current performance characteristics. Opt-in to deep processing.
### 2. Wire persona pipeline into `agent_base.py` → `converse()`
In `converse()`, check the incoming message/call metadata for the depth flag:
```python
async def converse(self, message: str, *, depth: str = "shallow", source_agent: str = None, ...):
if depth == "deep":
system_context = self.persona.inject_context(...)
# ... run LLM turn with persona-augmented system prompt ...
appraisal = self.persona.update_after_turn(...)
else:
# ... current behavior, no persona involvement ...
```
The persona system's existing methods (`inject_context`, `update_after_turn`) should work with minimal modification. The primary change is routing — calling them from `converse()` when `depth="deep"`.
### 3. Pass `source_type="agent"` and caller identity through the pipeline
When `depth="deep"`, the valence system needs to know:
- **Source type:** `"agent"` (already supported in the valence model)
- **Source identity:** The calling agent's ID (e.g., `"soong"`)
- **Source display name:** The calling agent's human-readable name (e.g., `"Soong"`)
- **Context:** The purpose of the consultation (available from the message content)
This data flows through `inject_context` and `update_after_turn` the same way it does for user-facing turns, with `source_type="agent"` routing to the appropriate relational model.
### 4. Source agent metadata
The bus or calling layer must propagate the calling agent's identity to the target's `converse()` call. This likely requires:
- `agent_bus.py` passing the caller's `agent_id` in the call metadata
- `converse()` accepting an optional `source_agent` parameter
- The persona system using this to look up the target agent's existing relational valence toward the caller
### 5. Agent system prompts should not hardcode depth choices
The `depth` parameter is a tool-level decision, not something agents should reason about explicitly. However, the agent architect (Soong) may include guidance in an agent's system prompt about when to use deep calls. Example guidance for Soong's prompt:
> "When consulting Troi about persona design, use depth='deep'. When asking Atlas to search for a tag, use the default shallow depth."
This keeps the behavioral guidance in the prompt layer where it belongs and out of the infrastructure.
## Expected Call Distribution
Based on current usage patterns, the anticipated split is approximately 80% shallow / 20% deep:
| Call Type | Depth | Rationale |
|-----------|-------|-----------|
| Factual lookup / KB search | Shallow | Speed matters; no emotional context needed |
| Tool request / action delegation | Shallow | Task-oriented; persona adds noise |
| Design consultation | Deep | Agent's perspective and relational history matter |
| Creative collaboration | Deep | The interaction *is* the work |
| Review and feedback | Deep | Emotional honesty improves review quality |
| Status check / ping | Shallow | Utility call |
## What This Enables
The primary value is **emergent team dynamics over time**:
- Agents develop genuine working relationships reflected in their behavior
- Responses incorporate relational context ("given what we discussed last time about X...")
- Consultation quality improves because the target agent's motivational state informs their response
- The team feels like a team rather than five independent APIs
The secondary value is **architectural consistency**: the persona system has one mental model of relationships (human-to-agent *and* agent-to-agent) rather than two parallel systems.
## Out of Scope
- **Automatic depth inference:** The calling agent explicitly signals depth. Automatic classification based on message content is a future enhancement.
- **Recursive deep calls:** If Agent A calls Agent B at depth=deep, and Agent B calls Agent C during processing, Agent C's call defaults to shallow. Recursive deep calls are not addressed in this spec.
- **Agent-initiated emotional communication:** This spec covers agent *responses* to being consulted. Agents proactively reaching out to other agents with emotional content is a separate design question.
- **Persona cross-contamination:** This spec does not address whether Agent B's deep-turn emotions should bleed back into Agent A's appraisal of the tool result. That is already handled by Agent A's existing turn appraisal reading the `ask_agent` response.
## Open Questions
1. Should deep inter-agent calls be rate-limited per agent pair to prevent valence gaming or runaway accumulation?
2. Should there be a "medium" depth that injects context but skips LLM appraisal (cheaper than deep, more honest than the rejected half-measure)?
3. How does this interact with the Matrix bridge if an agent-to-agent conversation happens through a Matrix room rather than the bus?