Skip to content

PR 10: Narrow meta-tool JSON coercion#314

Merged
dsarno merged 2 commits into
betafrom
claude/pr-10-meta-tool-json-coercion-narrow
May 4, 2026
Merged

PR 10: Narrow meta-tool JSON coercion#314
dsarno merged 2 commits into
betafrom
claude/pr-10-meta-tool-json-coercion-narrow

Conversation

@dsarno

@dsarno dsarno commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Base: beta

Addresses issue #297 finding #8 by narrowing nested JSON-string coercion in dispatch_manage_op().

The new policy is annotation-aware:

  • Decode JSON-shaped nested strings only when the selected handler parameter expects a list/dict-like value.
  • Preserve JSON-shaped strings unchanged when the handler parameter expects str.
  • Raise GodotCommandError(ErrorCode.INVALID_PARAMS) for malformed JSON-shaped text or wrong JSON container type when the handler expects list/dict-like params, with data including tool, op, and param.
  • Preserve existing handler TypeError wrapping for missing/extra arguments.

Compatibility is preserved for clients that stringify top-level manage params and for nested stringified list/dict values where the target handler annotation expects those containers.

PR 9 is being worked in parallel and this PR intentionally does not touch the GDScript self-update preload-alias scope.

Test Plan

  • ruff check src/ tests/
  • pytest -v (766 passed)
  • pytest -q tests/unit/test_meta_tool.py tests/unit/test_middleware_parse_stringified_params.py tests/unit/test_middleware_op_typo_hint.py (36 passed)
  • script/ci-check-gdscript
  • script/ci-godot-tests attempted locally; it found a Godot session, then exited with curl code 7 while opening main.tscn. A follow-up probe showed no MCP server responding on 127.0.0.1:8000.

Out of Scope

@codecov

codecov Bot commented May 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.10526% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/godot_ai/tools/_meta_tool.py 92.10% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

- Cache (signature, type_hints) per handler via _handler_meta — both ran
  on every dispatch before; handlers live for process lifetime so an
  unbounded functools.cache is safe.
- Drop tuple from _json_container_kinds list-acceptors. json.loads only
  produces list, never tuple, so a tuple-annotated param could not be
  satisfied by coercion anyway.
- Rename _json_container_prefix to _is_json_shaped and return bool —
  the prefix value was never consumed, only truth-tested.
- Document the empty-set "do not coerce" policy on _json_container_kinds
  so a future reader does not "fix" the unannotated bypass.
- Add a regression test for list[str] | None covering the Union branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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