Skip to content

Docs: Update Managed Agents docs for unified SessionInfo schema & ManagedBackendProtocol re-export (PR #1439) #165

@MervinPraison

Description

@MervinPraison

Overview

PraisonAI PR MervinPraison/PraisonAI#1439 (merged, closes #1429) introduces two user-facing documentation changes to the Managed Agents backend:

  1. Unified SessionInfo schemaretrieve_session() on both AnthropicManagedAgent and LocalManagedAgent now returns the same dictionary shape with all fields always present. Adds a new title field and a new status="unknown" default for empty sessions.
  2. ManagedBackendProtocol re-export — the protocol interface is now importable from praisonaiagents.managed, making it the recommended path for anyone building a custom backend.

Existing docs still describe the old, partial schema (no title, no defaults, retrieve_session() returning {} when empty). The code examples in docs/concepts/managed-agents-local.mdx and docs/concepts/managed-agents.mdx are now incomplete / out-of-date and need updating. One new small feature page should also be created to give users a single, discoverable place to learn about the unified schema.

Action for follow-up docs agent: The pages that need edits are in docs/concepts/ which per AGENTS.md is human-approved-only. This issue explicitly authorises the docs agent to update the two existing concept pages listed below (minimal edits — schema/usage table additions only, no structural rewrites) AND to create a new feature page at docs/features/managed-agents-session-info.mdx. Do NOT create new files in docs/concepts/.


What Changed in the SDK (Ground Truth)

1. New SessionInfo dataclass

Source: src/praisonai/praisonai/integrations/_session_info.py (new file)

from dataclasses import dataclass, asdict
from typing import Dict, Any, Optional

@dataclass
class SessionInfo:
    id: str = ""                                  # empty if no session
    status: str = "unknown"                       # idle, running, error, unknown, none
    title: str = ""                               # empty if not set
    usage: Optional[Dict[str, int]] = None        # {"input_tokens": 0, "output_tokens": 0}

    def __post_init__(self):
        if self.id is None: self.id = ""
        if self.status is None: self.status = "unknown"
        if self.title is None: self.title = ""
        if self.usage is None:
            self.usage = {"input_tokens": 0, "output_tokens": 0}
        else:
            self.usage.setdefault("input_tokens", 0)
            self.usage.setdefault("output_tokens", 0)

    def to_dict(self) -> Dict[str, Any]:
        return asdict(self)

Field table (for docs):

Field Type Default Description
id str "" Session ID. Empty string when no session is active.
status str "unknown" Session status: "idle", "running", "error", "unknown", "none".
title str "" Session title/name. Empty if backend does not track titles (e.g., LocalManagedAgent).
usage Dict[str, int] {"input_tokens": 0, "output_tokens": 0} Token usage counters. Both keys are always present.

2. Unified retrieve_session() behaviour

Source: src/praisonai/praisonai/integrations/managed_agents.py (AnthropicManagedAgent) and src/praisonai/praisonai/integrations/managed_local.py (LocalManagedAgent)

Before (old behaviour — currently documented):

# Anthropic backend returned partial dict
{"id": "...", "status": "idle", "usage": {"input_tokens": 10, "output_tokens": 5}}
# Local backend returned slightly different shape
{"id": "...", "status": "idle" or "none", "usage": {...}}
# Empty session → {}

After (new behaviour — needs documenting):

# BOTH backends now return identical shape, all 4 keys always present
{
  "id": "session-abc",
  "status": "idle",
  "title": "My Session",        # NEW field (empty string on LocalManagedAgent)
  "usage": {"input_tokens": 100, "output_tokens": 50},
}

# Empty session (no session yet)
{
  "id": "",
  "status": "unknown",          # was missing entirely before
  "title": "",
  "usage": {"input_tokens": 0, "output_tokens": 0},
}

# LocalManagedAgent with _session_id = None
{
  "id": "",
  "status": "none",             # "none" means "local agent has no session"
  "title": "",
  "usage": {"input_tokens": 0, "output_tokens": 0},
}

Status values to document:

Status When Backend
"idle" Session exists and is ready Both
"running" Session is actively processing Anthropic
"error" Session encountered an error Anthropic
"unknown" No session / status not available Both (default)
"none" Local agent has _session_id = None Local only

3. ManagedBackendProtocol re-export

Source: src/praisonai-agents/praisonaiagents/managed/__init__.py

Users can now import the protocol from the managed sub-package (previously required reaching into praisonaiagents.agent.protocols):

# NEW recommended import (PR #1439)
from praisonaiagents.managed import ManagedBackendProtocol

# Old path still works (no breaking change)
from praisonaiagents.agent.protocols import ManagedBackendProtocol

The import is lazyManagedBackendProtocol is not imported until first accessed, keeping the managed module lightweight.


Pages to Update

A. Update docs/concepts/managed-agents-local.mdx (existing)

Why: The "Usage Tracking" section (lines ~180–205) and "Persistent Sessions" section (lines ~125–135) show examples that assume the old partial schema (session_info.get("usage") guard, no title, no status handling).

Required edits:

  1. In the "Usage Tracking" example, remove the .get("usage") guard — usage is now always present:

    # Before (current docs)
    session_info = managed.retrieve_session()
    if session_info.get("usage"):
        print(f"Input tokens: {session_info['usage']['input_tokens']}")
        print(f"Output tokens: {session_info['usage']['output_tokens']}")
    
    # After (update to)
    session_info = managed.retrieve_session()
    print(f"Session: {session_info['id']} (status: {session_info['status']})")
    print(f"Input tokens:  {session_info['usage']['input_tokens']}")
    print(f"Output tokens: {session_info['usage']['output_tokens']}")
  2. Add a short note under "Session Management" that retrieve_session() always returns all 4 keys (id, status, title, usage) with sensible defaults when no session exists.

  3. Add a link card under "Related" → Managed Agents: SessionInfo Schema pointing to the new feature page (see section C).

B. Update docs/concepts/managed-agents.mdx (existing)

Why: The "Best Practices → Monitor Resource Usage" accordion references retrieve_session() without showing the return shape. Add a reference to the unified schema.

Required edits:

  1. Update the retrieve_session() line in the "Monitor Resource Usage" accordion:

    Track token usage with `retrieve_session()` — returns a unified schema
    (`id`, `status`, `title`, `usage`) on all backends. See the
    [SessionInfo Schema page](/docs/features/managed-agents-session-info) for details.
    
  2. In the Configuration Options table OR as a new sub-section, mention that ManagedBackendProtocol can be imported from praisonaiagents.managed:

    # Build a custom managed backend by implementing this protocol
    from praisonaiagents.managed import ManagedBackendProtocol
    

C. Create new docs/features/managed-agents-session-info.mdx (new file)

Why: Users need a single discoverable page explaining:

  • The unified return shape
  • All field semantics and values
  • Cross-backend consistency guarantees
  • The new ManagedBackendProtocol import path for custom backends

Full page draft (follows AGENTS.md template):

Click to expand full page draft
---
title: "Managed Agent Session Info"
sidebarTitle: "Session Info Schema"
description: "Unified session schema returned by managed agent backends"
icon: "circle-info"
---

`retrieve_session()` returns the same shape on every managed agent backend so you can write code once and switch providers freely.

```mermaid
graph LR
    subgraph "Unified SessionInfo"
        A[📝 retrieve_session] --> B{🧠 Backend}
        B -->|Anthropic| C[SessionInfo dict]
        B -->|Local| C
        C --> D[id]
        C --> E[status]
        C --> F[title]
        C --> G[usage]
    end

    classDef call fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef backend fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    classDef field fill:#189AB4,stroke:#7C90A0,color:#fff

    class A call
    class B backend
    class C result
    class D,E,F,G field
```

## Quick Start

<Steps>
<Step title="Read a session">
```python
from praisonaiagents import Agent
from praisonai.integrations.managed_agents import ManagedAgent, ManagedConfig

managed = ManagedAgent(config=ManagedConfig(model="claude-sonnet-4-6"))
agent = Agent(name="assistant", backend=managed)
agent.start("Hello!")

info = managed.retrieve_session()
print(info["id"], info["status"], info["title"])
print(info["usage"]["input_tokens"], info["usage"]["output_tokens"])
```
</Step>

<Step title="Works the same on LocalManagedAgent">
```python
from praisonai.integrations.managed_local import LocalManagedAgent

local = LocalManagedAgent()
info = local.retrieve_session()
# Same 4 keys — id, status, title, usage — every time
```
</Step>
</Steps>

---

## Schema

All four fields are **always present** with sensible defaults:

| Field | Type | Default | Values |
|-------|------|---------|--------|
| `id` | `str` | `""` | Session ID, empty if none |
| `status` | `str` | `"unknown"` | `idle`, `running`, `error`, `unknown`, `none` |
| `title` | `str` | `""` | Session title (Anthropic only sets this) |
| `usage` | `Dict[str, int]` | `{"input_tokens": 0, "output_tokens": 0}` | Always has both keys |

## Status Values

```mermaid
graph TB
    Start[No Session] -->|unknown| A[status: unknown]
    Start -->|none| B[status: none]
    Active[Session Active] -->|idle| C[status: idle]
    Active -->|running| D[status: running]
    Active -->|error| E[status: error]

    classDef empty fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef active fill:#10B981,stroke:#7C90A0,color:#fff

    class A,B empty
    class C,D,E active
```

| Status | Meaning |
|--------|---------|
| `idle` | Session exists and ready for input |
| `running` | Session actively processing (Anthropic) |
| `error` | Session hit an error (Anthropic) |
| `unknown` | No session / status unavailable |
| `none` | Local backend with no session ID |

## Empty Session Defaults

Before starting any turn you still get a valid dict — no `KeyError`, no `.get()` guards:

```python
managed = ManagedAgent(config=ManagedConfig())
info = managed.retrieve_session()
# {"id": "", "status": "unknown", "title": "", "usage": {"input_tokens": 0, "output_tokens": 0}}
```

## Building a Custom Backend

Import the protocol directly from `praisonaiagents.managed`:

```python
from praisonaiagents.managed import ManagedBackendProtocol
from typing import Dict, Any

class MyBackend:
    def retrieve_session(self) -> Dict[str, Any]:
        # Return the unified shape
        return {
            "id": "my-session",
            "status": "idle",
            "title": "My Session",
            "usage": {"input_tokens": 0, "output_tokens": 0},
        }
    # ... implement execute(), stream(), reset_session(), reset_all()
```

## Common Patterns

### Cost monitoring

```python
info = managed.retrieve_session()
cost = info["usage"]["input_tokens"] * 3e-6 + info["usage"]["output_tokens"] * 15e-6
print(f"Session {info['id']} spent ${cost:.4f}")
```

### Provider-agnostic logging

```python
def log_session(backend):
    info = backend.retrieve_session()
    print(f"[{info['status']}] {info['title'] or info['id']}")

log_session(anthropic_backend)
log_session(local_backend)  # Same code — both return identical shape
```

---

## Best Practices

<AccordionGroup>
<Accordion title="Don't guard with .get()">
Every key is always present. `info["usage"]["input_tokens"]` is always safe.
</Accordion>

<Accordion title="Check status before acting">
Use `status == "idle"` before sending a new message to avoid overlapping turns.
</Accordion>

<Accordion title="Titles are optional">
`LocalManagedAgent` always returns `title=""`. Only `AnthropicManagedAgent` sets it.
</Accordion>

<Accordion title="Import the protocol from praisonaiagents.managed">
`from praisonaiagents.managed import ManagedBackendProtocol` is the stable, recommended path.
</Accordion>
</AccordionGroup>

---

## Related

<CardGroup cols={2}>
<Card title="Managed Agents" icon="cloud" href="/docs/concepts/managed-agents">
  Overview of managed agent backends
</Card>
<Card title="Local Managed Agents" icon="desktop" href="/docs/concepts/managed-agents-local">
  Run managed agents locally
</Card>
</CardGroup>

D. Add navigation entry

Add an entry under the Features group in docs.json:

{
  "group": "Features",
  "pages": [
    "…existing…",
    "docs/features/managed-agents-session-info"
  ]
}

Do NOT modify any entries under the "Concepts" group (per AGENTS.md § 1.7 / § 1.8).


User Interaction Flow (as required by AGENTS.md rule 11)

┌────────┐  1. agent.start("hello")   ┌──────────────┐
│  User  │ ─────────────────────────► │ ManagedAgent │
└────────┘                             └──────┬───────┘
     ▲                                        │
     │ 4. print info                          │ 2. backend call
     │                                        ▼
     │                                 ┌──────────────┐
     │ 3. unified dict                 │   Backend    │
     └─────────────────────────────────┤ (Anthropic / │
          {id, status, title, usage}   │    Local)    │
                                        └──────────────┘

Typical sequence a user will write against:

agent.start("Hello")                         # turn 1
agent.start("Follow up question")            # turn 2
info = managed.retrieve_session()            # ← always safe, always 4 keys
if info["status"] == "idle":
    print(f"Spent {info['usage']['input_tokens']} in / "
          f"{info['usage']['output_tokens']} out tokens "
          f"on session '{info['title'] or info['id']}'")

SDK Source References

File What to read
src/praisonai/praisonai/integrations/_session_info.py SessionInfo dataclass (fields, defaults, to_dict())
src/praisonai/praisonai/integrations/managed_agents.py lines ~565–605 AnthropicManagedAgent.retrieve_session() implementation
src/praisonai/praisonai/integrations/managed_local.py lines ~690–715 LocalManagedAgent.retrieve_session() implementation
src/praisonai-agents/praisonaiagents/managed/__init__.py Lazy re-export of ManagedBackendProtocol
src/praisonai-agents/tests/managed/test_session_info_schema.py 8 tests covering schema equality + empty defaults
src/praisonai-agents/tests/unit/test_managed_backend.py line ~511 test_retrieve_session_no_session (updated expectation)

Acceptance Criteria

  • docs/concepts/managed-agents-local.mdx — "Usage Tracking" and "Persistent Sessions" examples updated to reflect the unified schema (no .get() guards, show status/title).
  • docs/concepts/managed-agents.mdx — "Monitor Resource Usage" accordion and Configuration Options reference the unified schema and praisonaiagents.managed import.
  • docs/features/managed-agents-session-info.mdx — new page created following the draft above, uses Mintlify components (Steps, AccordionGroup, CardGroup), includes hero Mermaid + status-flow Mermaid with the standard color scheme.
  • docs.json — new page added under the Features group only (do not touch Concepts).
  • All code examples run without modification (paste-and-run).
  • All field types and defaults match src/praisonai/praisonai/integrations/_session_info.py exactly.
  • No mention of undocumented fields or undocumented statuses.
  • Page passes the AGENTS.md Quality Checklist (frontmatter, hero diagram, Quick Start Steps, schema table, Best Practices accordions, Related card group).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaudeTrigger Claude Code analysisdocumentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions