diff --git a/src/agentex/lib/core/tracing/code_revision.py b/src/agentex/lib/core/tracing/code_revision.py index 7b08dd45f..2c6f96292 100644 --- a/src/agentex/lib/core/tracing/code_revision.py +++ b/src/agentex/lib/core/tracing/code_revision.py @@ -1,10 +1,11 @@ -"""Opt-in stamping of the agent's source commit onto its spans. +"""Stamping of the agent's source commit onto its spans. -Nothing is stamped until the agent calls :func:`enable`, mirroring the -``lineage`` registry next door: a process-wide switch the agent sets once at -import, rather than automatic behaviour every agent inherits. When enabled the -resolved commit lands in span data under ``__commit_sha__`` and is searchable in -the SGP Traces UI as ``__commit_sha__:``. +Stamping turns on when the process starts with ``AGENT_COMMIT_SHA`` set, which +the SGP cloud deploy does from the build record's attested commit, or when the +agent calls :func:`enable` itself. Nothing is stamped otherwise: upgrading the +SDK alone never starts emitting the field. When on, the resolved commit lands in +span data under ``__commit_sha__`` and is searchable in the SGP Traces UI as +``__commit_sha__:``. This is deliberately separate from ``__agent_version__``, which is automatic and carries the deployed image tag verbatim ("image tag or git sha"). That tag is a @@ -42,13 +43,16 @@ def enable(commit_sha: str | None = None) -> None: - """Opt this process in to stamping ``__commit_sha__`` onto every span. + """Turn on stamping ``__commit_sha__`` onto every span from this process. Value precedence: the explicit ``commit_sha`` argument, else ``AGENT_COMMIT_SHA``, else ``AGENT_VERSION`` when the deployment happened to set it to a bare commit SHA. A value that is not a git object name is refused with a warning and leaves stamping off -- better an absent field than one named for a commit that holds an image tag. + + Called once at import when ``AGENT_COMMIT_SHA`` is set, so a deployment that + supplies the commit needs no code change in the agent. """ global _commit_sha @@ -103,3 +107,12 @@ def is_enabled() -> bool: def commit_sha() -> str | None: """The resolved commit SHA, or ``None`` when stamping is not enabled.""" return _commit_sha + + +def _enable_from_environment() -> None: + """Auto-enable on ``AGENT_COMMIT_SHA`` only; ``AGENT_VERSION`` stays an explicit fallback.""" + if os.environ.get(_COMMIT_SHA_ENV, "").strip(): + enable() + + +_enable_from_environment() diff --git a/src/agentex/lib/environment_variables.py b/src/agentex/lib/environment_variables.py index 00dbbaada..7492037ce 100644 --- a/src/agentex/lib/environment_variables.py +++ b/src/agentex/lib/environment_variables.py @@ -68,11 +68,8 @@ class EnvironmentVariables(BaseModel): AGENT_ID: str | None = None # Build/version discriminator (image tag or git sha), set by the deployment AGENT_VERSION: str | None = None - # The agent's source commit, baked into the image or set by the deployment. - # Unlike AGENT_VERSION this is expected to be a git SHA and nothing else, and - # it is OPT-IN: nothing is stamped unless the agent calls - # `adk.code_revision.enable()`, which also refuses a value that is not a git - # object name. See agentex.lib.core.tracing.code_revision. + # The agent's source commit, set by the deployment or baked into the image; a git + # SHA and nothing else. Stamped as __commit_sha__ when set (see tracing.code_revision). AGENT_COMMIT_SHA: str | None = None AGENT_API_KEY: str | None = None ACP_TYPE: str | None = "async" diff --git a/tests/lib/core/tracing/processors/test_sgp_tracing_processor.py b/tests/lib/core/tracing/processors/test_sgp_tracing_processor.py index 6cd324f01..7b5c129d6 100644 --- a/tests/lib/core/tracing/processors/test_sgp_tracing_processor.py +++ b/tests/lib/core/tracing/processors/test_sgp_tracing_processor.py @@ -56,13 +56,13 @@ def test_agent_identity_and_version_stamped_into_span_data(self): SHA = "b362b171a9c4e1f09d8e7a6b5c4d3e2f1a0b9c8d" - def test_commit_sha_is_not_stamped_without_opt_in(self, monkeypatch): - """Upgrading the SDK must not start emitting __commit_sha__ on its own, - even when the environment carries a perfectly good SHA.""" + def test_commit_sha_is_not_stamped_when_env_absent(self, monkeypatch): + """Upgrading the SDK must not start emitting __commit_sha__ on its own; + only AGENT_COMMIT_SHA or an enable() call turns it on.""" from agentex.lib.core.tracing import code_revision from agentex.lib.core.tracing.processors.sgp_tracing_processor import _sgp_metadata - monkeypatch.setenv("AGENT_COMMIT_SHA", self.SHA) + monkeypatch.delenv("AGENT_COMMIT_SHA", raising=False) code_revision.disable() span = _make_span(); span.data = {} diff --git a/tests/lib/core/tracing/test_code_revision.py b/tests/lib/core/tracing/test_code_revision.py index 0b89b88f2..a696129d7 100644 --- a/tests/lib/core/tracing/test_code_revision.py +++ b/tests/lib/core/tracing/test_code_revision.py @@ -1,7 +1,8 @@ -"""Opt-in commit-SHA stamping. +"""Commit-SHA stamping. -The contract that matters: an agent that does not call ``enable()`` gets nothing, -so upgrading the SDK never starts emitting this field on its own. +The contract that matters: with ``AGENT_COMMIT_SHA`` absent and no ``enable()`` +call, nothing is stamped, so upgrading the SDK never starts emitting this field +on its own. A deployment that sets the env var turns it on without agent code. """ from __future__ import annotations @@ -21,14 +22,33 @@ def _reset(): code_revision.disable() -class TestOptIn: - def test_disabled_by_default(self, monkeypatch): - """Even with the env fully populated, nothing resolves until enable().""" - monkeypatch.setenv("AGENT_COMMIT_SHA", SHA) +class TestEnablement: + def test_off_when_env_absent(self, monkeypatch): + """The import-time hook ignores AGENT_VERSION; that fallback needs enable().""" + monkeypatch.delenv("AGENT_COMMIT_SHA", raising=False) monkeypatch.setenv("AGENT_VERSION", SHA) + code_revision._enable_from_environment() assert code_revision.commit_sha() is None assert code_revision.is_enabled() is False + def test_env_set_at_startup_enables_without_a_call(self, monkeypatch): + """The cloud deploy sets AGENT_COMMIT_SHA from the build record; the agent + should not need to know.""" + monkeypatch.setenv("AGENT_COMMIT_SHA", SHA) + code_revision._enable_from_environment() + assert code_revision.commit_sha() == SHA + + def test_env_set_after_import_needs_enable(self, monkeypatch): + monkeypatch.setenv("AGENT_COMMIT_SHA", SHA) + assert code_revision.commit_sha() is None + code_revision.enable() + assert code_revision.commit_sha() == SHA + + def test_bad_env_at_startup_leaves_it_off(self, monkeypatch): + monkeypatch.setenv("AGENT_COMMIT_SHA", "latest") + code_revision._enable_from_environment() + assert code_revision.commit_sha() is None + def test_enable_reads_agent_commit_sha(self, monkeypatch): monkeypatch.setenv("AGENT_COMMIT_SHA", SHA) code_revision.enable()