docs: Add Turn-time Runtime Resolution feature page and update handoffs#806
Conversation
…fs (fixes #804) - Create docs/features/runtime-resolution.mdx: new feature page covering turn-time runtime resolution for handoffs introduced in PraisonAI PR #2073. Includes hero Mermaid diagram, Quick Start with 3 steps (model swap, cache introspection, custom resolver), sequence diagram showing fallback path, SessionContext/cache constants reference tables, common patterns, and best practices. - Update docs/features/handoffs.mdx: add Dynamic Model Switching section explaining turn-time re-resolution and the fallback guarantee, with a link to the new runtime-resolution page. - Update docs.json: add docs/features/runtime-resolution under the Features group alongside typed-handoffs and handoff-tool-policy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: MervinPraison <454862+MervinPraison@users.noreply.github.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
📝 WalkthroughWalkthroughAdds a new ChangesRuntime Resolution Documentation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
Code Review
This pull request introduces documentation for the "Runtime Resolution" feature, including a new guide and updates to the existing handoffs documentation. The feedback suggests correcting a technical inaccuracy in the documentation where the phrase "raising False" is used instead of "returning False" for a boolean-returning method.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| </Accordion> | ||
|
|
||
| <Accordion title="Implement supports_model narrowly in custom resolvers"> | ||
| Return `False` from `supports_model` for models you do not handle. The built-in `DefaultRuntimeResolver` acts as the final fallback, so raising `False` simply delegates back to it. |
There was a problem hiding this comment.
The phrase "raising False" is technically inaccurate because supports_model returns a boolean value rather than raising an exception. It should be updated to "returning False" to be technically precise.
Return `False` from `supports_model` for models you do not handle. The built-in `DefaultRuntimeResolver` acts as the final fallback, so returning `False` simply delegates back to it.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/features/handoffs.mdx`:
- Around line 173-177: The documentation claim that handoff resolution failures
fall back to chat()/achat() "for any reason" is inaccurate because the code has
conditional fallback behavior. Reword the statement to clarify that only
specific resolution failures (such as ImportError and uninitialized state
RuntimeError) silently fall back to normal chat execution, while configuration
error RuntimeErrors are raised as exceptions and caught by the exception
handler, which returns an error message instead of triggering fallback. This
distinction is important for users to understand when they will see fallback
behavior versus error returns.
In `@docs/features/runtime-resolution.mdx`:
- Around line 282-296: The Python protocol code snippet uses Protocol and Any
without importing them, which will cause runtime errors. Add the required import
statement at the top of the example by importing Protocol and Any from the
typing module. This ensures the RuntimeProtocol and AgentRuntimeProtocol class
definitions can run independently as written in the documentation.
- Around line 8-34: Move the introductory prose text ("Handoffs resolve the
target agent's runtime...") to appear after the Mermaid diagram block instead of
before it, so the hero diagram appears first on the page. Additionally, update
the classDef for the process class to use the prescribed teal color `#189AB4`
instead of the current amber `#F59E0B` fill color. This ensures the process nodes
(Handoff, Resolve Runtime, and Create Runtime) display with the correct color
palette while maintaining the page structure guidelines requiring the hero
diagram to appear first.
- Around line 96-105: The import statements in the runtime resolution example
contain multiple incorrect paths and non-existent symbols. Change the import
path from `praisonaiagents.runtime.resolve` to
`praisonaiagents.runtime.resolver` (the actual module file is named
resolver.py). Move the `SessionContext` import to come from
`praisonaiagents.session` instead of `praisonaiagents.runtime`. Remove the
imports for `set_global_resolver`, `LLMRuntimeWrapper`, and `RuntimeResolver` as
these symbols do not exist in the codebase or are not part of the public API.
Replace these with the correct public API symbols that are actually available in
the praisonaiagents.runtime and praisonaiagents.runtime.resolver modules to
ensure the example code is functional.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7a760f63-480f-4d1d-a475-31b3a6201c5a
📒 Files selected for processing (3)
docs.jsondocs/features/handoffs.mdxdocs/features/runtime-resolution.mdx
| If resolution fails for any reason, handoffs fall back to the target agent's `chat()` / `achat()` so they never break. | ||
|
|
||
| <Card title="Runtime Resolution" icon="rotate" href="/docs/features/runtime-resolution"> | ||
| Cache behaviour, custom resolvers, and introspection API | ||
| </Card> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n -C4 "def _resolve_turn_runtime|chat\(|achat\(|except " praisonaiagents/agent praisonaiagents/runtime -g '*.py'Repository: MervinPraison/PraisonAIDocs
Length of output: 50384
🏁 Script executed:
# Search for _resolve_turn_runtime implementation and surrounding exception handling
rg -n "def _resolve_turn_runtime" --context 20 -A 30 praisonaiagents --type pyRepository: MervinPraison/PraisonAIDocs
Length of output: 2566
🏁 Script executed:
# Search for handoff-related functions and fallback logic
rg -n "fallback.*chat|chat.*fallback|_resolve_turn" praisonaiagents --type py -iRepository: MervinPraison/PraisonAIDocs
Length of output: 1027
🏁 Script executed:
# Look for the handoff method itself to understand the complete flow
rg -n "def handoff|def.*handoff" praisonaiagents --type py -i -A 10Repository: MervinPraison/PraisonAIDocs
Length of output: 17358
🏁 Script executed:
# Get complete exception handling in _resolve_turn_runtime
sed -n '5421,5480p' praisonaiagents/agent/agent.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 2652
🏁 Script executed:
# Search for where _resolve_turn_runtime is called and what happens on failure
rg -n "_resolve_turn_runtime" praisonaiagents --type py -B 2 -A 5Repository: MervinPraison/PraisonAIDocs
Length of output: 1567
🏁 Script executed:
# Check what happens when runtime_instance is None in unified_execution_mixin
sed -n '80,120p' praisonaiagents/agent/unified_execution_mixin.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 2118
🏁 Script executed:
# Search for fallback to chat() in unified execution
rg -n "def execute|async def achat" praisonaiagents/agent/unified_execution_mixin.py -A 30 | head -100Repository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
# Look at the handoff_tool function to see the complete exception handling and fallback
sed -n '776,850p' praisonaiagents/agent/handoff.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 3960
🏁 Script executed:
# Check if there's a try-except that wraps the resolution and falls back to chat()
sed -n '776,900p' praisonaiagents/agent/handoff.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 6189
🏁 Script executed:
# Check the complete exception handling in handoff_tool - get the exact line numbers
sed -n '842,860p' praisonaiagents/agent/handoff.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 1183
🏁 Script executed:
# Verify if the handoff_to and handoff_to_async methods have similar fallback guarantees
sed -n '3917,4000p' praisonaiagents/agent/agent.py | head -100Repository: MervinPraison/PraisonAIDocs
Length of output: 3228
🏁 Script executed:
# Check if the exception from _resolve_turn_runtime is caught anywhere with a fallback
rg -n "_resolve_turn_runtime\|await.*_resolve_turn_runtime" praisonaiagents/agent/unified_execution_mixin.py -A 10 | head -40Repository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
# Look for the complete achat method to see full exception handling
sed -n '40,150p' praisonaiagents/agent/unified_execution_mixin.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 5540
🏁 Script executed:
# Check if _resolve_turn_runtime RuntimeError is caught anywhere
rg -n "try:|except.*RuntimeError|except Exception" praisonaiagents/agent/unified_execution_mixin.py -B 2 -A 2 | head -60Repository: MervinPraison/PraisonAIDocs
Length of output: 2090
🏁 Script executed:
# Check the complete flow in the handoff_tool to see where chat() is called and if it could fail
sed -n '800,860p' praisonaiagents/agent/handoff.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 3460
The fallback claim is too strong — clarify which resolution failures trigger fallback versus error returns.
The text says resolution failures fall back to chat() / achat() "for any reason", but the code distinguishes between silent fallback and exceptions:
ImportError→ returnsNone→ continues with normalchat()(silent fallback)RuntimeErrorwith "not initialized" → returnsNone→ continues with normalchat()(silent fallback)RuntimeErrorwith configuration error → raises exception (lines 5451–5461) → caught by the broadexcept Exceptioninhandoff_tool→ returns error message, not fallback execution
The handoff error handler catches all exceptions but returns an error string rather than falling back to standard execution. Reword to clarify that only specific resolution failures (import/initialization) silently fall back, while configuration errors propagate as caught exceptions.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/features/handoffs.mdx` around lines 173 - 177, The documentation claim
that handoff resolution failures fall back to chat()/achat() "for any reason" is
inaccurate because the code has conditional fallback behavior. Reword the
statement to clarify that only specific resolution failures (such as ImportError
and uninitialized state RuntimeError) silently fall back to normal chat
execution, while configuration error RuntimeErrors are raised as exceptions and
caught by the exception handler, which returns an error message instead of
triggering fallback. This distinction is important for users to understand when
they will see fallback behavior versus error returns.
| Handoffs resolve the target agent's runtime at the moment of execution — if you change a sub-agent's model between turns, the next handoff uses the new model automatically. | ||
|
|
||
| ```mermaid | ||
| graph LR | ||
| subgraph "Turn-time Runtime Resolution" | ||
| A[🤖 Parent Agent] --> B{🔄 Handoff} | ||
| B --> C[🔍 Resolve Runtime] | ||
| C --> D[(Cache)] | ||
| D -->|hit| E[✅ Execute] | ||
| D -->|miss| F[🏗️ Create Runtime] | ||
| F --> E | ||
| C -->|error| G[⚡ Fallback chat] | ||
| G --> E | ||
| end | ||
|
|
||
| classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff | ||
| classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff | ||
| classDef cache fill:#189AB4,stroke:#7C90A0,color:#fff | ||
| classDef success fill:#10B981,stroke:#7C90A0,color:#fff | ||
| classDef fallback fill:#6366F1,stroke:#7C90A0,color:#fff | ||
|
|
||
| class A agent | ||
| class B,C,F process | ||
| class D cache | ||
| class E success | ||
| class G fallback | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Start with the hero diagram and use the required palette.
The page currently begins with prose before the hero block, and the process nodes are amber instead of the required teal #189AB4. Please move the intro below the hero diagram and update the process class to the prescribed palette. As per coding guidelines, docs pages should start with the hero Mermaid diagram and use the exact color scheme.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/features/runtime-resolution.mdx` around lines 8 - 34, Move the
introductory prose text ("Handoffs resolve the target agent's runtime...") to
appear after the Mermaid diagram block instead of before it, so the hero diagram
appears first on the page. Additionally, update the classDef for the process
class to use the prescribed teal color `#189AB4` instead of the current amber
`#F59E0B` fill color. This ensures the process nodes (Handoff, Resolve Runtime,
and Create Runtime) display with the correct color palette while maintaining the
page structure guidelines requiring the hero diagram to appear first.
Source: Coding guidelines
| from praisonaiagents.runtime import ( | ||
| set_global_resolver, | ||
| SessionContext, | ||
| ) | ||
| from praisonaiagents.runtime.resolve import ( | ||
| RuntimeResolver, | ||
| AgentRuntimeProtocol, | ||
| LLMRuntimeWrapper, | ||
| ) | ||
| from praisonaiagents.llm.llm import LLM |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔴 Critical
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n "set_global_resolver|SessionContext|RuntimeResolver|AgentRuntimeProtocol|LLMRuntimeWrapper" praisonaiagents/runtime praisonaiagents -g '*.py'Repository: MervinPraison/PraisonAIDocs
Length of output: 5203
🏁 Script executed:
cat -n praisonaiagents/runtime/__init__.py | head -120Repository: MervinPraison/PraisonAIDocs
Length of output: 6406
🏁 Script executed:
rg -n "LLMRuntimeWrapper" praisonaiagents -g '*.py' -A 2Repository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
ls -la praisonaiagents/runtime/ | grep -E '\.py$'Repository: MervinPraison/PraisonAIDocs
Length of output: 1306
🏁 Script executed:
cat -n docs/features/runtime-resolution.mdx | sed -n '96,105p'Repository: MervinPraison/PraisonAIDocs
Length of output: 478
🏁 Script executed:
cat -n praisonaiagents/runtime/__init__.py | sed -n '120,160p'Repository: MervinPraison/PraisonAIDocs
Length of output: 2105
🏁 Script executed:
rg -rn "class LLMRuntimeWrapper|def LLMRuntimeWrapper" praisonaiagentsRepository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
fd "resolve" praisonaiagents/runtime -type fRepository: MervinPraison/PraisonAIDocs
Length of output: 336
🏁 Script executed:
rg -n "RuntimeResolver|LLMRuntimeWrapper|set_global_resolver" praisonaiagents/runtime/ -g '*.py'Repository: MervinPraison/PraisonAIDocs
Length of output: 304
🏁 Script executed:
grep -r "set_global_resolver\|SessionContext" praisonaiagents/runtime/__init__.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
grep -n "from.*resolver" praisonaiagents/runtime/__init__.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
rg -n "set_global_resolver" praisonaiagents -g '*.py'Repository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
cat -n praisonaiagents/session/__init__.py | head -150Repository: MervinPraison/PraisonAIDocs
Length of output: 6112
🏁 Script executed:
rg -n "LLMRuntimeWrapper" praisonaiagents -A 3 -B 1Repository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
cat -n praisonaiagents/runtime/resolver.py | head -70Repository: MervinPraison/PraisonAIDocs
Length of output: 3040
🏁 Script executed:
rg "export|__all__" praisonaiagents/runtime/resolver.pyRepository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
python3 << 'PY'
# Check what's actually in the resolver.py and if set_global_resolver exists
import re
with open('praisonaiagents/runtime/resolver.py', 'r') as f:
content = f.read()
# Find all top-level defs and classes
matches = re.findall(r'^(def|class)\s+(\w+)', content, re.MULTILINE)
print("Top-level definitions in resolver.py:")
for kind, name in matches:
print(f" {kind} {name}")
PYRepository: MervinPraison/PraisonAIDocs
Length of output: 292
🏁 Script executed:
# Check if set_global_resolver, LLMRuntimeWrapper might be in other modules
rg "set_global_resolver|LLMRuntimeWrapper" praisonaiagents --type pyRepository: MervinPraison/PraisonAIDocs
Length of output: 165
🏁 Script executed:
# Double check if resolve.py exists anywhere
find praisonaiagents -name "*resolve*" -type fRepository: MervinPraison/PraisonAIDocs
Length of output: 277
🏁 Script executed:
cat -n praisonaiagents/config/resolver.py | head -50Repository: MervinPraison/PraisonAIDocs
Length of output: 2255
🏁 Script executed:
# Let's check what the actual correct imports should be by looking at what's exported
# from praisonaiagents.runtime and verify which symbols actually exist
python3 << 'PY'
import sys
# Check if RuntimeResolver can be imported from runtime
try:
from praisonaiagents.runtime.resolver import RuntimeResolver
print("✓ RuntimeResolver found in praisonaiagents.runtime.resolver")
except ImportError as e:
print(f"✗ RuntimeResolver not found in praisonaiagents.runtime.resolver: {e}")
# Check if it's exported from public runtime API
try:
from praisonaiagents.runtime import RuntimeResolver
print("✓ RuntimeResolver exported from public praisonaiagents.runtime")
except (ImportError, AttributeError) as e:
print(f"✗ RuntimeResolver not in public praisonaiagents.runtime: {e}")
# Check SessionContext
try:
from praisonaiagents.runtime import SessionContext
print("✓ SessionContext exported from praisonaiagents.runtime")
except (ImportError, AttributeError) as e:
print(f"✗ SessionContext not in praisonaiagents.runtime: {e}")
# Check SessionContext from session
try:
from praisonaiagents.session import SessionContext
print("✓ SessionContext exported from praisonaiagents.session")
except (ImportError, AttributeError) as e:
print(f"✗ SessionContext not in praisonaiagents.session: {e}")
# Check for set_global_resolver anywhere
try:
from praisonaiagents.runtime import set_global_resolver
print("✓ set_global_resolver in praisonaiagents.runtime")
except (ImportError, AttributeError) as e:
print(f"✗ set_global_resolver not found: {e}")
# Check for LLMRuntimeWrapper
try:
from praisonaiagents.runtime.resolver import LLMRuntimeWrapper
print("✓ LLMRuntimeWrapper in praisonaiagents.runtime.resolver")
except (ImportError, AttributeError) as e:
print(f"✗ LLMRuntimeWrapper not found: {e}")
# Check if resolve.py exists as a module
try:
from praisonaiagents.runtime import resolve
print("✓ praisonaiagents.runtime.resolve module exists")
except (ImportError, AttributeError) as e:
print(f"✗ praisonaiagents.runtime.resolve doesn't exist: {e}")
PYRepository: MervinPraison/PraisonAIDocs
Length of output: 1130
Fix import paths and verify symbol existence in the runtime resolution example.
The code at lines 96-105 has multiple critical issues:
- Module path
praisonaiagents.runtime.resolvedoesn't exist (the file isresolver.py, notresolve.py) set_global_resolverdoes not exist in the codebaseLLMRuntimeWrapperdoes not exist inpraisonaiagents.runtime.resolverSessionContextis exported frompraisonaiagents.session, notpraisonaiagents.runtimeRuntimeResolveris not part of the publicpraisonaiagents.runtimeAPI exports
The example code will fail on import. Correct the paths to use public APIs where available, or if these symbols are intentionally internal, use a different example that demonstrates the public resolver API.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/features/runtime-resolution.mdx` around lines 96 - 105, The import
statements in the runtime resolution example contain multiple incorrect paths
and non-existent symbols. Change the import path from
`praisonaiagents.runtime.resolve` to `praisonaiagents.runtime.resolver` (the
actual module file is named resolver.py). Move the `SessionContext` import to
come from `praisonaiagents.session` instead of `praisonaiagents.runtime`. Remove
the imports for `set_global_resolver`, `LLMRuntimeWrapper`, and
`RuntimeResolver` as these symbols do not exist in the codebase or are not part
of the public API. Replace these with the correct public API symbols that are
actually available in the praisonaiagents.runtime and
praisonaiagents.runtime.resolver modules to ensure the example code is
functional.
Source: Coding guidelines
| ```python | ||
| class RuntimeProtocol(Protocol): | ||
| def execute(self, prompt: str, **kwargs) -> Any: ... | ||
| async def aexecute(self, prompt: str, **kwargs) -> Any: ... | ||
| @property | ||
| def model_ref(self) -> str: ... | ||
| @property | ||
| def provider(self) -> str: ... | ||
|
|
||
| class AgentRuntimeProtocol(RuntimeProtocol): | ||
| @property | ||
| def supports_streaming(self) -> bool: ... | ||
| @property | ||
| def supports_tools(self) -> bool: ... | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Add the missing typing imports to the protocol snippet.
Protocol and Any are used here but never imported, so this example won't run as written. As per coding guidelines, every Python example must include the imports it needs and run without modification.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/features/runtime-resolution.mdx` around lines 282 - 296, The Python
protocol code snippet uses Protocol and Any without importing them, which will
cause runtime errors. Add the required import statement at the top of the
example by importing Protocol and Any from the typing module. This ensures the
RuntimeProtocol and AgentRuntimeProtocol class definitions can run independently
as written in the documentation.
Source: Coding guidelines
Fixes #804. Creates docs/features/runtime-resolution.mdx (new feature page following AGENTS.md template), updates docs/features/handoffs.mdx with Dynamic Model Switching section, and adds the new page to docs.json. Generated with Claude Code.
Summary by CodeRabbit