Skip to content

Python: [Bug]: Template interpolation rewrites substituted placeholder text #9095

Closed

Description

@ktz03

Description

A declarative SendActivity template can rewrite a substituted value and leave an authored placeholder unresolved when the value contains another placeholder from the template.

For example, with Local.first = "{Local.second}" and Local.second = "B", the authored template {Local.first}|{Local.second} produces B|{Local.second}. The expected output is {Local.second}|B: resolve the two authored placeholders and preserve the substituted text.

interpolate_string finds matches in the original template but applies each replacement to the already-modified string. A later replacement can therefore consume a placeholder introduced by an earlier value instead of the original occurrence. Repeated placeholders have the same problem when their value contains a reference to itself.

Code Sample

import asyncio

from agent_framework_declarative import WorkflowFactory


async def main():
    workflow = WorkflowFactory().create_workflow_from_definition({
        "kind": "Workflow",
        "actions": [
            {"kind": "SetVariable", "variable": "Local.first", "value": "{Local.second}"},
            {"kind": "SetVariable", "variable": "Local.second", "value": "B"},
            {"kind": "SendActivity", "activity": "{Local.first}|{Local.second}"},
        ],
    })
    result = await workflow.run({})
    print(result.get_outputs())


asyncio.run(main())

Expected: ['{Local.second}|B'].

Actual: ['B|{Local.second}'].

The behavior also reproduces with streaming execution and an activity mapping's text field. A template containing only {Local.first} already preserves its value as {Local.second}.

Error Messages / Stack Traces

No exception is raised; the output text is incorrect.

Package Versions

Source checkout at b9d24c8fb484c8330abe8bb9e7500ca3c3bbf46c; declarative package version 1.2.0, core version 1.20.0.

Python Version

Python 3.12.14 on Windows.

Additional Context

This reproducer uses local workflow execution without an external service or model. It concerns directly authored templates; the expression-result behavior addressed by #8509 is a separate path. I have a local fix that substitutes matches at their original template positions while retaining the existing matcher and state-path resolution, and will submit it with regression tests.

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 5, 2026
  2. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Oct 5, 2026
  3. github-actions commented on Oct 5, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    The bug reproduces in python/packages/declarative/agent_framework_declarative/_workflows/_declarative_base.py::DeclarativeWorkflowState.interpolate_string at lines 1007-1010 when a substituted value contains another authored template placeholder. Minimal repro: set Local.first to {Local.second}, set Local.second to B, send {Local.first}|{Local.second}, and assert the output is {Local.second}|B; current output is B|{Local.second}.

    • Failing test: python/packages/declarative/tests/test_graph_executors.py::test_factory_template_interpolation_preserves_substituted_placeholder_text
    • Files examined: python/packages/declarative/agent_framework_declarative/_workflows/_declarative_base.py, python/packages/declarative/agent_framework_declarative/_workflows/_executors_basic.py, python/packages/declarative/tests/test_graph_executors.py, python/packages/declarative/tests/test_workflow_factory.py, python/packages/declarative/pyproject.toml
    • Tests run: python/packages/declarative/tests/test_graph_executors.py::test_factory_template_interpolation_preserves_substituted_placeholder_text, python/packages/declarative/tests/test_graph_executors.py::TestDeclarativeActionExecutor::test_send_activity_executor
    • Reported version: 1.2.0
    • Current version: 1.2.0
  4. added
    declarativeUsage: [Issues, PRs], Target: declarative agents and workflows
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

declarativeUsage: [Issues, PRs], Target: declarative agents and workflowspythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions