mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-01 07:13:00 +00:00
fix: use anon id for ephemeral traces
This commit is contained in:
@@ -49,8 +49,13 @@ class PlusAPI:
|
|||||||
with httpx.Client(trust_env=False, verify=verify) as client:
|
with httpx.Client(trust_env=False, verify=verify) as client:
|
||||||
return client.request(method, url, headers=self.headers, **kwargs)
|
return client.request(method, url, headers=self.headers, **kwargs)
|
||||||
|
|
||||||
def login_to_tool_repository(self) -> httpx.Response:
|
def login_to_tool_repository(
|
||||||
return self._make_request("POST", f"{self.TOOLS_RESOURCE}/login")
|
self, user_identifier: str | None = None
|
||||||
|
) -> httpx.Response:
|
||||||
|
payload = {}
|
||||||
|
if user_identifier:
|
||||||
|
payload["user_identifier"] = user_identifier
|
||||||
|
return self._make_request("POST", f"{self.TOOLS_RESOURCE}/login", json=payload)
|
||||||
|
|
||||||
def get_tool(self, handle: str) -> httpx.Response:
|
def get_tool(self, handle: str) -> httpx.Response:
|
||||||
return self._make_request("GET", f"{self.TOOLS_RESOURCE}/{handle}")
|
return self._make_request("GET", f"{self.TOOLS_RESOURCE}/{handle}")
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from crewai.cli.utils import (
|
|||||||
tree_copy,
|
tree_copy,
|
||||||
tree_find_and_replace,
|
tree_find_and_replace,
|
||||||
)
|
)
|
||||||
|
from crewai.events.listeners.tracing.utils import get_user_id
|
||||||
|
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
@@ -169,7 +170,9 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
console.print(f"Successfully installed {handle}", style="bold green")
|
console.print(f"Successfully installed {handle}", style="bold green")
|
||||||
|
|
||||||
def login(self) -> None:
|
def login(self) -> None:
|
||||||
login_response = self.plus_api_client.login_to_tool_repository()
|
login_response = self.plus_api_client.login_to_tool_repository(
|
||||||
|
user_identifier=get_user_id()
|
||||||
|
)
|
||||||
|
|
||||||
if login_response.status_code != 200:
|
if login_response.status_code != 200:
|
||||||
console.print(
|
console.print(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from crewai.cli.plus_api import PlusAPI
|
|||||||
from crewai.cli.version import get_crewai_version
|
from crewai.cli.version import get_crewai_version
|
||||||
from crewai.events.listeners.tracing.types import TraceEvent
|
from crewai.events.listeners.tracing.types import TraceEvent
|
||||||
from crewai.events.listeners.tracing.utils import (
|
from crewai.events.listeners.tracing.utils import (
|
||||||
|
get_user_id,
|
||||||
is_tracing_enabled_in_context,
|
is_tracing_enabled_in_context,
|
||||||
should_auto_collect_first_time_traces,
|
should_auto_collect_first_time_traces,
|
||||||
)
|
)
|
||||||
@@ -120,7 +121,6 @@ class TraceBatchManager:
|
|||||||
payload = {
|
payload = {
|
||||||
"trace_id": self.current_batch.batch_id,
|
"trace_id": self.current_batch.batch_id,
|
||||||
"execution_type": execution_metadata.get("execution_type", "crew"),
|
"execution_type": execution_metadata.get("execution_type", "crew"),
|
||||||
"user_identifier": execution_metadata.get("user_context", None),
|
|
||||||
"execution_context": {
|
"execution_context": {
|
||||||
"crew_fingerprint": execution_metadata.get("crew_fingerprint"),
|
"crew_fingerprint": execution_metadata.get("crew_fingerprint"),
|
||||||
"crew_name": execution_metadata.get("crew_name", None),
|
"crew_name": execution_metadata.get("crew_name", None),
|
||||||
@@ -140,6 +140,7 @@ class TraceBatchManager:
|
|||||||
}
|
}
|
||||||
if use_ephemeral:
|
if use_ephemeral:
|
||||||
payload["ephemeral_trace_id"] = self.current_batch.batch_id
|
payload["ephemeral_trace_id"] = self.current_batch.batch_id
|
||||||
|
payload["user_identifier"] = get_user_id()
|
||||||
|
|
||||||
response = (
|
response = (
|
||||||
self.plus_api.initialize_ephemeral_trace_batch(payload)
|
self.plus_api.initialize_ephemeral_trace_batch(payload)
|
||||||
|
|||||||
@@ -28,7 +28,19 @@ class TestPlusAPI(unittest.TestCase):
|
|||||||
response = self.api.login_to_tool_repository()
|
response = self.api.login_to_tool_repository()
|
||||||
|
|
||||||
mock_make_request.assert_called_once_with(
|
mock_make_request.assert_called_once_with(
|
||||||
"POST", "/crewai_plus/api/v1/tools/login"
|
"POST", "/crewai_plus/api/v1/tools/login", json={}
|
||||||
|
)
|
||||||
|
self.assertEqual(response, mock_response)
|
||||||
|
|
||||||
|
@patch("crewai.cli.plus_api.PlusAPI._make_request")
|
||||||
|
def test_login_to_tool_repository_with_user_identifier(self, mock_make_request):
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_make_request.return_value = mock_response
|
||||||
|
|
||||||
|
response = self.api.login_to_tool_repository(user_identifier="test-hash-123")
|
||||||
|
|
||||||
|
mock_make_request.assert_called_once_with(
|
||||||
|
"POST", "/crewai_plus/api/v1/tools/login", json={"user_identifier": "test-hash-123"}
|
||||||
)
|
)
|
||||||
self.assertEqual(response, mock_response)
|
self.assertEqual(response, mock_response)
|
||||||
|
|
||||||
@@ -67,7 +79,7 @@ class TestPlusAPI(unittest.TestCase):
|
|||||||
response = self.api.login_to_tool_repository()
|
response = self.api.login_to_tool_repository()
|
||||||
|
|
||||||
self.assert_request_with_org_id(
|
self.assert_request_with_org_id(
|
||||||
mock_client_instance, "POST", "/crewai_plus/api/v1/tools/login"
|
mock_client_instance, "POST", "/crewai_plus/api/v1/tools/login", json={}
|
||||||
)
|
)
|
||||||
self.assertEqual(response, mock_response)
|
self.assertEqual(response, mock_response)
|
||||||
|
|
||||||
|
|||||||
@@ -840,3 +840,87 @@ class TestTraceListenerSetup:
|
|||||||
mock_mark_failed.assert_called_once_with(
|
mock_mark_failed.assert_called_once_with(
|
||||||
"test_batch_id_12345", "Internal Server Error"
|
"test_batch_id_12345", "Internal Server Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_ephemeral_batch_includes_anon_id(self):
|
||||||
|
"""Test that ephemeral batch initialization sends anon_id from get_user_id()"""
|
||||||
|
fake_user_id = "abc123def456"
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"crewai.events.listeners.tracing.trace_batch_manager.is_tracing_enabled_in_context",
|
||||||
|
return_value=True,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"crewai.events.listeners.tracing.trace_batch_manager.get_user_id",
|
||||||
|
return_value=fake_user_id,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"crewai.events.listeners.tracing.trace_batch_manager.should_auto_collect_first_time_traces",
|
||||||
|
return_value=False,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
batch_manager = TraceBatchManager()
|
||||||
|
|
||||||
|
mock_response = MagicMock(
|
||||||
|
status_code=201,
|
||||||
|
json=MagicMock(return_value={
|
||||||
|
"ephemeral_trace_id": "test-trace-id",
|
||||||
|
"access_code": "TRACE-abc123",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(
|
||||||
|
batch_manager.plus_api,
|
||||||
|
"initialize_ephemeral_trace_batch",
|
||||||
|
return_value=mock_response,
|
||||||
|
) as mock_init:
|
||||||
|
batch_manager.initialize_batch(
|
||||||
|
user_context={"privacy_level": "standard"},
|
||||||
|
execution_metadata={
|
||||||
|
"execution_type": "crew",
|
||||||
|
"crew_name": "test_crew",
|
||||||
|
},
|
||||||
|
use_ephemeral=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_init.assert_called_once()
|
||||||
|
payload = mock_init.call_args[0][0]
|
||||||
|
assert payload["user_identifier"] == fake_user_id
|
||||||
|
assert "ephemeral_trace_id" in payload
|
||||||
|
|
||||||
|
def test_non_ephemeral_batch_does_not_include_anon_id(self):
|
||||||
|
"""Test that non-ephemeral batch initialization does not send anon_id"""
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"crewai.events.listeners.tracing.trace_batch_manager.is_tracing_enabled_in_context",
|
||||||
|
return_value=True,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"crewai.events.listeners.tracing.trace_batch_manager.should_auto_collect_first_time_traces",
|
||||||
|
return_value=False,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
batch_manager = TraceBatchManager()
|
||||||
|
|
||||||
|
mock_response = MagicMock(
|
||||||
|
status_code=201,
|
||||||
|
json=MagicMock(return_value={"trace_id": "test-trace-id"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(
|
||||||
|
batch_manager.plus_api,
|
||||||
|
"initialize_trace_batch",
|
||||||
|
return_value=mock_response,
|
||||||
|
) as mock_init:
|
||||||
|
batch_manager.initialize_batch(
|
||||||
|
user_context={"privacy_level": "standard"},
|
||||||
|
execution_metadata={
|
||||||
|
"execution_type": "crew",
|
||||||
|
"crew_name": "test_crew",
|
||||||
|
},
|
||||||
|
use_ephemeral=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_init.assert_called_once()
|
||||||
|
payload = mock_init.call_args[0][0]
|
||||||
|
assert "user_identifier" not in payload
|
||||||
|
|||||||
Reference in New Issue
Block a user