[AIGTWY-4573] Apply the managed config at launch and version-gate it - #593
david-siqi-liu wants to merge 1 commit into
Conversation
6a2c5a9 to
0d7acf8
Compare
9be4c55 to
3670fe6
Compare
5f70142 to
83138ae
Compare
Resolve the managed config's per-agent inputs into each agent's own config shape: the model allow-list or discovery location into Claude's /model picker and Codex's model catalog, and the custom http_headers into each agent's outbound requests. Stacked on the launch-apply PR (#593). - managed_resolve: add managed_static_models, managed_model_service_location, and managed_custom_headers; extend managed_state_overrides to layer claude_static_models / codex_static_models, the per-agent model_service_location, and {tool}_custom_headers into state. For codex a discovery location alone does not count as supplying models (no reader for it), so discovery still runs; for claude it does. - claude: a static list becomes availableModels + enforceAvailableModels + a modelPicker (exactly the named ids, non-Claude included); a discovery location turns on gateway discovery instead. Ownership markers prune only ug-owned picker keys on a static-to-discovery transition, and clear only when the OS-managed file was written. Managed http_headers append to ANTHROPIC_CUSTOM_HEADERS, with ug's fixed headers winning on conflict; values that would break the header serialization (newlines, and commas for Gemini) are dropped. - codex: a static list is written as a model_catalog_json catalog of full ModelPresets; a fetch failure preserves an existing catalog (or falls back to discovery when none exists yet), and a successful but empty result falls back to discovery. Managed http_headers merge into the provider http_headers, ug's fixed headers winning. - gemini: managed http_headers merge into GEMINI_CLI_CUSTOM_HEADERS, ug's fixed headers winning. - README: document the Claude picker, the Codex catalog, and the ucode-models.json managed file. Co-authored-by: Isaac <no-reply@databricks.com>
83138ae to
4786af3
Compare
Resolve the managed config's per-agent inputs into each agent's own config shape: the model allow-list or discovery location into Claude's /model picker and Codex's model catalog, and the custom http_headers into each agent's outbound requests. Stacked on the launch-apply PR (#593). - managed_resolve: add managed_static_models, managed_model_service_location, and managed_custom_headers; extend managed_state_overrides to layer claude_static_models / codex_static_models, the per-agent model_service_location, and {tool}_custom_headers into state. For codex a discovery location alone does not count as supplying models (no reader for it), so discovery still runs; for claude it does. - claude: a static list becomes availableModels + enforceAvailableModels + a modelPicker (exactly the named ids, non-Claude included); a discovery location turns on gateway discovery instead. Ownership markers prune only ug-owned picker keys on a static-to-discovery transition, and clear only when the OS-managed file was written. Managed http_headers append to ANTHROPIC_CUSTOM_HEADERS, with ug's fixed headers winning on conflict; values that would break the header serialization (newlines, and commas for Gemini) are dropped. - codex: a static list is written as a model_catalog_json catalog of full ModelPresets; a fetch failure preserves an existing catalog (or falls back to discovery when none exists yet), and a successful but empty result falls back to discovery. Managed http_headers merge into the provider http_headers, ug's fixed headers winning. - gemini: managed http_headers merge into GEMINI_CLI_CUSTOM_HEADERS, ug's fixed headers winning. - README: document the Claude picker, the Codex catalog, and the ucode-models.json managed file. Co-authored-by: Isaac <no-reply@databricks.com>
4786af3 to
5b9668f
Compare
5b9668f to
10462a5
Compare
10462a5 to
204c109
Compare
204c109 to
3f841d6
Compare
3f841d6 to
2c23e59
Compare
| def check_gateway_endpoint(state: dict, tool: str) -> bool: | ||
| """V2-only: a tool is available iff we discovered models for it.""" | ||
| def check_gateway_endpoint(state: dict, tool: str, managed: dict | None = None) -> bool: | ||
| """V2-only: a tool is available iff we discovered models for it or the managed config supplies them. |
There was a problem hiding this comment.
what does v2 only mean here. should we remove it. i hope it's not aigw v2...
| # only when the config changed since last applied here, or on `--refresh`. The launched | ||
| # tool's own write below is suppressed, so this apply-all owns the OS write. | ||
| applied_ut = get_applied_managed_update_time(existing) | ||
| if managed is not None and (refresh or managed_config_is_newer(managed, applied_ut)): |
There was a problem hiding this comment.
can we check not just the timestamp but also that the workspace url is the same? if the workspace url is diff, we should always reapply
in the case below
time = t
workspace A -> updated at t-1 --> no managed config, apply for the first time at time t
workspace B -> updated at t-2 --> managed config but it's not newer than t. so it doesn't get updated
we currently don't reapply. but we should
| # The OS-managed (sudo) write is owned by the version-gated apply-all above and by `ug | ||
| # configure`; a launch only refreshes the user-level config and computes launch params, so | ||
| # suppress the OS write here to keep an unchanged launch prompt-free. | ||
| with suppressed_managed_writes(): |
There was a problem hiding this comment.
does this mean that we ONLY write to managed settings during ug configure? i think this is what i was worried about re the autoconfigure for ug claude
There was a problem hiding this comment.
we also write to managed settings during ug/ug claude/ug codex if drift has been detected
There was a problem hiding this comment.
is that in this PR or a diff PR? it looks like in this PR we never write to managed settings during configure_tool?
| if managed is not None: | ||
| state = set_applied_managed_update_time(state, managed_update_time(managed)) | ||
| save_state(state) | ||
| _apply_managed_mcp_and_skills(managed, picked, state) |
There was a problem hiding this comment.
what happens if i only configure 1 agent? ug configure --agents claude. that means that the timestamp is workspace wide but my codex is still using an old workspace config version?
2c23e59 to
4f848a0
Compare
4f848a0 to
c48f924
Compare
d5337d0 to
51202a8
Compare
| skip_validate: Annotated[ | ||
| bool, | ||
| typer.Option( | ||
| "--skip-validate", | ||
| help="Skip the post-configure validation step that sends a quick test " | ||
| "message through each agent. Config files are still written with the " | ||
| "freshly discovered models.", | ||
| ), | ||
| ] = False, |
There was a problem hiding this comment.
im worried that clients will use --skip-validate and break. can we mark as deprecated instead but leave the --skip-validate cmd so that No such option: --skip-validate doesn't throw? it can just do nothing + we can have a deprecation warning
| parts = name.split(".") | ||
| if len(parts) != 3 or not all(parts): | ||
| return None |
There was a problem hiding this comment.
can you use _is_uc_fqn instead and make it public
unity-gateway/src/ucode/managed_setup.py
Line 267 in ce887ad
| if not refresh and applied_ut is not None and config_changed: | ||
| print_note("The managed configuration was updated; re-applying it.") | ||
| enabled = managed_enabled_tools(managed) | ||
| to_apply = enabled if config_changed else [tool] if tool in enabled else [] |
There was a problem hiding this comment.
is this possible because we're doing all the applies for all tools at once?
1/ admin sets up claude code
2/ user uses claude code
3/ admins sets up codex incorrectly
4/ user goes to run claude code -> is now blocked because codex configuration is wrong
With the config parsed (the stacked parse PR), apply the managed configuration to every enabled agent at launch, but only when it changed since the last apply (an update_time watermark) or on --refresh, so an unchanged launch never re-writes the OS-managed files or prompts for a password. Also remove the post-configure probe validation, wire the managed MCP servers and skills, and rename user-facing strings. - Gate the launch apply on update_time. refresh_managed_config always fetches; a launch re-applies the managed configuration (the only step that writes the OS-managed files and can prompt for a password) only when update_time is newer than the applied watermark, or on ug <agent> --refresh, and records the new watermark. An unchanged launch skips the apply and never prompts. ug configure always applies and records the watermark. The "was updated; re-applying it" note prints only on a genuine version change, not on a no-op --refresh. The per-tool launch write is wrapped in suppressed_managed_writes() so the apply-all owns the single OS write. - Apply the managed config's mcp_servers and skills to each enabled agent. Both are UC-services-only selectors: register the absolute names (as UC mcp-services) or download the named skills, plus everything discovered under a unity_catalog_location (a schema's mcp-services via list_mcp_services, or its skills), unioned. Nothing on the launch path turned the workspace's published servers or skills into agent registrations before, so they never showed up. - `ug configure` wires the managed config's MCP servers and skills at configure time (not only at launch), and suppresses the interactive MCP/skills/plugins prompt when the managed config already defines them (and never installs anything under --dry-run), so a managed workspace is set up without asking the developer to configure MCP. - Stop ug configure from validating agents with a probe message. Remove the post-configure validation and the --skip-validate flag: it is not configure's job to test models, the probe also reverted a freshly-written config on failure, and the gateway enforces model access regardless. The now-unused validate_all_tools / provider_permission_error / resolve_managed_for_tool helpers are removed; validate_tool stays for headless and e2e callers. - Drop the "Using managed config - launching <agent>" banner and the redundant post-panel "Starting <agent>" line from the bare-ug launch, so bare ug matches ug <agent>. - When a config we previously applied is gone (deleted, or the feature turned off), the launch does not auto-revert the OS-managed files; it notes that Unity Gateway managed configurations are still applied and points the developer to `ug revert`, but only when the config is definitively gone (NOT_FOUND or the feature is off), not on a transient fetch failure. Keyed on the applied watermark, so a workspace that never had a config still just uses the developer's own settings. - Rename the product string "CLI Managed Configuration" to "managed configuration" (lowercase) across user-facing lines, tighten the budget-tier recommendation line, and remove the --skip-validate docs. Co-authored-by: Isaac <no-reply@databricks.com>
51202a8 to
c40ed41
Compare
With the config parsed (the parent PR), apply the managed configuration to every enabled agent at launch, but only when it changed since the last apply (an update_time watermark) or on
--refresh, so an unchanged launch never re-writes the OS-managed files or prompts for a password. Also wire the managed MCP servers and skills, drop the post-configure probe validation, and rename user-facing strings.Changes:
refresh_managed_configalways fetches; a launch re-applies the config (the only step that writes the OS-managed files and can prompt for a password) only when update_time is newer than the applied watermark, or onug <agent> --refresh, and records the new watermark. An unchanged launch skips the apply and never prompts.ug configurealways applies. The per-tool launch write is wrapped insuppressed_managed_writes()so the apply-all owns the single OS write.ug configurewires the managed MCP servers and skills at configure time (not only at launch), and suppresses the interactive MCP/skills/plugins prompt when the managed config already defines them (and never installs under--dry-run).ug configurefrom validating agents with a probe message: remove the post-configure validation and the--skip-validateflag (the probe reverted a freshly-written config on failure, and the gateway enforces model access regardless).validate_toolstays for headless and e2e callers.ug revert, but only when the config is definitively gone (NOT_FOUND or feature off), not on a transient fetch failure. Keyed on the applied watermark.This pull request and its description were written by Isaac.