Add managed-config serializer, validation, and per-agent model catalogs - #267
Open
tt-le wants to merge 1 commit into
Open
Add managed-config serializer, validation, and per-agent model catalogs#267tt-le wants to merge 1 commit into
tt-le wants to merge 1 commit into
Conversation
Admin-write foundation for the managed CodingAgentConfig, mirroring the developer-read side added in the parent commit. No CLI wiring and no network calls: the interactive `ucode setup` wizard and `ucode apply` build on this in follow-up changes. `managed_setup.py`: - `serialize_managed_config` — ucode-native manifest -> proto-JSON `CodingAgentConfig`, the exact inverse of `normalize_managed_config`. Builds each agent's `AgentModelConfig` oneof variant, which the server rejects when it doesn't match its agent: claude gets `ClaudeDefaultModels` family slots, codex gets no model list at all, and opencode/pi/gemini/copilot get a flat list. Output-only fields (workspace_id, timestamps, user ids) are never emitted. - `validate_manifest` — client-side pre-flight mirroring the handler's `validateStoredConfig`, so an admin sees problems before the round-trip rather than as an opaque INVALID_PARAMETER_VALUE. Also cross-checks configured models against the workspace's discovered inventory, skipped for agents routing through a Model Provider Service (those ids come from the provider's catalog). - Per-agent model catalogs: claude -> Claude only, gemini -> Gemini only, codex -> GPT + OSS, opencode/pi/copilot -> everything discovered. - `~/.ucode/managed-settings.json` persistence (0600, workspace-scoped), distinct from `managed-state.json`: this is the authored manifest, that is the pulled one. Note on units: `spending_percentage` is a fraction in [0, 1], not a percent — the server validates that range. `validate_manifest` rejects e.g. 80 with a message naming the expected form, since the spec doc's prose says "80%". `managed_config.py`: makes the two enum maps public so the write side inverts them instead of restating them — a new agent or MCP type is declared once and both directions pick it up. Mechanical rename otherwise. Tests: 77 cases. The load-bearing one is the round-trip property (serialize -> normalize == identity), asserted over the full manifest, the minimal manifest, every known agent, and every MCP type — it pins read and write together so they cannot drift as the proto grows. Co-authored-by: Isaac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
The admin-write foundation for the managed
CodingAgentConfig, mirroring the developer-read side from #263. No CLI wiring and no network calls: pure functions plus tests. The interactiveucode setupwizard (#PR2) anducode applybuild on this.managed_setup.py(new)—
serialize_managed_config— ucode-native manifest → proto-JSONCodingAgentConfig, the exact inverse ofnormalize_managed_config. Builds each agent'sAgentModelConfigoneof variant, which the server rejects when it doesn't match its agent: claude getsClaudeDefaultModelsfamily slots, codex gets no model list at all, and opencode/pi/gemini/copilot get a flat list. Output-only fields (workspace_id, timestamps, user ids) are never emitted.—
validate_manifest— client-side pre-flight mirroring the handler'svalidateStoredConfig, so an admin sees problems before the round-trip rather than as an opaqueINVALID_PARAMETER_VALUE. Also cross-checks configured models against the workspace's discovered inventory, skipped for agents routing through a Model Provider Service (those ids come from the provider's catalog).— Per-agent model catalogs: claude → Claude only, gemini → Gemini only, codex → GPT + OSS, opencode/pi/copilot → everything discovered.
—
~/.ucode/managed-settings.jsonpersistence (0600, workspace-scoped), distinct frommanaged-state.json: this is the authored manifest, that is the pulled one.managed_config.py— makes the two enum maps public so the write side inverts them instead of restating them, so a new agent or MCP type is declared once and both directions pick it up. Mechanical rename otherwise.Note on units
spending_percentageis a fraction in[0, 1], not a percent — the server validates that range.validate_manifestrejects e.g.80with a message naming the expected form, since the spec doc's prose says "80%".Testing
uv run pytest— 1218 passed, 36 skipped on this commit alone. 77 new cases.The load-bearing one is the round-trip property (
serialize→ #263'snormalize== identity), asserted over the full manifest, the minimal manifest, every known agent, and every MCP type. It pins read and write together so they cannot drift as the proto grows — which matters now that #265 consumes this same manifest shape.This pull request and its description were written by Isaac.