Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: coverage-models.xml,coverage-engine.xml,coverage-server.xml,coverage-sdk.xml
files: coverage-models.xml,coverage-engine.xml,coverage-telemetry.xml,coverage-server.xml,coverage-sdk.xml
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}

Expand Down
36 changes: 28 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
.PHONY: help sync openapi-spec openapi-spec-check test test-extras test-all models-test test-models test-sdk lint lint-fix typecheck check build build-models build-server build-sdk publish publish-models publish-server publish-sdk hooks-install hooks-uninstall prepush evaluators-test evaluators-lint evaluators-lint-fix evaluators-typecheck evaluators-build galileo-test galileo-lint galileo-lint-fix galileo-typecheck galileo-build sdk-ts-generate sdk-ts-overlay-test sdk-ts-name-check sdk-ts-generate-check sdk-ts-build sdk-ts-test sdk-ts-lint sdk-ts-typecheck sdk-ts-release-check sdk-ts-publish-dry-run sdk-ts-publish
.PHONY: help sync openapi-spec openapi-spec-check test test-extras test-all models-test test-models test-sdk lint lint-fix typecheck check build build-models build-server build-sdk publish publish-models publish-server publish-sdk hooks-install hooks-uninstall prepush evaluators-test evaluators-lint evaluators-lint-fix evaluators-typecheck evaluators-build galileo-test galileo-lint galileo-lint-fix galileo-typecheck galileo-build sdk-ts-generate sdk-ts-overlay-test sdk-ts-name-check sdk-ts-generate-check sdk-ts-build sdk-ts-test sdk-ts-lint sdk-ts-typecheck sdk-ts-release-check sdk-ts-publish-dry-run sdk-ts-publish telemetry-test telemetry-lint telemetry-lint-fix telemetry-typecheck telemetry-build telemetry-publish

# Workspace package names
PACK_MODELS := agent-control-models
PACK_SERVER := agent-control-server
PACK_SDK := agent-control
PACK_ENGINE := agent-control-engine
PACK_TELEMETRY := agent-control-telemetry
PACK_EVALUATORS := agent-control-evaluators
OPENAPI_SPEC_PATH := server/.generated/openapi.json

Expand All @@ -14,6 +15,7 @@ SERVER_DIR := server
SDK_DIR := sdks/python
TS_SDK_DIR := sdks/typescript
ENGINE_DIR := engine
TELEMETRY_DIR := telemetry
EVALUATORS_DIR := evaluators/builtin
GALILEO_DIR := evaluators/contrib/galileo
UI_DIR := ui
Expand All @@ -31,7 +33,7 @@ help:
@echo " make openapi-spec-check - verify OpenAPI generation succeeds"
@echo ""
@echo "Test:"
@echo " make test - run tests for core packages (models, server, engine, sdk, evaluators)"
@echo " make test - run tests for core packages (models, telemetry, server, engine, sdk, evaluators)"
@echo " make models-test - run shared model tests with coverage"
@echo " make test-extras - run tests for contrib evaluators (galileo, etc.)"
@echo " make test-all - run all tests (core + extras)"
Expand Down Expand Up @@ -82,13 +84,16 @@ openapi-spec-check: openapi-spec
# Test
# ---------------------------

test: models-test server-test engine-test sdk-test evaluators-test
test: models-test telemetry-test server-test engine-test sdk-test evaluators-test

models-test:
cd $(MODELS_DIR) && uv run pytest --cov=src --cov-report=xml:../coverage-models.xml -q

test-models: models-test

telemetry-test:
$(MAKE) -C $(TELEMETRY_DIR) test

# Run tests for contrib evaluators (not included in default test target)
test-extras: galileo-test

Expand All @@ -102,26 +107,35 @@ check: test lint typecheck
# Quality
# ---------------------------

lint: engine-lint evaluators-lint
lint: engine-lint telemetry-lint evaluators-lint
uv run --package $(PACK_MODELS) ruff check --config pyproject.toml models/src
uv run --package $(PACK_SERVER) ruff check --config pyproject.toml server/src
uv run --package $(PACK_SDK) ruff check --config pyproject.toml sdks/python/src

lint-fix: engine-lint-fix evaluators-lint-fix
lint-fix: engine-lint-fix telemetry-lint-fix evaluators-lint-fix
uv run --package $(PACK_MODELS) ruff check --config pyproject.toml --fix models/src
uv run --package $(PACK_SERVER) ruff check --config pyproject.toml --fix server/src
uv run --package $(PACK_SDK) ruff check --config pyproject.toml --fix sdks/python/src

typecheck: engine-typecheck evaluators-typecheck
typecheck: engine-typecheck telemetry-typecheck evaluators-typecheck
uv run --package $(PACK_MODELS) mypy --config-file pyproject.toml models/src
uv run --package $(PACK_SERVER) mypy --config-file pyproject.toml server/src
uv run --package $(PACK_SDK) mypy --config-file pyproject.toml sdks/python/src

