Skip to content

fix(api): use config_to_dict() for ROMAConfig serialization in ExecutionService#95

Open
0xghost42 wants to merge 1 commit into
sentient-agi:mainfrom
0xghost42:fix/71-romaconfig-serialization
Open

fix(api): use config_to_dict() for ROMAConfig serialization in ExecutionService#95
0xghost42 wants to merge 1 commit into
sentient-agi:mainfrom
0xghost42:fix/71-romaconfig-serialization

Conversation

@0xghost42
Copy link
Copy Markdown

Summary

Closes #71.

POST /api/v1/executions returns a 500 regardless of profile:

{"detail":"Failed to create execution: 'ROMAConfig' object is not iterable"}

The root cause was diagnosed in #74 by @nguyenhuulocbb (credit to them — no PR had been opened):

ExecutionService.start_execution falls through a hasattr(config, "model_dump") guard to dict(config) when persisting the execution record. ROMAConfig is OmegaConf-structured — it is not a Pydantic model with model_dump and is not iterable as a mapping — so the dict(config) branch raises TypeError before storage.create_execution is ever called.

Change

src/roma_dspy/api/execution_service.py:

  • Use config_to_dict() from roma_dspy.config.utils. That helper already handles both ROMAConfig and plain DictConfig inputs via OmegaConf.to_container, and is the path the rest of the codebase uses for the same conversion (see get_config_diff in the same module).
  • Drop the dual-branch model_dump / dict(config) ternary entirely — there is only one correct serialisation path.
-            config=config.model_dump()
-            if hasattr(config, "model_dump")
-            else dict(config),
+            config=config_to_dict(config),

tests/unit/test_execution_service.py:

  • Update the mock_config_manager fixture to return a real OmegaConf.create(...) config instead of a MagicMock with a pre-canned .model_dump. The mock-based test happily walked the (broken) model_dump branch in production code, masking the regression. Returning a real config exercises the actual serialisation path.

Verification

  • python3 -m py_compile clean on both touched files.
  • The dict produced by config_to_dict() is JSON-serializable, which is what storage.create_execution (PostgresStorage) ultimately needs.

Out of scope

#74 also proposed adding a free_tier config profile. I left that out — free_tier is not referenced in the current README, QUICKSTART.md, or CONFIGURATION.md (the examples all use general and crypto_agent), so the issue reporter's choice of "config_profile": "free_tier" would still fail profile lookup after this fix. The fix here ensures any valid profile name now serialises correctly; adding new profiles should be a separate scoped change.

…ionService

Closes sentient-agi#71.

Reported in sentient-agi#71: POST /api/v1/executions returns 500 with

  {"detail":"Failed to create execution: 'ROMAConfig' object is not iterable"}

regardless of profile. The root cause was diagnosed in sentient-agi#74 by
@nguyenhuulocbb: ExecutionService.start_execution falls through a
`hasattr(config, 'model_dump')` guard to `dict(config)` when persisting
the execution record. ROMAConfig is OmegaConf-structured (not a Pydantic
model with model_dump and not iterable as a mapping), so the
`dict(config)` branch raises TypeError before storage.create_execution
is ever called.

Use config_to_dict() from roma_dspy.config.utils, which is the helper
the rest of the codebase already uses for the same conversion (see
get_config_diff in the same module). It handles both ROMAConfig and
plain DictConfig inputs via OmegaConf.to_container.

Tests
- Updated the mock_config_manager fixture in test_execution_service to
  return a real OmegaConf DictConfig instead of a MagicMock with a
  pre-canned model_dump. This exercises the real serialisation path and
  would have caught the regression at its introduction.
@0xghost42
Copy link
Copy Markdown
Author

Hi @salzubi401 — gentle bump if this repo is still on your radar. PR has been open since 13/05; fixes ExecutionService serializing a Pydantic ROMAConfig with the wrong helper (uses to_dict()/dict instead of config_to_dict(), so nested models leak through). Small, scoped change. Happy to rebase or split if needed.

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.

API calls don't work

1 participant