From 71e8ea8dba38a323e9bbfde64f9f25a72bef09d8 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Fri, 7 Aug 2026 14:31:36 +0900 Subject: [PATCH] Python: track agent-hooks feature usage --- docs/specs/feature-usage-bit-registry.md | 3 ++- .../core/agent_framework/_agent_hooks.py | 2 ++ .../core/agent_framework/_telemetry.py | 1 + .../core/tests/core/test_agent_hooks.py | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/specs/feature-usage-bit-registry.md b/docs/specs/feature-usage-bit-registry.md index f4e1bcbd1c..6b89e4988f 100644 --- a/docs/specs/feature-usage-bit-registry.md +++ b/docs/specs/feature-usage-bit-registry.md @@ -136,7 +136,8 @@ only to approved first-party endpoints. | 15 | `core.in_memory_skills_source` | In-memory / programmatic skills | `agent_framework.InMemorySkillsSource` | | 16 | `core.mcp_skills_source` | MCP-backed skills | `agent_framework.MCPSkillsSource` | | 17 | `core.session_store` | Agent session store | `agent_framework.SessionStore` / `FileSessionStore` | -| 18–31 | _reserved_ | core growth | — | +| 18 | `core.agent_hooks` | Agent Hooks middleware | `agent_framework.create_agent_hooks_middleware` | +| 19–31 | _reserved_ | core growth | — | | 32 | `orchestration.sequential` | Sequential orchestration | `agent_framework_orchestrations.SequentialBuilder` | | 33 | `orchestration.concurrent` | Concurrent orchestration | `agent_framework_orchestrations.ConcurrentBuilder` | | 34 | `orchestration.group_chat` | Group-chat orchestration | `agent_framework_orchestrations.GroupChatBuilder` | diff --git a/python/packages/core/agent_framework/_agent_hooks.py b/python/packages/core/agent_framework/_agent_hooks.py index 669cdb262a..31c52f235d 100644 --- a/python/packages/core/agent_framework/_agent_hooks.py +++ b/python/packages/core/agent_framework/_agent_hooks.py @@ -120,6 +120,7 @@ _current_run_identity, # pyright: ignore[reportPrivateUsage] _RunPersistenceGate, # pyright: ignore[reportPrivateUsage] ) +from ._telemetry import FeatureIndex, mark_feature_used from ._types import ( AgentResponse, AgentResponseUpdate, @@ -1610,6 +1611,7 @@ def create_agent_hooks_middleware_from_emitter( def _build_bundle(config: _AgentHooksConfig) -> MiddlewareBundle: + mark_feature_used(FeatureIndex.CORE_AGENT_HOOKS) return MiddlewareBundle([ _AgentHooksAgentMiddleware(config), _AgentHooksChatMiddleware(config), diff --git a/python/packages/core/agent_framework/_telemetry.py b/python/packages/core/agent_framework/_telemetry.py index c133b9903d..955e276fe2 100644 --- a/python/packages/core/agent_framework/_telemetry.py +++ b/python/packages/core/agent_framework/_telemetry.py @@ -54,6 +54,7 @@ class FeatureIndex(IntEnum): CORE_IN_MEMORY_SKILLS_SOURCE = 15 CORE_MCP_SKILLS_SOURCE = 16 CORE_SESSION_STORE = 17 + CORE_AGENT_HOOKS = 18 # This environment variable is reserved by the Foundry hosting environment to diff --git a/python/packages/core/tests/core/test_agent_hooks.py b/python/packages/core/tests/core/test_agent_hooks.py index 347d7bae4f..a13b96baa0 100644 --- a/python/packages/core/tests/core/test_agent_hooks.py +++ b/python/packages/core/tests/core/test_agent_hooks.py @@ -9,6 +9,7 @@ import pytest import agent_framework +import agent_framework._telemetry as telemetry from agent_framework import ( Agent, AgentContext, @@ -155,6 +156,23 @@ def points(records: list[Any]) -> list[str]: # region Factory validation +@pytest.mark.parametrize("factory_kind", ["managed", "host_owned"]) +@requires_sdk +def test_agent_hooks_factories_activate_feature_telemetry(factory_kind: str, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(telemetry, "_feature_mask", 0) + monkeypatch.setattr(telemetry, "IS_TELEMETRY_ENABLED", True) + monkeypatch.setenv(telemetry.FEATURE_MASK_DISABLED_ENV_VAR, "false") + + if factory_kind == "managed": + create_agent_hooks_middleware([AllowGuard()]) + else: + emitter = InterceptionEmitter().register(AllowGuard()) + builder = AgentContextBuilder(agent_id="a", framework="agent-framework", session_id="s") + create_agent_hooks_middleware_from_emitter(emitter, builder) + + assert telemetry.get_feature_token() == "v1.40000" + + @requires_sdk async def test_factory_requires_interceptors() -> None: with pytest.raises(ValueError, match="at least one interceptor"):