telemetry-lint:
$(MAKE) -C $(TELEMETRY_DIR) lint

telemetry-lint-fix:
$(MAKE) -C $(TELEMETRY_DIR) lint-fix

telemetry-typecheck:
$(MAKE) -C $(TELEMETRY_DIR) typecheck

# ---------------------------
# Build / Publish
# ---------------------------

build: build-models build-server build-sdk engine-build evaluators-build
build: build-models build-server build-sdk engine-build telemetry-build evaluators-build

build-models:
cd $(MODELS_DIR) && uv build
Expand All @@ -132,7 +146,10 @@ build-server:
build-sdk:
cd $(SDK_DIR) && uv build

publish: publish-models publish-server publish-sdk engine-publish
telemetry-build:
cd $(TELEMETRY_DIR) && uv build

publish: publish-models publish-server publish-sdk engine-publish telemetry-publish

publish-models:
cd $(MODELS_DIR) && uv publish
Expand All @@ -143,6 +160,9 @@ publish-server:
publish-sdk:
cd $(SDK_DIR) && uv publish

telemetry-publish:
cd $(TELEMETRY_DIR) && uv publish

# ---------------------------
# Git hooks
# ---------------------------
Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ fixes:
- "agent_control_engine/::engine/src/agent_control_engine/"
- "agent_control_models/::models/src/agent_control_models/"
- "agent_control_evaluators/::evaluators/builtin/src/agent_control_evaluators/"
- "agent_control_telemetry/::telemetry/src/agent_control_telemetry/"
- "agent_control/::sdks/python/src/agent_control/"
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
"models",
"server",
"sdks/python",
"telemetry",
"engine",
"evaluators/builtin",
# NOTE: evaluators/contrib/* excluded - install separately when needed
Expand All @@ -36,6 +37,7 @@ required-environments = [
agent-control-models = { workspace = true }
agent-control-engine = { workspace = true }
agent-control-evaluators = { workspace = true }
agent-control-telemetry = { workspace = true }

[tool.ruff]
line-length = 100
Expand Down Expand Up @@ -68,6 +70,7 @@ version_toml = [
"models/pyproject.toml:project.version",
"engine/pyproject.toml:project.version",
"sdks/python/pyproject.toml:project.version",
"telemetry/pyproject.toml:project.version",
"server/pyproject.toml:project.version",
"evaluators/builtin/pyproject.toml:project.version",
"evaluators/contrib/galileo/pyproject.toml:project.version",
Expand Down
32 changes: 25 additions & 7 deletions scripts/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"""Build packages for PyPI distribution.

This script builds all publishable packages. For SDK and server, it copies internal
packages (models, engine) into the source directories before building, then cleans up
afterward. This allows the published wheels to be self-contained.
packages (models, engine, telemetry) into the source directories before building,
then cleans up afterward. This allows the published wheels to be self-contained.

Usage:
python scripts/build.py [models|evaluators|sdk|server|galileo|all]
Expand Down Expand Up @@ -81,7 +81,7 @@ def build_sdk() -> None:
print(f"Building agent-control-sdk v{version}")

# Clean previous builds and vendored code
for pkg in ["agent_control_models", "agent_control_engine"]:
for pkg in ["agent_control_models", "agent_control_engine", "agent_control_telemetry"]:
target = sdk_src / pkg
if target.exists():
shutil.rmtree(target)
Expand All @@ -99,6 +99,10 @@ def build_sdk() -> None:
ROOT / "engine" / "src" / "agent_control_engine",
sdk_src / "agent_control_engine",
)
shutil.copytree(
ROOT / "telemetry" / "src" / "agent_control_telemetry",
sdk_src / "agent_control_telemetry",
)

# Inject bundle metadata for conflict detection
inject_bundle_metadata(
Expand All @@ -111,6 +115,11 @@ def build_sdk() -> None:
"agent-control-sdk",
version,
)
inject_bundle_metadata(
sdk_src / "agent_control_telemetry" / "__init__.py",
"agent-control-sdk",
version,
)

# Set version
set_package_version(sdk_dir / "pyproject.toml", version)
Expand All @@ -120,7 +129,7 @@ def build_sdk() -> None:
print(f" Built agent-control-sdk v{version}")
finally:
# Clean up vendored code (don't commit it)
for pkg in ["agent_control_models", "agent_control_engine"]:
for pkg in ["agent_control_models", "agent_control_engine", "agent_control_telemetry"]:
target = sdk_src / pkg
if target.exists():
shutil.rmtree(target)
Expand All @@ -139,7 +148,7 @@ def build_server() -> None:
print(f"Building agent-control-server v{version}")

# Clean previous builds and vendored code
for pkg in ["agent_control_models", "agent_control_engine"]:
for pkg in ["agent_control_models", "agent_control_engine", "agent_control_telemetry"]:
target = server_src / pkg
if target.exists():
shutil.rmtree(target)
Expand All @@ -148,7 +157,7 @@ def build_server() -> None:
if dist_dir.exists():
shutil.rmtree(dist_dir)

# Copy vendored packages (models and engine only, NOT evaluators)
# Copy vendored packages (models, engine, and telemetry only, NOT evaluators)
shutil.copytree(
ROOT / "models" / "src" / "agent_control_models",
server_src / "agent_control_models",
Expand All @@ -157,6 +166,10 @@ def build_server() -> None:
ROOT / "engine" / "src" / "agent_control_engine",
server_src / "agent_control_engine",
)
shutil.copytree(
ROOT / "telemetry" / "src" / "agent_control_telemetry",
server_src / "agent_control_telemetry",
)

# Inject bundle metadata for conflict detection
inject_bundle_metadata(
Expand All @@ -169,6 +182,11 @@ def build_server() -> None:
"agent-control-server",
version,
)
inject_bundle_metadata(
server_src / "agent_control_telemetry" / "__init__.py",
"agent-control-server",
version,
)

# Set version
set_package_version(server_dir / "pyproject.toml", version)
Expand All @@ -178,7 +196,7 @@ def build_server() -> None:
print(f" Built agent-control-server v{version}")
finally:
# Clean up vendored code (don't commit it)
for pkg in ["agent_control_models", "agent_control_engine"]:
for pkg in ["agent_control_models", "agent_control_engine", "agent_control_telemetry"]:
target = server_src / pkg
if target.exists():
shutil.rmtree(target)
Expand Down
15 changes: 12 additions & 3 deletions sdks/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name = "agent-control-sdk"
version = "7.3.2"
description = "Python SDK for Agent Control - protect your AI agents with controls"
requires-python = ">=3.12"
# Note: agent-control-models and agent-control-engine are bundled at build time
# Note: agent-control-models, agent-control-engine, and agent-control-telemetry
# are bundled at build time
# Note: agent-control-evaluators is a runtime dependency (NOT vendored) to avoid
# duplicate module conflict when galileo extras are installed
dependencies = [
Expand Down Expand Up @@ -48,6 +49,7 @@ dev = [
"mypy>=1.8.0",
"agent-control-models",
"agent-control-engine",
"agent-control-telemetry",
"agent-control-evaluators",
"strands-agents>=1.26.0", # For strands integration tests
]
Expand All @@ -57,8 +59,14 @@ requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
# Note: agent_control_models and agent_control_engine are copied by scripts/build.py
packages = ["src/agent_control", "src/agent_control_models", "src/agent_control_engine"]
# Note: agent_control_models, agent_control_engine, and agent_control_telemetry
# are copied by scripts/build.py
packages = [
"src/agent_control",
"src/agent_control_models",
"src/agent_control_engine",
"src/agent_control_telemetry",
]

[tool.ruff]
line-length = 100
Expand All @@ -80,6 +88,7 @@ known-first-party = ["agent_control"]
[tool.uv.sources]
agent-control-models = { workspace = true }
agent-control-engine = { workspace = true }
agent-control-telemetry = { workspace = true }
agent-control-evaluators = { workspace = true }
# For local dev: use local galileo package instead of PyPI
agent-control-evaluator-galileo = { path = "../../evaluators/contrib/galileo", editable = true }
14 changes: 9 additions & 5 deletions sdks/python/src/agent_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ async def handle_input(user_message: str) -> str:
Step,
StepSchema,
)
from agent_control_telemetry.trace_context import (
clear_trace_context_provider,
get_trace_context_from_provider,
set_trace_context_provider,
)

from . import agents, controls, evaluation, evaluators, policies
from ._control_registry import (
Expand All @@ -86,18 +91,15 @@ async def handle_input(user_message: str) -> str:
add_event,
configure_logging,
get_event_batcher,
get_event_sink,
get_log_config,
get_logger,
init_observability,
is_observability_enabled,
log_control_evaluation,
shutdown_observability,
sync_shutdown_observability,
)
from .telemetry import (
clear_trace_context_provider,
get_trace_context_from_provider,
set_trace_context_provider,
write_events,
)
from .tracing import (
get_current_span_id,
Expand Down Expand Up @@ -1310,9 +1312,11 @@ async def main():
# Observability
"init_observability",
"add_event",
"write_events",
"shutdown_observability",
"is_observability_enabled",
"get_event_batcher",
"get_event_sink",
"configure_logging",
"get_log_config",
"log_control_evaluation",
Expand Down
5 changes: 2 additions & 3 deletions sdks/python/src/agent_control/evaluation_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
EvaluationResponse,
)

from .observability import add_event, get_logger, is_observability_enabled
from .observability import get_logger, is_observability_enabled, write_events

_logger = get_logger(__name__)

Expand Down Expand Up @@ -210,5 +210,4 @@ def enqueue_observability_events(events: list[ControlExecutionEvent]) -> None:
if not is_observability_enabled():
return

for event in events:
add_event(event)
write_events(events)
Loading
Loading