Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/agentex/lib/core/tracing/code_revision.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from agentex.lib.utils.logging import make_logger

__all__ = ("COMMIT_SHA_KEY", "enable", "disable", "is_enabled", "commit_sha")
__all__ = ("COMMIT_SHA_KEY", "enable", "disable", "is_enabled", "commit_sha", "is_git_object_name")

logger = make_logger(__name__)

Expand All @@ -31,6 +31,12 @@
# git's own 7-character minimum.
_GIT_SHA_RE = re.compile(r"[0-9a-fA-F]{7,64}")


def is_git_object_name(value: str) -> bool:
"""Whether ``value`` is a full or abbreviated git SHA-1/SHA-256 object name."""
return _GIT_SHA_RE.fullmatch(value.strip()) is not None


_COMMIT_SHA_ENV = "AGENT_COMMIT_SHA"
# Fallback only: automatic, and only usable when it happens to be SHA-shaped.
_AGENT_VERSION_ENV = "AGENT_VERSION"
Expand Down
3 changes: 3 additions & 0 deletions src/agentex/lib/environment_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class EnvVarKeys(str, Enum):
AGENT_ID = "AGENT_ID"
AGENT_VERSION = "AGENT_VERSION"
AGENT_COMMIT_SHA = "AGENT_COMMIT_SHA"
AGENT_SOURCE_REPO = "AGENT_SOURCE_REPO"
AGENT_API_KEY = "AGENT_API_KEY"
# ACP Configuration
ACP_URL = "ACP_URL"
Expand Down Expand Up @@ -74,6 +75,8 @@ class EnvironmentVariables(BaseModel):
# `adk.code_revision.enable()`, which also refuses a value that is not a git
# object name. See agentex.lib.core.tracing.code_revision.
AGENT_COMMIT_SHA: str | None = None
# Git remote the agent was built from (any URL form; normalized to host/path on use).
AGENT_SOURCE_REPO: str | None = None
AGENT_API_KEY: str | None = None
ACP_TYPE: str | None = "async"
AGENT_INPUT_TYPE: str | None = None
Expand Down
3 changes: 2 additions & 1 deletion src/agentex/lib/utils/build_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def normalize_remote(url: Optional[str]) -> Optional[str]:
"""Strip credentials and scheme from a remote, returning ``host/path``."""
if not url:
return None
candidate = url.strip()
# Query strings and fragments never name a repo, but they do carry tokens.
candidate = url.strip().split("?", 1)[0].split("#", 1)[0]
# scp-like syntax: git@host:org/repo(.git) — no scheme, host/path split on ':'
if "://" not in candidate and ":" in candidate and "/" not in candidate.split(":", 1)[0]:
candidate = candidate.split("@", 1)[-1].replace(":", "/", 1)
Expand Down
33 changes: 26 additions & 7 deletions src/agentex/lib/utils/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from agentex.lib.utils.logging import make_logger
from agentex.lib.environment_variables import EnvironmentVariables
from agentex.lib.utils.build_provenance import normalize_remote
from agentex.lib.core.tracing.code_revision import is_git_object_name

logger = make_logger(__name__)

Expand All @@ -20,6 +22,29 @@ def get_auth_principal(env_vars: EnvironmentVariables):
except Exception:
return None


def build_registration_metadata(env_vars: EnvironmentVariables, agent_card=None) -> dict:
"""Deployment id, source provenance, and agent card; keys appear only when known."""
metadata: dict = {}
if env_vars.AGENTEX_DEPLOYMENT_ID:
metadata["deployment_id"] = env_vars.AGENTEX_DEPLOYMENT_ID
commit = (env_vars.AGENT_COMMIT_SHA or "").strip()
if commit:
if is_git_object_name(commit):
metadata["commit_sha"] = commit
else:
logger.warning(
"AGENT_COMMIT_SHA=%r is not a git commit SHA; commit_sha omitted from registration.",
commit,
)
repo = normalize_remote(env_vars.AGENT_SOURCE_REPO)
Comment thread
max-parke-scale marked this conversation as resolved.
if repo:
metadata["source_repo"] = repo
Comment thread
max-parke-scale marked this conversation as resolved.
if agent_card is not None:
metadata["agent_card"] = agent_card.model_dump() if hasattr(agent_card, "model_dump") else agent_card
return metadata


async def register_agent(env_vars: EnvironmentVariables, agent_card=None):
"""Register this agent with the Agentex server"""
if not env_vars.AGENTEX_BASE_URL:
Expand All @@ -33,13 +58,7 @@ async def register_agent(env_vars: EnvironmentVariables, agent_card=None):
or f"Generic description for agent: {env_vars.AGENT_NAME}"
)

# Registration metadata carries the deployment id and agent card.
registration_metadata: dict = {}
if env_vars.AGENTEX_DEPLOYMENT_ID:
registration_metadata["deployment_id"] = env_vars.AGENTEX_DEPLOYMENT_ID
if agent_card is not None:
card_data = agent_card.model_dump() if hasattr(agent_card, "model_dump") else agent_card
registration_metadata["agent_card"] = card_data
registration_metadata = build_registration_metadata(env_vars, agent_card)

# Prepare registration data
registration_data = {
Expand Down
2 changes: 2 additions & 0 deletions tests/lib/test_agent_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ def mock_env_vars(self):
"AGENT_ID": None,
"AGENT_INPUT_TYPE": None,
"AGENT_API_KEY": None,
"AGENT_COMMIT_SHA": None,
"AGENT_SOURCE_REPO": None,
"AGENTEX_DEPLOYMENT_ID": None,
})()
return mock
Expand Down
1 change: 1 addition & 0 deletions tests/lib/test_build_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def _write(root: Path, rel: str, content: str = "x") -> None:
("https://github.com/scaleapi/Repo.git", "github.com/scaleapi/Repo"),
("https://x-token:secret@GitHub.com/scaleapi/Repo", "github.com/scaleapi/Repo"),
("ssh://git@gitlab.com/group/sub/proj.git", "gitlab.com/group/sub/proj"),
("https://github.com/scaleapi/Repo.git?access_token=SECRET#frag", "github.com/scaleapi/Repo"),
("", None),
(None, None),
],
Expand Down
49 changes: 49 additions & 0 deletions tests/lib/utils/test_registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Registration metadata: what an agent reports about itself at startup."""

from __future__ import annotations

import pytest

from agentex.lib.utils.registration import build_registration_metadata
from agentex.lib.environment_variables import EnvironmentVariables

SHA = "b362b171a9c4e1f09d8e7a6b5c4d3e2f1a0b9c8d"


def _env(**overrides) -> EnvironmentVariables:
return EnvironmentVariables(AGENT_NAME="sample-agent", ACP_URL="http://agent", **overrides)


def test_nothing_known_yields_empty_metadata():
assert build_registration_metadata(_env()) == {}


def test_commit_and_repo_reported_when_set():
env = _env(AGENT_COMMIT_SHA=SHA, AGENT_SOURCE_REPO="git@github.com:scaleapi/Demo.git")
assert build_registration_metadata(env) == {
"commit_sha": SHA,
"source_repo": "github.com/scaleapi/Demo",
}


@pytest.mark.parametrize("value", ["latest", "v1.2.3", "rocket_mock_agent-" + SHA, "abc", " "])
def test_non_commit_values_are_omitted_not_forwarded(value):
"""A field named for a commit never holds an image tag, same rule as __commit_sha__."""
assert "commit_sha" not in build_registration_metadata(_env(AGENT_COMMIT_SHA=value))


def test_repo_normalization_strips_scheme_and_credentials():
env = _env(AGENT_SOURCE_REPO="https://x-token:secret@GitHub.com/scaleapi/Demo.git")
assert build_registration_metadata(env)["source_repo"] == "github.com/scaleapi/Demo"


def test_deployment_id_and_agent_card_still_reported():
class Card:
def model_dump(self):
return {"name": "sample"}

env = _env(AGENTEX_DEPLOYMENT_ID="dep-1")
assert build_registration_metadata(env, Card()) == {
"deployment_id": "dep-1",
"agent_card": {"name": "sample"},
}
Loading