Skip to content

dynamic_choices - #19

Merged
alain-sv merged 15 commits into
developfrom
dynamic_choices
Apr 8, 2026
Merged

dynamic_choices#19
alain-sv merged 15 commits into
developfrom
dynamic_choices

Conversation

@alain-sv

@alain-sv alain-sv commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

What did

Added dynamic support for AgentMethodField and wired a get_dynamic_choices callback into Agent- Implemented a new //dynamic_choices HTTP endpoint and integrated it into the example controller template- Added comprehensive unit tests covering serialization, endpoint behavior, multiple-key assertions, and runtime behavior- Refactored agent.py and dynamic_choices routes/tests: removed dead return-type union, dropped unused params, strengthened assertions, and renamed tests- Updated changelog and docs with the dynamic choices feature and link

Why

To support runtime-populated choice fields for agent methods, enabling UI/components to fetch up-to-date options from the agent at start time.

How

tested- tests verifying:
-_choices field serialization in fieldsinitions - get_dynamic_choices endpoint behavior and returned values (including multi-key cases)

  • end-to-end wiring in the example controller template### Risks or trade-offs- None significant; refactors removed dead types and unused test params, and tests to reduce flakiness.

alain-sv and others added 10 commits April 8, 2026 19:03
- Remove dead `| JSONResponse` union from `get_dynamic_choices` return type (endpoint never returns JSONResponse, only raises HTTPException or returns dict)
- Drop unused `mocker: Any` params from all five dynamic_choices route tests
- Strengthen `test_dynamic_choices_endpoint_multiple_keys` to assert values, not just key presence
- Rename two misleading test_agent.py tests: `non_choice_field` → `optional_choice_field`, `returns_empty` → `dispatches_by_method_name`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add dynamic choices support for AgentMethodField with runtime callback resolution

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add dynamic_choices attribute to AgentMethodField for runtime-resolved choice options
• Implement dynamic_choices_callback on Agent to provide choices via callback function
• Create GET /start/dynamic_choices endpoint to fetch dynamic choices at runtime
• Wire callback into example controller template with sample implementation
• Add 18 comprehensive unit tests covering field validation, serialization, endpoint behavior, and
  edge cases
• Refactor code: remove dead return-type union, drop unused params, strengthen assertions, rename
  misleading tests
• Update changelog and documentation with dynamic choices feature and setup guide
Diagram
flowchart LR
  A["AgentMethodField<br/>dynamic_choices: str"] -->|key name| B["Agent<br/>dynamic_choices_callback"]
  B -->|invoked with method_name| C["Callback Function<br/>returns dict of choices"]
  C -->|returns| D["GET /start/dynamic_choices<br/>endpoint"]
  D -->|fetches at runtime| E["Supervaize Studio<br/>renders form with choices"]
Loading

Grey Divider

File Changes

1. src/supervaizer/agent.py ✨ Enhancement +21/-1

Add dynamic_choices field and callback to Agent classes

src/supervaizer/agent.py


2. src/supervaizer/routes.py ✨ Enhancement +30/-0

Add GET /start/dynamic_choices endpoint for runtime choices

src/supervaizer/routes.py


3. src/supervaizer/examples/controller_template.py ✨ Enhancement +20/-0

Wire get_dynamic_choices callback into example agent

src/supervaizer/examples/controller_template.py


View more (7)
4. tests/test_agent.py 🧪 Tests +241/-0

Add 18 unit tests for dynamic choices field and callback

tests/test_agent.py


5. tests/test_routes.py 🧪 Tests +119/-1

Add 6 unit tests for dynamic choices endpoint behavior

tests/test_routes.py


6. docs/CHANGELOG.md 📝 Documentation +3/-2

Update changelog with dynamic choices feature entry

docs/CHANGELOG.md


7. docs/api/openapi.json 📝 Documentation +1/-1

Auto-generated OpenAPI schema update

docs/api/openapi.json


8. docs/model_reference/model_core.md 📝 Documentation +1/-1

Auto-generated model reference timestamp update

docs/model_reference/model_core.md


