Skip to content

Python: [Bug]: Workflow build rejects an edge from an executor that sends a Literal type to one that handles str #9354

Closed

Description

Observed Behavior

An executor whose handler sends a Literal type, for example WorkflowContext[Literal["approve", "reject"]], cannot be connected to an executor that handles str. WorkflowBuilder.build() raises TypeCompatibilityError, because the edge type check is_type_compatible(Literal["approve", "reject"], str) returns False.

Routing on a fixed set of values is a common pattern (decisions, labels, states), and the runtime check already accepts these messages: is_instance_of handles Literal since #8351. Only the build-time edge validation rejects the workflow.

Expected Behavior

A Literal source type is compatible with a target type when every literal value fits the target, as static type checkers treat it: Literal["approve", "reject"] fits str, Literal["a", 1] fits str | int, and Literal["a"] fits Literal["a", "b"]. A plain str still does not fit a Literal target.

Steps to Reproduce

  1. Create an executor whose handler declares WorkflowContext[Literal["approve", "reject"]].
  2. Connect it to an executor whose handler takes str.
  3. Build the workflow.

Minimal Reproduction

import asyncio
from typing import Literal

from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler


class Reviewer(Executor):
    @handler
    async def review(self, text: str, ctx: WorkflowContext[Literal["approve", "reject"]]) -> None:
        await ctx.send_message("approve")


class Publisher(Executor):
    @handler
    async def publish(self, decision: str, ctx: WorkflowContext[str, str]) -> None:
        await ctx.yield_output(f"decision: {decision}")


reviewer = Reviewer(id="reviewer")
publisher = Publisher(id="publisher")
workflow = WorkflowBuilder(start_executor=reviewer).add_edge(reviewer, publisher).build()  # raises
print(asyncio.run(workflow.run("draft")).get_outputs())

The cause is in agent_framework/_workflows/_typing_utils.py, is_type_compatible: a Literal source has origin typing.Literal, which is not a class, so no case matches and the "different container types" case returns False.

Error Messages and Stack Traces

agent_framework._workflows._validation.TypeCompatibilityError: [TYPE_COMPATIBILITY] Type incompatibility between executors 'reviewer' -> 'publisher'. Source executor outputs types ["typing.Literal['approve', 'reject']"] but target executor can only handle types ["<class 'str'>"].

Package Versions

agent-framework-core: 1.21.0 (main at 1b9879c)

Python Version

Python 3.12

Additional Context

I'd like to fix this. The change is a short case in is_type_compatible: a Literal source is compatible when every value fits the target (by value for a Literal target, as is_instance_of does, and through the value's own type otherwise). Plus regression tests.

AI assistance: I used an AI coding assistant for the analysis and to draft this report. I reproduced and verified the behavior myself.

Metadata

Metadata

Labels

pythonUsage: [Issues, PRs], Target: Python

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions