Skip to content

Python: fix: DevUI list[Message] input for declarative ToolAgent entry (#6533)#6534

Open
anneheartrecord wants to merge 1 commit into
microsoft:mainfrom
anneheartrecord:fix/6533-devui-list-message-entry
Open

Python: fix: DevUI list[Message] input for declarative ToolAgent entry (#6533)#6534
anneheartrecord wants to merge 1 commit into
microsoft:mainfrom
anneheartrecord:fix/6533-devui-list-message-entry

Conversation

@anneheartrecord

Copy link
Copy Markdown

When a declarative ToolAgent is created, its entry JoinExecutor declares input_types = [dict | str | list[Message] | ...]. DevUI called select_primary_input_type which returned bare Message instead of list[Message], passing a single Message to an executor that expects a list -- causing 'cannot handle message of type Message'.

Root cause: select_primary_input_type iterated over message_types without searching inside the union for list[Message].

Changes:

  • _is_list_message_type: detect list[Message] via get_origin/get_args
  • _find_chat_message_type: recursively searches union members, prefers list[Message] over bare Message
  • select_primary_input_type: use _find_chat_message_type so list[Message] is returned correctly
  • generate_input_schema: return {type: string} for list[Message] so DevUI shows a text box
  • _looks_like_message_dict: distinguish serialised Message payloads from structured workflow inputs
  • parse_input_for_type: handle list[Message] target -- wrap strings/Messages, convert lists of dicts item-by-item, pass structured workflow inputs through unchanged

12 regression tests added; 57 total pass.

Closes #6533

)

When a declarative ToolAgent is created with default settings the
entry JoinExecutor declares `input_types = [dict | str | list[Message]
| ActionTrigger | ...]`.  DevUI called `select_primary_input_type`
which returned bare `Message` instead of `list[Message]`, then passed
a single Message to the executor that expects a list — causing a
"cannot handle message of type Message" runtime error.

Changes:
- Add `_is_list_message_type` helper (GenericAlias cannot be used with
  isinstance; get_origin/get_args required).
- Add `_find_chat_message_type` that recursively searches union members
  and returns `list[Message]` in preference to bare `Message`.
- `select_primary_input_type`: first-pass uses `_find_chat_message_type`
  so the declarative entry type is correctly returned as `list[Message]`.
- `generate_input_schema`: returns `{"type":"string"}` for `list[Message]`
  so DevUI renders a plain text box.
- Add `_looks_like_message_dict` heuristic (role present, type=="message",
  or exactly {"input":...}) to distinguish serialised Message payloads
  from structured workflow inputs without false positives.
- `parse_input_for_type`: handle `list[Message]` target — wrap plain
  strings/Message objects, convert lists of dicts item-by-item, pass
  structured workflow inputs through unchanged.
- Add 12 regression tests (57 total pass).
Copilot AI review requested due to automatic review settings June 16, 2026 06:13
@moonbox3 moonbox3 added the python Issues related to the Python codebase label Jun 16, 2026
@github-actions github-actions Bot changed the title fix: DevUI list[Message] input for declarative ToolAgent entry (#6533) Python: fix: DevUI list[Message] input for declarative ToolAgent entry (#6533) Jun 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR improves DevUI handling of declarative entry executors whose input union includes list[Message], ensuring the UI presents a simple text box while runtime input parsing wraps user text into the expected list[Message] shape.

Changes:

  • Add recursive detection of list[Message] vs Message in select_primary_input_type.
  • Render list[Message] input schemas as a plain JSON {"type":"string"} and parse raw inputs into list[Message].
  • Add regression tests covering schema generation and parse_input_for_type behavior for list[Message].

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
python/packages/devui/agent_framework_devui/_utils.py Adds list[Message] detection, schema rendering as string, and input parsing logic to wrap/convert into list[Message].
python/packages/devui/tests/devui/test_server.py Adds regression tests for select_primary_input_type and parse_input_for_type with list[Message].
python/packages/devui/tests/devui/test_schema_generation.py Adds regression test ensuring list[Message] generates a simple string schema.
Comments suppressed due to low confidence (2)

python/packages/devui/agent_framework_devui/_utils.py:476

  • generate_input_schema and parse_input_for_type accept and are now called with list[Message], which is a types.GenericAlias (not a type) in modern Python. Keeping the parameter annotations as type is misleading for callers and type checkers, and isinstance(input_data, target_type) will raise TypeError for other generic aliases (e.g., list[str]) if they ever get passed in. Updating these signatures to accept Any (or type[Any] | object) and guarding isinstance (only call it when target_type is a real type) would make this API safer and more accurate.
def generate_input_schema(input_type: type) -> dict[str, Any]:

python/packages/devui/agent_framework_devui/_utils.py:536

  • generate_input_schema and parse_input_for_type accept and are now called with list[Message], which is a types.GenericAlias (not a type) in modern Python. Keeping the parameter annotations as type is misleading for callers and type checkers, and isinstance(input_data, target_type) will raise TypeError for other generic aliases (e.g., list[str]) if they ever get passed in. Updating these signatures to accept Any (or type[Any] | object) and guarding isinstance (only call it when target_type is a real type) would make this API safer and more accurate.
def parse_input_for_type(input_data: Any, target_type: type) -> Any:

Comment on lines 583 to 584
if isinstance(input_data, target_type):
return input_data
Comment on lines +575 to +578
parsed_dict = _string_key_dict(input_data)
if parsed_dict is not None:
if parsed_dict and _looks_like_message_dict(parsed_dict):
return [_build_message_from_legacy_payload(parsed_dict)]
return input_data


def _looks_like_message_dict(d: dict[str, Any]) -> bool:
Comment on lines +612 to +616
if d.get("type") == "message":
return True
if "role" in d:
return True
return set(d.keys()) == {"input"}
@anneheartrecord

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

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

Labels

python Issues related to the Python codebase

Projects

None yet

3 participants