Stage 3: Implement Execution

View as Markdown

One NVIDIA NeMo Fabric runtime is a lifecycle, state-isolation, and correlation boundary. It does not require a particular process, service, thread, or native target session topology.

Implement the Required Lifecycle

The minimum adapter implements these operations:

OperationAdapter Responsibility
startValidate startup-only requirements, translate AgentConfig, and retain one isolated target runtime.
invokeTranslate one AgentRunRequest, execute the retained target, and return one AgentRunResult.
stopAttempt to release every adapter-owned resource, including after partial startup or failed invocation.

The required order is one successful start, zero or more ordered invoke operations, and one stop attempt. The minimum profile permits one active invocation in a runtime. The adapter does not need a queue or internal concurrency; consumers start independent runtimes for parallel work.

Keep mutable target state inside the runtime instance. Do not share it between independent Fabric runtimes.

Start From the Minimum Python Host

Python adapters can opt into nemo-fabric-adapters-common instead of implementing the persistent local-host binding. The following implementation shows the complete method surface:

1from nemo_fabric_adapter_contract.models import AgentConfig
2from nemo_fabric_adapter_contract.models import AgentRunError
3from nemo_fabric_adapter_contract.models import AgentRunRequest
4from nemo_fabric_adapter_contract.models import AgentRunResult
5from nemo_fabric_adapter_contract.models import AgentRunStatus
6from nemo_fabric_adapter_contract.models import RuntimeContext
7from nemo_fabric_adapters.common import lifecycle
8
9
10class TargetRuntime:
11 def __init__(self):
12 self.target = None
13
14 async def start(self, payload):
15 config: AgentConfig = payload["config"]
16 target = await create_target(config)
17 self.target = target
18
19 async def invoke(
20 self,
21 request: AgentRunRequest,
22 context: RuntimeContext,
23 ) -> AgentRunResult:
24 try:
25 native = await self.target.run(request.input)
26 except TargetInvocationError: # Use the target SDK's documented failure type.
27 return AgentRunResult(
28 status=AgentRunStatus.FAILED,
29 error=AgentRunError(
30 code="target_failed",
31 message="The target could not complete the invocation",
32 ),
33 )
34 return AgentRunResult(
35 status=AgentRunStatus.SUCCEEDED,
36 output={"response": native.text},
37 )
38
39 async def stop(self):
40 target, self.target = self.target, None
41 if target is not None:
42 await target.close()
43
44
45def main() -> None:
46 lifecycle.serve(TargetRuntime, config_loader=AgentConfig.from_mapping)
47
48
49if __name__ == "__main__":
50 main()

The host creates one TargetRuntime per local host, validates the start config as AgentConfig, passes typed request and context objects to invoke, requires a typed terminal result, serializes lifecycle operations, reserves stdout for its wire protocol, and attempts cleanup on end of file. The common host is optional; an adapter can implement another supported binding directly.

The target factory must release resources it creates if it fails before returning. Once the factory returns, retain the target immediately. Make stop idempotent, clear retained state even if cleanup fails, and keep it safe after a failed invocation. A no-op stop is valid for a thin remote-service adapter that owns no remote lifecycle, but it must still complete successfully.

Use RuntimeContext for Operation Context

NeMo Fabric creates RuntimeContext. Treat every ID as an opaque correlation value:

FieldPurpose
runtime_idCorrelates all operations in one Fabric runtime.
invocation_idIdentifies one invocation attempt.
request_idCorrelates the caller’s request through NeMo Fabric and the adapter.
environmentSupplies the resolved workspace, artifact root, environment values, ownership, and provider context.
artifactsLists artifacts visible when the operation begins.
telemetrySupplies invocation telemetry context, including generated Relay configuration when enabled.

Use the canonical runtime-context.schema.json for the exact shape. Runtime identity belongs in RuntimeContext, not in AgentConfig.workflow. Per-invocation task input belongs in the request, not in workflow settings.

Propagate Failures Safely

Use a lifecycle failure when the adapter cannot satisfy start, invoke, or stop, including protocol and transport failures. A lifecycle failure can invalidate the runtime.

A target-level failure is an AgentRunResult with status=FAILED and an AgentRunError. Do not expose stack traces, credentials, complete environment values, HTTP authorization headers, or arbitrary user input in errors or logs. NeMo Fabric does not automatically replay an invocation after a transport failure.

Add Streaming Only When Needed

Runtime.invoke_stream() is the primary normalized streaming API. It runs the ordinary adapter invoke operation while NeMo Relay exposes correlated ATOF to the consumer. NeMo Fabric owns ingestion, correlation, buffering, backpressure, and the consumer stream lifecycle.

The event stream and terminal result describe the same invocation but are delivered separately. An empty stream can have a valid result, stream exhaustion does not imply success, and closing the consumer stream does not cancel the target invocation.

An adapter that needs native progressive output can implement the narrower invoke_openai_stream capability. No other target-native event formats are part of v1alpha2.

The descriptor also contains reserved cancellation, updates, and service capability flags. Do not claim them until the selected NeMo Fabric runtime binding exposes and tests the corresponding adapter operation.

After the lifecycle works, normalize its terminal outcomes.