diff --git a/packages/narada-core/pyproject.toml b/packages/narada-core/pyproject.toml index 0966dab..9d3d69c 100644 --- a/packages/narada-core/pyproject.toml +++ b/packages/narada-core/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "narada-core" -version = "0.0.23" +version = "0.0.24" description = "Code shared by the `narada` and `narada-pyodide` packages." license = "Apache-2.0" readme = "README.md" diff --git a/packages/narada-core/src/narada_core/models.py b/packages/narada-core/src/narada_core/models.py index 18f183f..4685dc5 100644 --- a/packages/narada-core/src/narada_core/models.py +++ b/packages/narada-core/src/narada_core/models.py @@ -254,6 +254,7 @@ class RunCustomAgentTrace(TypedDict): workflow_name: str status: Literal["success", "error"] error_message: NotRequired[str] + children: NotRequired[ActionTrace] class IfTrace(TypedDict): @@ -312,6 +313,7 @@ class PythonSubAgentCallEvent(TypedDict): prompt: str status: Literal["success", "error", "timeout"] request_id: NotRequired[str] + text: NotRequired[str] error_message: NotRequired[str] action_trace: NotRequired[ActionTrace] diff --git a/packages/narada-core/src/narada_core/tracing/model.py b/packages/narada-core/src/narada_core/tracing/model.py index d2c6245..e4d2712 100644 --- a/packages/narada-core/src/narada_core/tracing/model.py +++ b/packages/narada-core/src/narada_core/tracing/model.py @@ -189,6 +189,7 @@ class RunCustomAgentTrace(BaseModel): workflow_name: str status: Literal["success", "error"] error_message: str | None = None + children: ActionTrace | None = None class IfTrace(BaseModel): @@ -260,6 +261,7 @@ class PythonSubAgentCallEvent(BaseModel): prompt: str status: Literal["success", "error", "timeout"] request_id: str | None = None + text: str | None = None error_message: str | None = None action_trace: ActionTrace | None = None diff --git a/packages/narada-pyodide/pyproject.toml b/packages/narada-pyodide/pyproject.toml index 84f6dce..47dd6f1 100644 --- a/packages/narada-pyodide/pyproject.toml +++ b/packages/narada-pyodide/pyproject.toml @@ -1,14 +1,14 @@ [project] name = "narada-pyodide" -version = "0.0.52" +version = "0.0.53" description = "Pyodide-compatible Python client SDK for Narada" license = "Apache-2.0" readme = "README.md" authors = [{ name = "Narada", email = "support@narada.ai" }] requires-python = ">=3.12" dependencies = [ - "narada-core==0.0.23", + "narada-core==0.0.24", # Must be a supported version in https://pyodide.org/en/stable/usage/packages-in-pyodide.html "packaging==24.2", ] diff --git a/packages/narada-pyodide/src/narada/_trace.py b/packages/narada-pyodide/src/narada/_trace.py index 659ac88..52be5bf 100644 --- a/packages/narada-pyodide/src/narada/_trace.py +++ b/packages/narada-pyodide/src/narada/_trace.py @@ -87,6 +87,7 @@ def emit_sub_agent_call( prompt: str, status: SubAgentCallStatus, request_id: str | None = None, + text: str | None = None, error_message: str | None = None, action_trace_raw: list[dict[str, Any]] | None = None, ) -> None: @@ -100,6 +101,8 @@ def emit_sub_agent_call( } if request_id is not None: event["request_id"] = request_id + if text is not None: + event["text"] = text if error_message is not None: event["error_message"] = error_message if action_trace_raw is not None: diff --git a/packages/narada-pyodide/src/narada/window.py b/packages/narada-pyodide/src/narada/window.py index 9d9b6c1..0bf4d3b 100644 --- a/packages/narada-pyodide/src/narada/window.py +++ b/packages/narada-pyodide/src/narada/window.py @@ -490,12 +490,19 @@ async def dispatch_request( and response_content is not None else None ) + trace_text: str | None = ( + response_content.get("text") + if response["status"] == "success" + and response_content is not None + else None + ) _trace.emit_sub_agent_call( ts_start=trace_start_ms, agent_type=agent_type_str, prompt=prompt, status=trace_status, request_id=request_id, + text=trace_text, error_message=trace_error, action_trace_raw=( response_content.get("actionTrace") diff --git a/packages/narada-pyodide/tests/test_cloud_browser.py b/packages/narada-pyodide/tests/test_cloud_browser.py index 2342cab..eecedc8 100644 --- a/packages/narada-pyodide/tests/test_cloud_browser.py +++ b/packages/narada-pyodide/tests/test_cloud_browser.py @@ -314,6 +314,86 @@ async def test_dispatch_request_emits_string_trace_agent_type_for_sdk_enum( assert json.loads(emitted_events[0])["agent_type"] == "operator" +@pytest.mark.asyncio +async def test_dispatch_request_emits_success_text_in_sub_agent_trace( + monkeypatch: pytest.MonkeyPatch, +) -> None: + pyfetch = AsyncMock( + side_effect=[ + _FakeResponse(json_data={"requestId": "req-123"}), + _FakeResponse( + json_data={ + "status": "success", + "response": { + "text": "TRACE_CORE_AGENT_DONE", + "actionTrace": [], + }, + } + ), + ] + ) + narada_pkg, _, window_module = _import_pyodide_narada(monkeypatch, pyfetch=pyfetch) + emitted_events: list[str] = [] + monkeypatch.setattr( + sys.modules["narada._trace"], + "_narada_emit_trace_event", + emitted_events.append, + raising=False, + ) + + window = window_module.CloudBrowserWindow( + browser_window_id="browser-window-123", + session_id="session-123", + api_key="test-api-key", + ) + response = await window.dispatch_request( + prompt="reply with marker", + agent=narada_pkg.Agent.CORE_AGENT, + ) + + from narada_core.tracing.model import PythonSubAgentCallEvent + + assert response["status"] == "success" + assert len(emitted_events) == 1 + event = json.loads(emitted_events[0]) + parsed_event = PythonSubAgentCallEvent.model_validate(event) + assert parsed_event.agent_type == "coreAgent" + assert parsed_event.text == "TRACE_CORE_AGENT_DONE" + assert parsed_event.action_trace == [] + + +def test_parse_action_trace_preserves_run_custom_agent_children( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.syspath_prepend(str(CORE_SRC)) + + from narada_core.tracing.model import parse_action_trace + + parsed_trace = parse_action_trace( + [ + { + "step_type": "runCustomAgent", + "url": "https://example.com", + "workflow_id": "workflow-parent", + "workflow_name": "Parent workflow", + "status": "success", + "children": [ + { + "step_type": "print", + "url": "https://example.com", + "message": "TRACE_GUI_CHILD_DONE", + } + ], + } + ] + ) + + assert parsed_trace[0].step_type == "runCustomAgent" + assert parsed_trace[0].children is not None + assert parsed_trace[0].children[0].step_type == "print" + assert parsed_trace[0].children[0].message == "TRACE_GUI_CHILD_DONE" + + @pytest.mark.asyncio async def test_cloud_browser_window_dispatch_request_preserves_current_file_variable_shape( monkeypatch: pytest.MonkeyPatch, diff --git a/packages/narada/pyproject.toml b/packages/narada/pyproject.toml index b47e034..f3e175f 100644 --- a/packages/narada/pyproject.toml +++ b/packages/narada/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "narada" -version = "0.1.53a2" +version = "0.1.53a3" description = "Python client SDK for Narada" license = "Apache-2.0" readme = "README.md" authors = [{ name = "Narada", email = "support@narada.ai" }] requires-python = ">=3.12" dependencies = [ - "narada-core==0.0.23", + "narada-core==0.0.24", "aiohttp>=3.12.13", "playwright>=1.53.0", "rich>=14.0.0", diff --git a/uv.lock b/uv.lock index 47dabed..d298bf4 100644 --- a/uv.lock +++ b/uv.lock @@ -312,7 +312,7 @@ wheels = [ [[package]] name = "narada" -version = "0.1.53a2" +version = "0.1.53a3" source = { editable = "packages/narada" } dependencies = [ { name = "aiohttp" }, @@ -345,7 +345,7 @@ dev = [ [[package]] name = "narada-core" -version = "0.0.23" +version = "0.0.24" source = { editable = "packages/narada-core" } dependencies = [ { name = "pydantic" }, @@ -356,7 +356,7 @@ requires-dist = [{ name = "pydantic", specifier = "==2.12.5" }] [[package]] name = "narada-pyodide" -version = "0.0.52" +version = "0.0.53" source = { editable = "packages/narada-pyodide" } dependencies = [ { name = "narada-core" },