Source code for nvflare.client.cell.defs

# Copyright (c) 2026, NVIDIA CORPORATION.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Protocol vocabulary for the Client API control protocol over Cell.

This module is the frozen control-protocol vocabulary of the Client API Execution
Modes design (docs/design/client_api_execution_modes.md, "Control Protocol"). It is consumed by the
trainer-side Cell engine, the external_process backend, and the attach backend. It is a
pure vocabulary module: constants only, no Cell/cellnet imports, no I/O.
"""

# Cell channel used for all Client API control protocol messages.
# Clearly namespaced so it cannot collide with the legacy FlareAgent channel
# ("flare_agent" in nvflare/client/ipc/defs.py) or other Cell channels.
# This is a frozen wire constant; its exact value is part of the cross-track contract.
CHANNEL = "client_api"

# The Client API control protocol version carried in HELLO.
# V1 supports exactly one protocol version; the field exists so later versions
# can define a compatibility window.
PROTOCOL_VERSION = 1


[docs] class Topic: """Topics of the Client API control protocol messages over the Cell CHANNEL. Reply-type messages (HELLO_CHALLENGE, HELLO_ACCEPTED, TASK_ACCEPTED, RESULT_ACCEPTED, RESULT_REJECTED) may be modeled as Cell request replies at runtime rather than separate sends; the constants still name them so state machines, logs, and tests share one vocabulary. Values are prefixed with "client_api." so they never collide with legacy topic values (e.g. "hello"/"heartbeat"/"abort"/"bye" in nvflare/client/ipc/defs.py). """ # Session setup (all out-of-process modes) HELLO = "client_api.hello" HELLO_CHALLENGE = "client_api.hello_challenge" HELLO_PROOF = "client_api.hello_proof" HELLO_ACCEPTED = "client_api.hello_accepted" # Distinct from ERROR (a protocol/transport error): HELLO_REJECTED is a clean, semantic # auth/handshake refusal (bad proof, wrong scope, consumed/expired nonce, single-session), # so consumers can tell a recoverable auth failure from a protocol fault. HELLO_REJECTED = "client_api.hello_rejected" # Per task (every round) TASK_READY = "client_api.task_ready" TASK_ACCEPTED = "client_api.task_accepted" # Sent when the trainer has materialized (or lazily bound) the task payload and hands # it to user code. Ends the payload-materialization phase: the forward-path heartbeat # exemption stops here and heartbeats govern the session lease while user code trains. TASK_PAYLOAD_READY = "client_api.task_payload_ready" TASK_FAILED = "client_api.task_failed" RESULT_READY = "client_api.result_ready" RESULT_ACCEPTED = "client_api.result_accepted" RESULT_REJECTED = "client_api.result_rejected" # Throughout the session LOG = "client_api.log" HEARTBEAT = "client_api.heartbeat" # Teardown / failure ABORT = "client_api.abort" SHUTDOWN = "client_api.shutdown" BYE = "client_api.bye" ERROR = "client_api.error"
[docs] class MsgKey: """Keys for Client API control protocol message payloads. These string values are the frozen wire contract shared across tracks; renaming a value is a protocol break, not a refactor. """ SESSION_ID = "session_id" ATTACH_ID = "attach_id" JOB_ID = "job_id" SITE_NAME = "site_name" TRAINER_FQCN = "trainer_fqcn" TARGET_FQCN = "target_fqcn" RANK = "rank" # Rank policy the session is scoped to (a TokenScope / HELLO_PROOF-covered field); # distinct from RANK, which is the concrete rank a trainer reports in HELLO. RANK_POLICY = "rank_policy" PROTOCOL_VERSION = "protocol_version" NONCE = "nonce" PROOF = "proof" REASON = "reason" TASK_ID = "task_id" # TASK_READY carries the task name alongside the task id. TASK_NAME = "task_name" # TASK_READY carries the FLModel reference and its params (lazy refs, not materialized bytes). MODEL = "model" PARAMS = "params" RESULT_ID = "result_id" TRANSFER_ID = "transfer_id" # RESULT_READY carries the payload manifest describing the result envelope. MANIFEST = "manifest"