Skip to content

fix: bug of the prompts can't render in each other#1

Merged
mohamed-em2m merged 2 commits into
mainfrom
fix/rendering-inner-prompts
May 22, 2026
Merged

fix: bug of the prompts can't render in each other#1
mohamed-em2m merged 2 commits into
mainfrom
fix/rendering-inner-prompts

Conversation

@mohamed-em2m
Copy link
Copy Markdown
Owner

@mohamed-em2m mohamed-em2m commented May 22, 2026

  • rendering prompts or sub prompts into each other to add more ability to divide long prompt or the common prompts into sub sections files

Summary by cubic

Enable nested prompt rendering in Jinja so prompts can include other prompts by name or via a prompts[...] proxy. Adds recursion protection, fixes synchronous rendering, and tightens directory scanning to make nested usage safe and reliable.

  • New Features

    • Support nested rendering with {{ customer_service }} or prompts['child'] using a new PromptsProxy.
    • Pass store and parent_context into PromptNode to enable lazy sub-prompt resolution.
  • Bug Fixes

    • Block circular includes via a context-based render stack; cycles render a safe placeholder instead of crashing.
    • Fix .render() so nested prompts resolve consistently (with or without auto_render), and skip hidden/env/cache folders during scan (.*, __pycache__, venv, env, dynaprompt).

Additional updates: docs and examples demonstrating nested prompts; debug_render.py helper for local testing.

Written for commit aecaed2. Summary will update on new commits. Review in cubic

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="pyproject.toml">

