Problem
sys_list_models currently takes no parameters and returns every model exposed
by every declared worker's provider.
An orchestrator commonly needs to validate only a small set of configured
worker/model combinations before dispatch. When a provider exposes a large
catalogue, such as OpenRouter, the complete response can be unnecessarily large
and remains in conversation history for later model calls.
Reproduction
An agent with six declared workers needed to validate seven configured model
IDs.
Measured serialized response sizes:
| Request |
Response size |
| Current unfiltered response |
30,618 characters |
| Required workers and model IDs only |
1,870 characters |
The filtered response was approximately 94% smaller while retaining all
information required for dispatch preflight.
Example relevant IDs:
xiaomi/mimo-v2.5-pro
z-ai/glm-5.2
moonshotai/kimi-k3
gpt-5.6-sol
gpt-5.6-terra
claude-sonnet-5
claude-opus-4-8
Proposed API
Add two optional parameters:
{
"workers": [
"pi",
"codex",
"codex_deep",
"codex_fast",
"claude_code",
"claude_deep"
],
"model_ids": [
"xiaomi/mimo-v2.5-pro",
"z-ai/glm-5.2",
"moonshotai/kimi-k3",
"gpt-5.6-sol",
"gpt-5.6-terra",
"claude-sonnet-5",
"claude-opus-4-8"
]
}
Semantics:
workers limits the returned worker rows.
model_ids retains only exact matching IDs in each selected row.
- A selected worker with no matching models remains present with
models: [],
allowing callers to detect unavailable configured models.
- Omitting either filter leaves that dimension unfiltered.
- Calling
sys_list_models({}) preserves the existing complete response.
Backward compatibility
The existing schema and response remain valid when the optional filters are
omitted:
Fields such as source, verified, and note remain unchanged. Filtering
only affects which worker rows and model entries are returned.
Proposed implementation
A shared filtering helper can keep the in-process and runner-local paths
consistent.
omnigent/tools/builtins/list_models.py
Extend the tool schema:
"parameters": {
"type": "object",
"properties": {
"workers": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
"description": (
"Optional worker names to return. "
"Omit to return every worker."
),
},
"model_ids": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
"description": (
"Optional exact model IDs to retain in each row. "
"Rows without a match remain present with models: []."
),
},
},
"required": [],
"additionalProperties": False,
},
Add a shared filtering function:
def filter_model_catalog(
catalog: dict[str, Any],
arguments: dict[str, Any],
) -> dict[str, Any]:
"""Return a worker/model-filtered copy of a model catalogue."""
workers = arguments.get("workers")
worker_names = set(workers) if isinstance(workers, list) else None
model_ids = arguments.get("model_ids")
selected_models = set(model_ids) if isinstance(model_ids, list) else None
filtered: dict[str, Any] = {}
for worker, raw_row in catalog.items():
if worker_names is not None and worker not in worker_names:
continue
if not isinstance(raw_row, dict):
filtered[worker] = raw_row
continue
row = dict(raw_row)
if selected_models is not None and isinstance(row.get("models"), list):
row["models"] = [
model
for model in row["models"]
if isinstance(model, dict)
and model.get("id") in selected_models
]
filtered[worker] = row
return filtered
Use it in the in-process path:
def invoke(self, arguments: str, ctx: ToolContext) -> str:
del ctx
from omnigent.model_catalog import catalog_for_spec
try:
args = json.loads(arguments or "{}")
except json.JSONDecodeError as exc:
return f"Error: sys_list_models invalid JSON arguments: {exc}"
if not isinstance(args, dict):
return "Error: sys_list_models arguments must be a JSON object"
catalog = catalog_for_spec(self._spec)
return json.dumps(filter_model_catalog(catalog, args))
omnigent/runner/tool_dispatch.py
Pass the tool arguments through the runner-local path:
async def _execute_list_models_tool(
args: dict[str, Any],
*,
agent_spec: Any | None,
) -> str:
if agent_spec is None:
return "Error: sys_list_models requires an agent spec"
from omnigent.model_catalog import catalog_for_spec
from omnigent.tools.builtins.list_models import filter_model_catalog
catalog = await asyncio.to_thread(catalog_for_spec, agent_spec)
return json.dumps(filter_model_catalog(catalog, args))
Update the dispatch branch:
elif tool_name in _LIST_MODELS_TOOLS:
output = await _execute_list_models_tool(
args,
agent_spec=agent_spec,
)
This preserves the current behavior for sys_list_models({}) and avoids
duplicating filtering logic between execution paths.
Acceptance criteria
- An unfiltered call returns the same complete catalogue as before.
workers returns only the named worker rows.
model_ids performs exact ID matching within each returned row.
- Selected workers with no matching models remain present with an empty
models array.
- Unknown worker names do not cause unrelated rows to be returned.
- The in-process and runner-local paths behave identically.
- Tests cover unfiltered, worker-only, model-only, combined, and empty-match
cases.
Problem
sys_list_modelscurrently takes no parameters and returns every model exposedby every declared worker's provider.
An orchestrator commonly needs to validate only a small set of configured
worker/model combinations before dispatch. When a provider exposes a large
catalogue, such as OpenRouter, the complete response can be unnecessarily large
and remains in conversation history for later model calls.
Reproduction
An agent with six declared workers needed to validate seven configured model
IDs.
Measured serialized response sizes:
The filtered response was approximately 94% smaller while retaining all
information required for dispatch preflight.
Example relevant IDs:
xiaomi/mimo-v2.5-proz-ai/glm-5.2moonshotai/kimi-k3gpt-5.6-solgpt-5.6-terraclaude-sonnet-5claude-opus-4-8Proposed API
Add two optional parameters:
{ "workers": [ "pi", "codex", "codex_deep", "codex_fast", "claude_code", "claude_deep" ], "model_ids": [ "xiaomi/mimo-v2.5-pro", "z-ai/glm-5.2", "moonshotai/kimi-k3", "gpt-5.6-sol", "gpt-5.6-terra", "claude-sonnet-5", "claude-opus-4-8" ] }Semantics:
workerslimits the returned worker rows.model_idsretains only exact matching IDs in each selected row.models: [],allowing callers to detect unavailable configured models.
sys_list_models({})preserves the existing complete response.Backward compatibility
The existing schema and response remain valid when the optional filters are
omitted:
{}Fields such as
source,verified, andnoteremain unchanged. Filteringonly affects which worker rows and model entries are returned.
Proposed implementation
A shared filtering helper can keep the in-process and runner-local paths
consistent.
omnigent/tools/builtins/list_models.pyExtend the tool schema:
Add a shared filtering function:
Use it in the in-process path:
omnigent/runner/tool_dispatch.pyPass the tool arguments through the runner-local path:
Update the dispatch branch:
This preserves the current behavior for
sys_list_models({})and avoidsduplicating filtering logic between execution paths.
Acceptance criteria
workersreturns only the named worker rows.model_idsperforms exact ID matching within each returned row.modelsarray.cases.