From 44af79585ca2649ee4b3e27db8e21b6c7d42177e Mon Sep 17 00:00:00 2001 From: Nathan Walston Date: Fri, 7 Aug 2026 14:45:15 -0700 Subject: [PATCH 1/5] fix(intake): accept ATIF observation on all step types Relay emits an `observation` on any ATIF step, but Intake only permitted it on agent steps. In-process harnesses like DeepAgents put an observation on a nested system step, so Intake rejected the entire ATIF POST with HTTP 422 and stored nothing. Move `observation` from AtifStepAgent to the shared AtifStepBase; run the tool-call-reference and v1.7 subagent-ref validators on all step types; let the mapper read observations on any step. Adds a regression test reproducing a DeepAgents nested-system-step observation. Co-authored-by: Yuchen Zhang <134643420+yczhang-nv@users.noreply.github.com> Signed-off-by: Nathan Walston --- .../nmp/intake/spans/ingest/atif_domain.py | 9 ++- .../nmp/intake/spans/ingest/atif_mapping.py | 4 +- services/intake/tests/test_atif_v17.py | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/services/intake/src/nmp/intake/spans/ingest/atif_domain.py b/services/intake/src/nmp/intake/spans/ingest/atif_domain.py index 24daf0aff8..8f141d0bbb 100644 --- a/services/intake/src/nmp/intake/spans/ingest/atif_domain.py +++ b/services/intake/src/nmp/intake/spans/ingest/atif_domain.py @@ -155,6 +155,7 @@ class AtifStepBase(BaseModel): is_copied_context: bool | None = None extra: dict[str, Any] | None = None llm_call_count: int | None = Field(default=None, ge=0) + observation: AtifObservation | None = None model_config = ConfigDict(extra="forbid") @@ -184,7 +185,6 @@ class AtifStepAgent(AtifStepBase): reasoning_effort: str | float | None = None reasoning_content: str | None = None tool_calls: list[AtifToolCall] | None = None - observation: AtifObservation | None = None metrics: AtifMetrics | None = None @@ -209,10 +209,9 @@ def validate_atif_step_ids(steps: list[AtifStep]) -> None: def validate_atif_tool_call_references(steps: list[AtifStep]) -> None: """Require unique calls and resolvable observation call references.""" for step in steps: - if not isinstance(step, AtifStepAgent): - continue tool_call_ids: set[str] = set() - for tool_call in step.tool_calls or []: + tool_calls = step.tool_calls if isinstance(step, AtifStepAgent) else None + for tool_call in tool_calls or []: if tool_call.tool_call_id in tool_call_ids: raise ValueError(f"Duplicate tool_call_id '{tool_call.tool_call_id}' in step {step.step_id}") tool_call_ids.add(tool_call.tool_call_id) @@ -229,7 +228,7 @@ def validate_atif_tool_call_references(steps: list[AtifStep]) -> None: def validate_atif_v17_subagent_ref_resolution_keys(steps: list[AtifStep]) -> None: """Require v1.7 subagent references to include a resolvable key.""" for step in steps: - if not isinstance(step, AtifStepAgent) or step.observation is None: + if step.observation is None: continue for result in step.observation.results: for subagent_ref in result.subagent_trajectory_ref or []: diff --git a/services/intake/src/nmp/intake/spans/ingest/atif_mapping.py b/services/intake/src/nmp/intake/spans/ingest/atif_mapping.py index 576a89dcd6..d0d89a936d 100644 --- a/services/intake/src/nmp/intake/spans/ingest/atif_mapping.py +++ b/services/intake/src/nmp/intake/spans/ingest/atif_mapping.py @@ -844,8 +844,8 @@ def _step_tool_calls(step: AtifStep) -> list[AtifToolCall]: def _step_observation(step: AtifStep) -> AtifObservation | None: - """Return the observation attached to an agent step.""" - return step.observation if isinstance(step, AtifStepAgent) else None + """Return the observation attached to any step.""" + return step.observation def _observation_result_for_tool_call(step: AtifStep, tool_call_id: str) -> AtifObservationResult | None: diff --git a/services/intake/tests/test_atif_v17.py b/services/intake/tests/test_atif_v17.py index b21de1ab13..821455c7df 100644 --- a/services/intake/tests/test_atif_v17.py +++ b/services/intake/tests/test_atif_v17.py @@ -1040,3 +1040,61 @@ def test_atif_mapping_end_time_none_when_no_timing_exists_at_all() -> None: for span in spans if span.name in {"user-1", "bash"} or (span.name == "sample-agent" and span.kind == SpanKind.LLM) ) + + +def test_atif_v17_observation_on_nested_system_step() -> None: + """Regression: DeepAgents emits an observation on a nested *system* step. + + ``observation`` previously lived only on ``AtifStepAgent``, so a system step + carrying one was rejected as an extra field and Intake returned HTTP 422, + storing nothing. It now lives on ``AtifStepBase``; every step type accepts it, + validators run on all step types, and the mapper reads observations anywhere. + """ + trajectory = AtifTrajectory.model_validate( + { + "schema_version": "ATIF-v1.7", + "session_id": "deepagents-session", + "trajectory_id": "root", + "agent": {"name": "orchestrator", "version": "1.0"}, + "steps": [ + {"step_id": 1, "source": "user", "message": "classify this email"}, + { + "step_id": 2, + "source": "agent", + "message": "delegating to phishing-analyzer", + "tool_calls": [{"tool_call_id": "task-1", "function_name": "task"}], + "observation": { + "results": [{"source_call_id": "task-1", "subagent_trajectory_ref": [{"trajectory_id": "sub"}]}] + }, + }, + ], + "subagent_trajectories": [ + { + "schema_version": "ATIF-v1.7", + "trajectory_id": "sub", + "agent": {"name": "phishing-analyzer", "version": "1.0"}, + "steps": [ + { + "step_id": 1, + "source": "system", + "message": "You are a careful email phishing analyzer.", + "observation": {"results": [{"content": "is_likely_phishing: true"}]}, + } + ], + } + ], + } + ) + + system_step = trajectory.subagent_trajectories[0].steps[0] + assert system_step.source == "system" + assert system_step.observation is not None + assert system_step.observation.results[0].content == "is_likely_phishing: true" + + # The non-agent observation maps without error and produces spans. + spans = trajectory_to_spans( + workspace="default", + trajectory=trajectory, + ingested_at=datetime(2026, 1, 1, tzinfo=timezone.utc), + ) + assert spans From 0eefc266c40004374c7f3163cb9c53f919a53904 Mon Sep 17 00:00:00 2001 From: Nathan Walston Date: Mon, 10 Aug 2026 08:26:31 -0700 Subject: [PATCH 2/5] test(intake): assert observation reachable on nested system step Address review: the prior `assert spans` passed even if `_step_observation` regressed to agent-only, since trajectory/step spans emit independently. Locate the nested system-step span and assert `_step_observation` returns the observation value on the non-agent step, so the test fails if the mapper stops reading observations there. Signed-off-by: Nathan Walston --- services/intake/tests/test_atif_v17.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/services/intake/tests/test_atif_v17.py b/services/intake/tests/test_atif_v17.py index 821455c7df..5a9b09df5c 100644 --- a/services/intake/tests/test_atif_v17.py +++ b/services/intake/tests/test_atif_v17.py @@ -18,7 +18,7 @@ AtifSubagentTrajectoryRef, AtifTrajectory, ) -from nmp.intake.spans.ingest.atif_mapping import AtifTrajectoryDepthError, trajectory_to_spans +from nmp.intake.spans.ingest.atif_mapping import AtifTrajectoryDepthError, _step_observation, trajectory_to_spans from nmp.intake.spans.ingest.evaluation_context import EvaluationContext from pydantic import ValidationError @@ -1091,10 +1091,19 @@ def test_atif_v17_observation_on_nested_system_step() -> None: assert system_step.observation is not None assert system_step.observation.results[0].content == "is_likely_phishing: true" - # The non-agent observation maps without error and produces spans. + # Map the whole tree. The nested system step is emitted as its own span; + # previously the entire POST 422'd before any span could be stored. spans = trajectory_to_spans( workspace="default", trajectory=trajectory, ingested_at=datetime(2026, 1, 1, tzinfo=timezone.utc), ) - assert spans + system_span = next((s for s in spans if s.name == "system-1"), None) + assert system_span is not None, "nested system step should map to a span" + + # Guard the mapper fix: `_step_observation` must read observations on + # non-agent steps. If it regresses to agent-only (returns None), the + # observation is lost even though the POST is now accepted. + observation = _step_observation(system_step) + assert observation is not None + assert observation.results[0].content == "is_likely_phishing: true" From b6ff20a554f75895ef434675f3d7383dcc19a2ac Mon Sep 17 00:00:00 2001 From: Nathan Walston Date: Mon, 10 Aug 2026 12:20:35 -0700 Subject: [PATCH 3/5] chore(openapi): regenerate spec for ATIF observation on all step types The intake fix moved `observation` from `AtifStepAgent` to `AtifStepBase`, which changes the ATIF ingest contract: `observation` now appears on the `system` and `user` step schemas as well. Regenerated via `script/generate-openapi-spec.sh`; no hand edits. Co-authored-by: Yuchen Zhang <134643420+yczhang-nv@users.noreply.github.com> Signed-off-by: Nathan Walston --- openapi/ga/individual/platform.openapi.yaml | 8 ++++++-- openapi/ga/openapi.yaml | 8 ++++++-- openapi/openapi.yaml | 8 ++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/openapi/ga/individual/platform.openapi.yaml b/openapi/ga/individual/platform.openapi.yaml index 33a0d3c022..1d6704e7a2 100644 --- a/openapi/ga/individual/platform.openapi.yaml +++ b/openapi/ga/individual/platform.openapi.yaml @@ -8645,6 +8645,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: agent @@ -8665,8 +8667,6 @@ components: items: $ref: '#/components/schemas/AtifToolCall' type: array - observation: - $ref: '#/components/schemas/AtifObservation' metrics: $ref: '#/components/schemas/AtifMetrics' additionalProperties: false @@ -8704,6 +8704,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: system @@ -8743,6 +8745,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: user diff --git a/openapi/ga/openapi.yaml b/openapi/ga/openapi.yaml index 33a0d3c022..1d6704e7a2 100644 --- a/openapi/ga/openapi.yaml +++ b/openapi/ga/openapi.yaml @@ -8645,6 +8645,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: agent @@ -8665,8 +8667,6 @@ components: items: $ref: '#/components/schemas/AtifToolCall' type: array - observation: - $ref: '#/components/schemas/AtifObservation' metrics: $ref: '#/components/schemas/AtifMetrics' additionalProperties: false @@ -8704,6 +8704,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: system @@ -8743,6 +8745,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: user diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 33a0d3c022..1d6704e7a2 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -8645,6 +8645,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: agent @@ -8665,8 +8667,6 @@ components: items: $ref: '#/components/schemas/AtifToolCall' type: array - observation: - $ref: '#/components/schemas/AtifObservation' metrics: $ref: '#/components/schemas/AtifMetrics' additionalProperties: false @@ -8704,6 +8704,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: system @@ -8743,6 +8745,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: user From c44b99745221ef7d6e8ff94e524ea814e84a7bd2 Mon Sep 17 00:00:00 2001 From: Nathan Walston Date: Mon, 10 Aug 2026 12:32:09 -0700 Subject: [PATCH 4/5] chore(sdk): regenerate SDK for ATIF observation on all step types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stainless sync (`sdk/stainless.sh sync`) for the ATIF ingest contract change: `observation` moved from `AtifStepAgent` to `AtifStepBase`, so the generated `AtifStepSystemParam` / `AtifStepUserParam` models now carry it, and the `.nmpcontext` snapshot matches the regenerated spec (clears `lint-python-sdk`). Also sweeps one unrelated docstring-only update in `resources/jobs/jobs.py` (execution-profiles description), which was pre-existing drift on main picked up by the clean regen — generated output, not hand-edited. Co-authored-by: Yuchen Zhang <134643420+yczhang-nv@users.noreply.github.com> Signed-off-by: Nathan Walston --- .../nemo-platform/.nmpcontext/openapi.yaml | 8 ++- .../src/nemo_platform/resources/jobs/jobs.py | 18 ++++- .../intake/ingest/atif_step_system_param.py | 3 + .../intake/ingest/atif_step_user_param.py | 3 + .../api_resources/intake/ingest/test_atif.py | 68 +++++++++++++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml index 33a0d3c022..1d6704e7a2 100644 --- a/sdk/python/nemo-platform/.nmpcontext/openapi.yaml +++ b/sdk/python/nemo-platform/.nmpcontext/openapi.yaml @@ -8645,6 +8645,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: agent @@ -8665,8 +8667,6 @@ components: items: $ref: '#/components/schemas/AtifToolCall' type: array - observation: - $ref: '#/components/schemas/AtifObservation' metrics: $ref: '#/components/schemas/AtifMetrics' additionalProperties: false @@ -8704,6 +8704,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: system @@ -8743,6 +8745,8 @@ components: title: Llm Call Count type: integer minimum: 0.0 + observation: + $ref: '#/components/schemas/AtifObservation' source: type: string const: user diff --git a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py index 1c8bf65dbe..3fb1c4e410 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py +++ b/sdk/python/nemo-platform/src/nemo_platform/resources/jobs/jobs.py @@ -459,7 +459,14 @@ def list_execution_profiles( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JobListExecutionProfilesResponse: - """Get all currently configured execution profiles.""" + """ + Get all currently configured execution profiles. + + Returns the capability-filtered merge from jobs config. In local standalone the + controller may prune the shared list further after registry boot; in split + topologies the API advertises its own merge result (not controller process + memory). + """ return self._get( "/apis/jobs/v2/execution-profiles", options=make_request_options( @@ -971,7 +978,14 @@ async def list_execution_profiles( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> JobListExecutionProfilesResponse: - """Get all currently configured execution profiles.""" + """ + Get all currently configured execution profiles. + + Returns the capability-filtered merge from jobs config. In local standalone the + controller may prune the shared list further after registry boot; in split + topologies the API advertises its own merge result (not controller process + memory). + """ return await self._get( "/apis/jobs/v2/execution-profiles", options=make_request_options( diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_system_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_system_param.py index 3912b27870..58b30c6041 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_system_param.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_system_param.py @@ -22,6 +22,7 @@ from typing_extensions import Literal, Required, Annotated, TypedDict from ...._utils import PropertyInfo +from .atif_observation_param import AtifObservationParam from .atif_content_part_param import AtifContentPartParam __all__ = ["AtifStepSystemParam"] @@ -40,4 +41,6 @@ class AtifStepSystemParam(TypedDict, total=False): message: Union[str, Iterable[AtifContentPartParam]] + observation: AtifObservationParam + timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_user_param.py b/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_user_param.py index efe3d680f6..d3b2b491c3 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_user_param.py +++ b/sdk/python/nemo-platform/src/nemo_platform/types/intake/ingest/atif_step_user_param.py @@ -22,6 +22,7 @@ from typing_extensions import Literal, Required, Annotated, TypedDict from ...._utils import PropertyInfo +from .atif_observation_param import AtifObservationParam from .atif_content_part_param import AtifContentPartParam __all__ = ["AtifStepUserParam"] @@ -40,4 +41,6 @@ class AtifStepUserParam(TypedDict, total=False): message: Union[str, Iterable[AtifContentPartParam]] + observation: AtifObservationParam + timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/sdk/python/nemo-platform/tests/api_resources/intake/ingest/test_atif.py b/sdk/python/nemo-platform/tests/api_resources/intake/ingest/test_atif.py index 00c2dee527..bcad47fa9c 100644 --- a/sdk/python/nemo-platform/tests/api_resources/intake/ingest/test_atif.py +++ b/sdk/python/nemo-platform/tests/api_resources/intake/ingest/test_atif.py @@ -81,6 +81,23 @@ def test_method_create_with_all_params(self, client: NeMoPlatform) -> None: "is_copied_context": True, "llm_call_count": 0, "message": "string", + "observation": { + "results": [ + { + "content": "string", + "extra": {"foo": "bar"}, + "source_call_id": "source_call_id", + "subagent_trajectory_ref": [ + { + "extra": {"foo": "bar"}, + "session_id": "session_id", + "trajectory_id": "trajectory_id", + "trajectory_path": "trajectory_path", + } + ], + } + ] + }, "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), } ], @@ -118,6 +135,23 @@ def test_method_create_with_all_params(self, client: NeMoPlatform) -> None: "is_copied_context": True, "llm_call_count": 0, "message": "string", + "observation": { + "results": [ + { + "content": "string", + "extra": {"foo": "bar"}, + "source_call_id": "source_call_id", + "subagent_trajectory_ref": [ + { + "extra": {"foo": "bar"}, + "session_id": "session_id", + "trajectory_id": "trajectory_id", + "trajectory_path": "trajectory_path", + } + ], + } + ] + }, "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), } ], @@ -234,6 +268,23 @@ async def test_method_create_with_all_params(self, async_client: AsyncNeMoPlatfo "is_copied_context": True, "llm_call_count": 0, "message": "string", + "observation": { + "results": [ + { + "content": "string", + "extra": {"foo": "bar"}, + "source_call_id": "source_call_id", + "subagent_trajectory_ref": [ + { + "extra": {"foo": "bar"}, + "session_id": "session_id", + "trajectory_id": "trajectory_id", + "trajectory_path": "trajectory_path", + } + ], + } + ] + }, "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), } ], @@ -271,6 +322,23 @@ async def test_method_create_with_all_params(self, async_client: AsyncNeMoPlatfo "is_copied_context": True, "llm_call_count": 0, "message": "string", + "observation": { + "results": [ + { + "content": "string", + "extra": {"foo": "bar"}, + "source_call_id": "source_call_id", + "subagent_trajectory_ref": [ + { + "extra": {"foo": "bar"}, + "session_id": "session_id", + "trajectory_id": "trajectory_id", + "trajectory_path": "trajectory_path", + } + ], + } + ] + }, "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), } ], From 2a3841884e6775d31ded21e9d9d06c0b3ad1797f Mon Sep 17 00:00:00 2001 From: Nathan Walston Date: Mon, 10 Aug 2026 12:47:17 -0700 Subject: [PATCH 5/5] chore(cli): regenerate CLI commands and reference docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `lint-cli` runs `make update-cli` and fails if it dirties the tree. Running it regenerates the jobs execution-profiles docstring in the generated CLI command (and its vendored SDK copy + CLI reference docs). This is drift from #1082 (AIRCORE-971, merged to main today), which changed the jobs API docstring without regenerating the spec/SDK/CLI — swept up here by the clean regen, since the generators produce it deterministically and the branch cannot go green otherwise. Generated output, no hand edits. Co-authored-by: Yuchen Zhang <134643420+yczhang-nv@users.noreply.github.com> Signed-off-by: Nathan Walston --- docs/cli/reference.mdx | 5 +++++ .../nemo_platform_ext/cli/commands/api/jobs/__init__.py | 7 ++++++- .../src/nemo_platform/cli/commands/api/jobs/__init__.py | 7 ++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/cli/reference.mdx b/docs/cli/reference.mdx index 1681a493da..94d525e3b9 100644 --- a/docs/cli/reference.mdx +++ b/docs/cli/reference.mdx @@ -4047,6 +4047,11 @@ Filter jobs by workspace, project, name, status, source, created_at, and updated Get all currently configured execution profiles. +Returns the capability-filtered merge from jobs config. In local standalone the +controller may prune the shared list further after registry boot; in split +topologies the API advertises its own merge result (not controller process +memory). + **Usage:** ```shell diff --git a/packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/jobs/__init__.py b/packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/jobs/__init__.py index e0e6cfb653..cb367ab453 100644 --- a/packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/jobs/__init__.py +++ b/packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/jobs/__init__.py @@ -400,7 +400,12 @@ def list_execution_profiles_jobs( columns: OutputColumnsOption = None, stream: StreamOutputOption = False, ) -> None: - """Get all currently configured execution profiles.""" + """Get all currently configured execution profiles. + + Returns the capability-filtered merge from jobs config. In local standalone the + controller may prune the shared list further after registry boot; in split + topologies the API advertises its own merge result (not controller process + memory).""" state: CLIContext = ctx.obj output_format = state.get_output_format(output_format) validate_stream_output_format(output_format, stream) diff --git a/sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/jobs/__init__.py b/sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/jobs/__init__.py index 9a6fcc0b41..c0ac03827b 100644 --- a/sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/jobs/__init__.py +++ b/sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/jobs/__init__.py @@ -400,7 +400,12 @@ def list_execution_profiles_jobs( columns: OutputColumnsOption = None, stream: StreamOutputOption = False, ) -> None: - """Get all currently configured execution profiles.""" + """Get all currently configured execution profiles. + + Returns the capability-filtered merge from jobs config. In local standalone the + controller may prune the shared list further after registry boot; in split + topologies the API advertises its own merge result (not controller process + memory).""" state: CLIContext = ctx.obj output_format = state.get_output_format(output_format) validate_stream_output_format(output_format, stream)