Skip to content

Parse AI behavior actionParams into typed models#417

Merged
mocha06 merged 1 commit into
devfrom
rc-dev/feat/typed-behavior-params
Jul 17, 2026
Merged

Parse AI behavior actionParams into typed models#417
mocha06 merged 1 commit into
devfrom
rc-dev/feat/typed-behavior-params

Conversation

@mocha06

@mocha06 mocha06 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Motivation

BehaviorInput.action_params was a raw dict | None, and every consumer re-walked it with dual-alias branches (aiBehaviorParams/ai_behavior_params, actionsAttributes/actions_attributes): the model validator, the SDK preflight and pipe/phase-transition checks, and MCP helpers such as the pipe-ID extraction. That duplicated dict-walking contradicts the repo's "parse, don't validate" / self-guaranteeing-types rules and multiplies as more fields are added to the payload.

Outcome

action_params is now a typed Pydantic model (AiBehaviorActionParamsAiBehaviorParams → action and capability attributes) with per-declared-field camelCase aliases matching the GraphQL input schema and extra="allow" so unknown/sibling keys pass through verbatim. Every consumer parses once and reads typed attributes, so no dual-alias branches remain in SDK or MCP agent code paths.

Behavior is unchanged for every payload that was already valid end-to-end. snake_case inner keys — which the API always rejected while the toolkit's dual-alias branches accepted them — are now normalized to the declared wire names, so that input works for the first time. Aliasing is strictly per declared field (never a blanket snake→camel pass, which would corrupt genuinely snake_case siblings like card_id/to_phase_id), and action metadata stays a pass-through dict so GET→update round-trips serialize identically.

Tested e2e a few times

image

No new validation rules land here — capability and provider hardening build on this typed base.

Closes #416.

Replace the raw dict | None action_params and its dual-alias dict-walking
(aiBehaviorParams/ai_behavior_params, actionsAttributes/actions_attributes)
with nested Pydantic models carrying per-declared-field camelCase aliases and
extra=allow. Consumers parse once and read typed attributes; no dual-alias
branches remain in SDK or MCP agent code paths. snake_case inner keys now
normalize to the declared wire names, and action metadata stays a pass-through
dict so GET-update round-trips serialize identically. No new validation rules.

Closes #416.

@adriannoes adriannoes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Summary

Solid prep PR for typed behavior actionParams.

Nested models with per-field aliases replace the dual-alias dict walks without changing valid end-to-end wire payloads, and capability/provider hardening correctly stays out of scope for #424. Review ran checkout plus local tests (2922 passed, ruff green); CI lint and test are green.

What worked well

Per-field camelCase aliases with extra="allow" keep AutomationActionParams siblings (card_id, to_phase_id) intact while normalizing declared AI-behavior keys. Lenient BehaviorPayload reads versus strict BehaviorInput writes is a clean split, and the slug-resolve path deep-copies before parse so caller metadata is not mutated through pydantic references.

Also noted

  • The public resolve_and_populate_field_refs helper early-returns without rewriting keys when no slug fetch runs, while populate_referenced_field_ids now only reads declared camelCase names. In-repo MCP/CLI/facade paths already model_dump(by_alias=True) first, so they stay correct. If that helper remains a supported entry point for raw snake_case dicts, normalizing on every exit (or documenting dump-first) would match #416's "normalize at the entry edge" wording.

@mocha06
mocha06 merged commit 0e9328e into dev Jul 17, 2026
2 checks passed
@mocha06
mocha06 deleted the rc-dev/feat/typed-behavior-params branch July 17, 2026 14:21
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.

2 participants