9. docs/model_reference/model_extra.md 📝 Documentation +1/-1

Auto-generated model reference timestamp update

docs/model_reference/model_extra.md


10. docs/superpowers/plans/2026-04-08-dynamic-choices.md 📝 Documentation +1247/-0

Add comprehensive implementation plan for dynamic choices

docs/superpowers/plans/2026-04-08-dynamic-choices.md


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 8, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. Stale OpenAPI spec🐞
Description
The new GET /supervaizer/agents/{slug}/start/dynamic_choices endpoint is implemented in
routes.py, but docs/api/openapi.json was not regenerated and does not include this route. This
makes the published OpenAPI/spec (and any Swagger/Redoc/codegen that consumes it) incomplete
relative to the actual server behavior.
Code

docs/api/openapi.json[4416]

+}
Evidence
routes.py adds the /start/dynamic_choices handler under agent routes, while the exported
docs/api/openapi.json still transitions from /validate-method-fields directly to /jobs for the
agent without any /start/dynamic_choices path present; the repository has an explicit export tool
that writes this file from the running FastAPI app, so it should be regenerated when routes change.

src/supervaizer/routes.py[621-649]
docs/api/openapi.json[559-632]
tools/export_openapi.py[10-19]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new API endpoint was added, but `docs/api/openapi.json` was not regenerated, leaving the committed OpenAPI spec out of sync with the actual FastAPI routes.
### Issue Context
The repo includes `tools/export_openapi.py`, which generates `docs/api/openapi.json` from `supervaizer.examples.controller_template.sv_server.app`. After adding new endpoints, this file should be regenerated and committed.
### Fix Focus Areas
- tools/export_openapi.py[10-19]
- docs/api/openapi.json[559-632]
- src/supervaizer/routes.py[621-649]
### What to do
1. Run the OpenAPI export script (or the project’s documented equivalent) to regenerate `docs/api/openapi.json`.
2. Verify the regenerated spec contains `/supervaizer/agents/{slug}/start/dynamic_choices`.
3. Commit the updated `docs/api/openapi.json`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Changelog endpoint path mismatch🐞
Description
The changelog documents the dynamic choices endpoint as GET /agents/{slug}/start/dynamic_choices,
but the router actually mounts agent routes under the /supervaizer prefix. This is likely to
confuse integrators by pointing them at a non-existent path.
Code

docs/CHANGELOG.md[25]

+- **Dynamic choices for `AgentMethodField`** — Fields can now use `dynamic_choices` instead of static `choices` to resolve options at runtime via a callback. Add a `dynamic_choices_callback` callable to the `Agent` constructor and a `dynamic_choices` key to your `AgentMethodField`. Supervaize Studio fetches choices from the new `GET /agents/{slug}/start/dynamic_choices` endpoint when rendering the job start form. Static `choices` and `dynamic_choices` are mutually exclusive on a field. See [Dynamic Choices guide](https://docs.runwaize.com/docs/supervaizer-controller/dynamic-choices).
Evidence
create_agents_routes() mounts all agent routers with prefix /supervaizer, and each agent
router’s prefix comes from Agent.path which starts with /agents/{slug}; therefore the full path
includes both segments.

docs/CHANGELOG.md[20-26]
src/supervaizer/routes.py[350-368]
src/supervaizer/agent.py[724-727]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The changelog’s endpoint path for dynamic choices omits the `/supervaizer` prefix that is part of the actual mounted route.
### Issue Context
Agent routes are included under `/supervaizer` and then under each agent’s `/agents/{slug}` path, so the fully-qualified endpoint is `/supervaizer/agents/{slug}/start/dynamic_choices`.
### Fix Focus Areas
- docs/CHANGELOG.md[20-26]
- src/supervaizer/routes.py[350-368]
- src/supervaizer/agent.py[724-727]
### What to do
Update the changelog entry to reference the correct full path (or explicitly state that `/agents/{slug}/...` is relative to the `/supervaizer` API prefix).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread docs/api/openapi.json Outdated
@alain-sv
alain-sv merged commit c5836fb into develop Apr 8, 2026
5 checks passed
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