<violation number="1" location="pyproject.toml:46">
P2: pytest is a test framework and should not be a runtime dependency. Remove it from `dependencies` — it is already listed under `[dependency-groups]` dev.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread pyproject.toml
@@ -43,6 +43,7 @@ dependencies = [
"pyyaml>=6.0.0",
"tomli>=2.0.1; python_version < '3.11'",
"pydantic>=2.0.0",
"pytest>=8.4.2",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: pytest is a test framework and should not be a runtime dependency. Remove it from dependencies — it is already listed under [dependency-groups] dev.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pyproject.toml, line 46:

<comment>pytest is a test framework and should not be a runtime dependency. Remove it from `dependencies` — it is already listed under `[dependency-groups]` dev.</comment>

<file context>
@@ -43,6 +43,7 @@ dependencies = [
     "pyyaml>=6.0.0",
     "tomli>=2.0.1; python_version < '3.11'",
     "pydantic>=2.0.0",
+    "pytest>=8.4.2",
 ]
 keywords = [
</file context>

@mohamed-em2m mohamed-em2m merged commit 1d38428 into main May 22, 2026
9 checks passed
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 issues found

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="dynaprompt/engine/resolver.py">

<violation number="1" location="dynaprompt/engine/resolver.py:44">
P2: The `"dynaprompt"` exclusion is overly broad and may silently skip legitimate prompt files stored in a subdirectory named `dynaprompt`. This is the library's own name, not a standard system/environment directory like `__pycache__` or `venv`. Consider removing it from the exclusion list.</violation>
</file>

<file name="prompts/docs_api_reference_2_2.md">

<violation number="1" location="prompts/docs_api_reference_2_2.md:29">
P2: The `invoke` method does not exist on `PromptNode`. mkdocstrings will produce a warning or empty documentation for this non-existent member.</violation>
</file>

<file name="prompts/docs.advanced.debugging.md">

<violation number="1" location="prompts/docs.advanced.debugging.md:79">
P2: Replace deprecated `datetime.utcnow()` with `datetime.now(datetime.timezone.utc)` in the example code. `datetime.utcnow()` was deprecated in Python 3.12 and should not be used in documentation examples that users may copy.</violation>
</file>

<file name="prompts/docs.advanced.hooks.md">

<violation number="1" location="prompts/docs.advanced.hooks.md:122">
P2: Custom validator example and lifecycle diagram use `validate(node, rendered)` but the actual `PromptValidator.validate` signature is `validate(self, prompt_node, kwargs, current_env)`. The custom validator inheriting from `PromptValidator` will not work as shown — `rendered` will receive `kwargs` (a dict), so `rendered.text` would raise an AttributeError. Update the example and diagram to match the actual signature.</violation>
</file>

<file name="prompts/docs_advanced_async_2.md">

<violation number="1" location="prompts/docs_advanced_async_2.md:86">
P1: The `prompts.add_hook("before_render", "inject_context", async_inject_context)` call registers the hook under key `"before_render_inject_context"`, but the `async_hookable` dispatch for `async_render()` looks for `"before_async_render"`. The hook will silently never fire.</violation>
</file>

<file name="prompts/docs_advanced_environments_2.md">

<violation number="1" location="prompts/docs_advanced_environments_2.md:113">
P2: Debug trace output contradicts the TOML configuration: production sets `max_tokens = 4096`, but the debug trace shows `max_tokens = 1024 (from default)` while production is marked ACTIVE.</violation>
</file>

<file name="prompts/docs_advanced_environments_2_2_2.md">

<violation number="1" location="prompts/docs_advanced_environments_2_2_2.md:100">
P3: debug_trace() output shown in the documentation does not match the actual implementation output. Users following the docs will expect this format but will see a different visualization.</violation>
</file>

<file name="prompts/docs_advanced_hooks.md">

<violation number="1" location="prompts/docs_advanced_hooks.md:118">
P2: `TiktokenValidator.__init__` should call `super().__init__()` to properly initialize the `PromptValidator` base class. Without it, any setup that the base class performs (storing name patterns, validation rules, env gates, etc.) is skipped, which can cause runtime attribute errors or incorrect behavior.</violation>
</file>

<file name="prompts/docs_api_reference.md">

<violation number="1" location="prompts/docs_api_reference.md:29">
P1: The `invoke` member listed for `PromptNode` does not exist on the class. This will cause mkdocstrings to fail during documentation build.</violation>
</file>

<file name="prompts/docs_advanced_debugging_2.md">

<violation number="1" location="prompts/docs_advanced_debugging_2.md:72">
P2: The `prompt_hash` documentation is inaccurate: the hash is a 12-character truncation of the SHA-256 digest (not a full hash), and it is computed over `text`, `config`, and `schema_json` combined (not just `rendered.text`). Update the docs to match the actual implementation so users designing audit trails, test assertions, or version checks have correct expectations.</violation>
</file>

<file name="prompts/docs.schemas.md">

<violation number="1" location="prompts/docs.schemas.md:7">
P3: Document YAML schema loading here as well; the current text is incomplete and misleads users about supported schema files.</violation>

<violation number="2" location="prompts/docs.schemas.md:46">
P3: Remove the `register()` mention; this API does not exist in the repository.</violation>
</file>

<file name="prompts/docs_advanced_async.md">

<violation number="1" location="prompts/docs_advanced_async.md:70">
P2: Don't present `@async_hookable` as the way to attach async hooks, and don't show a before-render hook mutating kwargs here. As written, the example won't affect the render context.</violation>

<violation number="2" location="prompts/docs_advanced_async.md:106">
P2: Don't claim `render()` and `async_render()` are fully interchangeable. The sync path can't await async hooks, so they diverge as soon as a prompt uses coroutine hooks.</violation>
</file>

<file name="prompts/docs_advanced_hooks_2_2_2.md">

<violation number="1" location="prompts/docs_advanced_hooks_2_2_2.md:122">
P1: The `TiktokenValidator.validate` method signature `(self, node, rendered)` does not match the framework's actual `PromptValidator.validate` signature `(self, prompt_node, kwargs, current_env="default")`. The second argument is a `kwargs` dict (render variables), not a rendered result object, so `rendered.text` would raise an `AttributeError` at runtime.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 100 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.

Re-trigger cubic

kwargs["user_name"] = user_data["name"]
return kwargs

prompts.add_hook("before_render", "inject_context", async_inject_context)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The prompts.add_hook("before_render", "inject_context", async_inject_context) call registers the hook under key "before_render_inject_context", but the async_hookable dispatch for async_render() looks for "before_async_render". The hook will silently never fire.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_advanced_async_2.md, line 86:

<comment>The `prompts.add_hook("before_render", "inject_context", async_inject_context)` call registers the hook under key `"before_render_inject_context"`, but the `async_hookable` dispatch for `async_render()` looks for `"before_async_render"`. The hook will silently never fire.</comment>

<file context>
@@ -0,0 +1,106 @@
+    kwargs["user_name"] = user_data["name"]
+    return kwargs
+
+prompts.add_hook("before_render", "inject_context", async_inject_context)
+
+rendered = await prompts.chat.async_render(user_id="123")
</file context>

- async_render
- rerender
- async_rerender
- invoke
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The invoke member listed for PromptNode does not exist on the class. This will cause mkdocstrings to fail during documentation build.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_api_reference.md, line 29:

<comment>The `invoke` member listed for `PromptNode` does not exist on the class. This will cause mkdocstrings to fail during documentation build.</comment>

<file context>
@@ -0,0 +1,37 @@
+        - async_render
+        - rerender
+        - async_rerender
+        - invoke
+
+::: dynaprompt.nodes.RenderedPrompt
</file context>

self.max_tokens = max_tokens
self.enc = tiktoken.encoding_for_model(model)

def validate(self, node, rendered) -> None:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The TiktokenValidator.validate method signature (self, node, rendered) does not match the framework's actual PromptValidator.validate signature (self, prompt_node, kwargs, current_env="default"). The second argument is a kwargs dict (render variables), not a rendered result object, so rendered.text would raise an AttributeError at runtime.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_advanced_hooks_2_2_2.md, line 122:

<comment>The `TiktokenValidator.validate` method signature `(self, node, rendered)` does not match the framework's actual `PromptValidator.validate` signature `(self, prompt_node, kwargs, current_env="default")`. The second argument is a `kwargs` dict (render variables), not a rendered result object, so `rendered.text` would raise an `AttributeError` at runtime.</comment>

<file context>
@@ -0,0 +1,155 @@
+        self.max_tokens = max_tokens
+        self.enc = tiktoken.encoding_for_model(model)
+
+    def validate(self, node, rendered) -> None:
+        token_count = len(self.enc.encode(rendered.text))
+        if token_count > self.max_tokens:
</file context>

rel_parts = child.relative_to(directory).parts
if any(
part.startswith(".")
or part in ("__pycache__", "venv", "env", "dynaprompt")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The "dynaprompt" exclusion is overly broad and may silently skip legitimate prompt files stored in a subdirectory named dynaprompt. This is the library's own name, not a standard system/environment directory like __pycache__ or venv. Consider removing it from the exclusion list.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At dynaprompt/engine/resolver.py, line 44:

<comment>The `"dynaprompt"` exclusion is overly broad and may silently skip legitimate prompt files stored in a subdirectory named `dynaprompt`. This is the library's own name, not a standard system/environment directory like `__pycache__` or `venv`. Consider removing it from the exclusion list.</comment>

<file context>
@@ -37,6 +37,15 @@ def scan_directory(
+            rel_parts = child.relative_to(directory).parts
+            if any(
+                part.startswith(".")
+                or part in ("__pycache__", "venv", "env", "dynaprompt")
+                for part in rel_parts
+            ):
</file context>

- async_render
- rerender
- async_rerender
- invoke
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The invoke method does not exist on PromptNode. mkdocstrings will produce a warning or empty documentation for this non-existent member.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_api_reference_2_2.md, line 29:

<comment>The `invoke` method does not exist on `PromptNode`. mkdocstrings will produce a warning or empty documentation for this non-existent member.</comment>

<file context>
@@ -0,0 +1,37 @@
+        - async_render
+        - rerender
+        - async_rerender
+        - invoke
+
+::: dynaprompt.nodes.RenderedPrompt
</file context>


## Async Hooks

You can also attach async hooks using `@async_hookable`. This is useful for:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Don't present @async_hookable as the way to attach async hooks, and don't show a before-render hook mutating kwargs here. As written, the example won't affect the render context.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_advanced_async.md, line 70:

<comment>Don't present `@async_hookable` as the way to attach async hooks, and don't show a before-render hook mutating kwargs here. As written, the example won't affect the render context.</comment>

<file context>
@@ -0,0 +1,106 @@
+
+## Async Hooks
+
+You can also attach async hooks using `@async_hookable`. This is useful for:
+- Calling an async PII redaction service before rendering
+- Logging to an async audit trail after rendering
</file context>

---

!!! tip "Sync is still supported"
`async_render()` and `render()` are fully interchangeable. Use sync in scripts and tests, async in web servers and agents.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Don't claim render() and async_render() are fully interchangeable. The sync path can't await async hooks, so they diverge as soon as a prompt uses coroutine hooks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_advanced_async.md, line 106:

<comment>Don't claim `render()` and `async_render()` are fully interchangeable. The sync path can't await async hooks, so they diverge as soon as a prompt uses coroutine hooks.</comment>

<file context>
@@ -0,0 +1,106 @@
+---
+
+!!! tip "Sync is still supported"
+    `async_render()` and `render()` are fully interchangeable. Use sync in scripts and tests, async in web servers and agents.
</file context>


**Output:**
```
🔍 Debug Trace for: analyzer
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: debug_trace() output shown in the documentation does not match the actual implementation output. Users following the docs will expect this format but will see a different visualization.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs_advanced_environments_2_2_2.md, line 100:

<comment>debug_trace() output shown in the documentation does not match the actual implementation output. Users following the docs will expect this format but will see a different visualization.</comment>

<file context>
@@ -0,0 +1,120 @@
+
+**Output:**
+```
+🔍 Debug Trace for: analyzer
+──────────────────────────────────
+Layer: default
</file context>

Comment thread prompts/docs.schemas.md

## How it works

When you pass a list of files or a directory to `settings_files`, DynaPrompt scans for `.py` and `.json` files.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Document YAML schema loading here as well; the current text is incomplete and misleads users about supported schema files.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs.schemas.md, line 7:

<comment>Document YAML schema loading here as well; the current text is incomplete and misleads users about supported schema files.</comment>

<file context>
@@ -0,0 +1,57 @@
+
+## How it works
+
+When you pass a list of files or a directory to `settings_files`, DynaPrompt scans for `.py` and `.json` files.
+
+### 1. Python Schemas (.py)
</file context>
Suggested change
When you pass a list of files or a directory to `settings_files`, DynaPrompt scans for `.py` and `.json` files.
When you pass a list of files or a directory to `settings_files`, DynaPrompt scans for `.py`, `.json`, `.yaml`, and `.yml` files.

Comment thread prompts/docs.schemas.md

## Referencing Schemas in Prompts

Once a schema is registered (either automatically or via `register()`), you can reference it by its string name in your prompt frontmatter.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Remove the register() mention; this API does not exist in the repository.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At prompts/docs.schemas.md, line 46:

<comment>Remove the `register()` mention; this API does not exist in the repository.</comment>

<file context>
@@ -0,0 +1,57 @@
+
+## Referencing Schemas in Prompts
+
+Once a schema is registered (either automatically or via `register()`), you can reference it by its string name in your prompt frontmatter.
+
+**Example (`prompt.md`):**
</file context>
Suggested change
Once a schema is registered (either automatically or via `register()`), you can reference it by its string name in your prompt frontmatter.
Once a schema is loaded, you can reference it by its string name in your prompt frontmatter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant