Model Catalog Governance: Routing, Discovery and IAM in OCI Enterprise AI
💡 Tool Tip:API Tester, JSON Formatter, JSON to YAML, Env File Generator
Oracle published its October 2026 OCI Enterprise AI update on October 9, and the headline is easy: xAI's Grok 4.6 and Grok 4.7 are now available for on-demand inference. The interesting part is everything around the models. The same release adds a Smart Model Router that routes inference across customer-selected regions, a Model Discovery API that reports what models exist in a region along with their retirement dates, an expanded Model Import catalogue spanning Alibaba, DeepSeek, Google and Z.ai, and IAM policies that can allow or exclude specific model IDs. That is a platform growing governance features, and governance is what turns a model demo into something you can leave running.
Platform value: turning cross-Region routing into a piece of configuration
What actually shipped
Six items, and they divide cleanly into capacity, catalogue and control. On capacity, Grok 4.6 and 4.7 arrive for on-demand inference, positioned for coding, agentic tasks, reasoning and knowledge work without customers managing the underlying infrastructure. On catalogue, Model Discovery exposes the regional model list programmatically, and Model Import expands with Alibaba Qwen3.8-27B and Qwen3.5-397B-A17B, DeepSeek V4 Pro 0813 and V4.1 Flash, Google Gemma 4 31B IT and 26B A4B IT, and Z.ai GLM-5.3 and GLM-5.3-Flash. On control, there is Smart Model Router, model-level IAM policies, and the Responses API gaining the ability to call select imported models, beginning with Qwen3.6-35B-A3B and Gemma 4 31B IT. Cohere Command A Vision and Embed 4 also expanded to UAE East (Dubai).
# A routing profile is configuration, not application code.
ROUTING_PROFILE = {
'name': 'prod-inference-eu-apac',
'model': 'xai.grok-4.7',
'approved_regions': ['eu-frankfurt-1', 'ap-singapore-1', 'ap-tokyo-1'],
'excluded_regions': ['us-ashburn-1'],
}
def resolve(profile, requested_region):
if requested_region in profile['excluded_regions']:
return {'region': None, 'reason': 'region excluded by policy'}
allowed = profile['approved_regions']
if not allowed:
return {'region': None, 'reason': 'no approved regions'}
if requested_region in allowed:
return {'region': requested_region, 'reason': 'requested region is approved'}
return {'region': allowed[0], 'reason': 'routed to first approved region'}
print(resolve(ROUTING_PROFILE, 'us-ashburn-1'))
print(resolve(ROUTING_PROFILE, 'ap-singapore-1'))
# The regional scope stays yours. Write the profile so a reviewer can read it.The routing profile is the abstraction worth copying
Smart Model Router routes on-demand inference requests across customer-selected OCI regions where a model is available. The mechanic is a routing profile: you define the model and the approved regions, then use that profile with the Chat API or the Responses API. Oracle's framing is that this saves teams from building and maintaining their own cross-region routing logic, which is true, but the more valuable property is that the regional scope stays under customer control. That distinction matters in regulated environments: a cross-region router built inside an application tends to be a function someone wrote to make latency numbers look better, whereas a routing profile is a named artefact with an approved-region list that a reviewer can read and a change process can govern. Whether you adopt this feature or build your own, copy the shape: make the routing decision data, not code.
# Model discovery replaces the hardcoded model list in your app.
def refresh_catalog(client, region):
catalog = {}
for model in client.list_models(region=region):
catalog[model['id']] = {
'input_types': model.get('input_types', []),
'output_types': model.get('output_types', []),
'serving': model.get('serving_options', []),
'params': model.get('supported_parameters', []),
'retires_on': model.get('retirement_date'),
}
return catalog
def retiring_soon(catalog, today, days=90):
alerts = []
for model_id, meta in catalog.items():
when = meta.get('retires_on')
if when and (when - today).days <= days:
alerts.append({'model': model_id, 'retires_on': when.isoformat()})
return alerts
# A model list you maintain by hand is a model list that is already wrong.A model catalog should be queried, not maintained by hand
Model discovery turns the catalogue into a query
Model Discovery gives developers API access to discover models available in a specific region and retrieve details such as capabilities, input and output types, serving options, supported parameters, and retirement dates. The retirement date is the part to build on. Every team that has run a model in production has a version of this problem: a model ID hardcoded in a config file, a vendor notice arriving by email, and a scramble with a quarter of the runway you wanted. If the catalogue is queryable, you can refresh it on a schedule, diff it against the version you depend on, and raise an alert the moment a model you call gains a retirement date. That converts an emergency into a ticket with a due date, and it costs one scheduled job.
# On-demand or imported? Two shapes, mostly decided by steady-state load.
def serving_choice(rpm_peak, avg_input_tok, avg_output_tok, hours_per_day=8):
daily_tokens = rpm_peak * 60 * hours_per_day * (avg_input_tok + avg_output_tok)
return {
'daily_tokens': daily_tokens,
'recommended': 'on-demand' if daily_tokens < 5e8 else 'dedicated cluster with import',
'reasons': [
'on-demand has no capacity to manage and no idle cost',
'import needs a compatible dedicated AI cluster, and you own the hosting',
'import pays off when utilisation stays high across the month',
],
}
print(serving_choice(rpm_peak=40, avg_input_tok=1800, avg_output_tok=400))
# Import also buys model choice. On-demand buys not having an on-call rota for GPUs.Import and on-demand are two different operating models
Model Import and on-demand inference look similar from an API call and are very different from an operations standpoint. On-demand means no capacity to manage and no idle cost, with the trade-off that you consume whatever capacity the provider makes available. Import means you first import and host the model on a compatible dedicated AI cluster, then call it, which gives you model choice beyond the hosted catalogue and predictable throughput, at the cost of owning the hosting. The decision is mostly about utilisation: a workload that runs hot all month justifies dedicated capacity, while a bursty one pays for idle capacity it will never use. Model one against the other with your own numbers before choosing, and remember that the imported path also inherits a maintenance obligation that on-demand does not.
# Model-level IAM: allow by pattern, exclude by explicit deny.
POLICY_RULES = [
{'group': 'app-team-search', 'allow_patterns': ['cohere.*', 'google.gemma-4-*'], 'deny': []},
{'group': 'app-team-agents', 'allow_patterns': ['xai.*', 'deepseek.*'], 'deny': ['xai.grok-4.6']},
]
def match(pattern, value):
prefix = pattern.split('*')[0]
suffix = pattern.split('*')[-1] if pattern.count('*') else ''
return value.startswith(prefix) and value.endswith(suffix)
def permitted(group, model_id):
for rule in POLICY_RULES:
if rule['group'] != group:
continue
if model_id in rule['deny']:
return {'allowed': False, 'reason': 'explicitly denied'}
for pattern in rule['allow_patterns']:
if match(pattern, model_id):
return {'allowed': True, 'reason': 'matched ' + pattern}
return {'allowed': False, 'reason': 'no matching allow rule'}
return {'allowed': False, 'reason': 'group has no policy'}
print(permitted('app-team-agents', 'xai.grok-4.6'))
print(permitted('app-team-agents', 'xai.grok-4.7'))
# Access control that lives in the cloud beats access control that lives in a wiki.Model-level IAM keeps access control in the cloud, not in a wiki page
IAM at the model level is the control that keeps auditors calm
The most underrated item in the release is the least glamorous: OCI IAM policies can now control which models different groups can invoke, allowing specific model IDs or patterns and excluding selected models. Plenty of organisations implement model access control inside the application, which works until someone adds a new service and forgets. Moving it into the cloud identity layer means the platform team can answer a question like which teams can call a given model without reading five codebases, and it means a newly added model is not automatically reachable by everything with network access. Patterns make the policy maintainable as the catalogue grows, and explicit exclusions make it possible to keep a specific model out of a specific team's reach without denying the whole family.
# Retirement is a date, so treat migration as a scheduled task.
from datetime import date
def migration_plan(model_id, retires_on, today):
window = (retires_on - today).days
return {
'model': model_id,
'days_remaining': window,
'steps': [
('frost the model in new code', window <= 120),
('stand up the replacement behind the same interface', window <= 90),
('run the compatibility suite on both', window <= 60),
('shift traffic and keep a rollback profile', window <= 30),
],
'rollback': 'repoint the routing profile at the previous model',
}
plan = migration_plan('google.gemma-4-31b-it', date(2027, 1, 31), date(2026, 10, 14))
print(plan['days_remaining'], [step for step, due in plan['steps'] if due])
# Because switching is a profile change, the migration is boring. Keep it boring.A rollout plan that survives model retirement
Put the pieces together and the operating model looks like this. Keep model IDs in a routing profile rather than in application code, so changing a model is a configuration change with a reviewable diff. Refresh the discovered catalogue on a schedule and treat retirement dates as planning inputs, with a migration sequence that frosts a model in new code well before its end date, stands up a replacement behind the same interface, runs a compatibility suite against both, then shifts traffic with the old profile retained for rollback. Enforce entitlements in IAM so the blast radius of a mistake is bounded by policy rather than by vigilance. None of this is exciting work, and that is exactly the point: the teams that survive a model retirement cycle without an incident are the ones for whom switching models was already boring.
📌 Frequently Asked Questions
What is new in OCI Enterprise AI this month?
xAI Grok 4.6 and 4.7 available for on-demand inference, Smart Model Router for cross-region routing, Model Discovery, an expanded Model Import catalogue, the Responses API supporting select imported models, model-level IAM policies, and Cohere multimodal models in UAE East (Dubai).
What does Smart Model Router do?
It routes on-demand inference requests across customer-selected OCI regions where the model is available. You define a routing profile with the model and approved regions, then use it with the Chat API or the Responses API, so teams do not have to build their own cross-region routing logic.
What does Model Discovery return?
API access to the models available in a specific region with details such as capabilities, input and output types, serving options, supported parameters, and retirement dates.
How do IAM policies affect model access?
OCI IAM policies can allow specific model IDs or patterns, or exclude selected models, so access can be controlled per group at the platform layer rather than inside each application.
Which models can be imported?
The September additions span Alibaba Qwen3.8-27B, Qwen3.5-397B-A17B and Qwen3.6-35B-A3B, DeepSeek V4 Pro 0813 and V4.1 Flash, Google Gemma 4 31B IT and 26B A4B IT, and Z.ai GLM-5.3 and GLM-5.3-Flash, with the Responses API callable for selected imported models.