From 59dee06048adc459f470c405644cc1628f7ee385 Mon Sep 17 00:00:00 2001 From: Chen-ROE Date: Tue, 18 Aug 2026 00:13:56 -0700 Subject: [PATCH 1/3] Implement resend_webhook on the agent jobs facade The generated endpoint module and the SDK examples both reference client.agents.jobs.resend_webhook, but the hand-written facade had no such method, so following the documented example raised AttributeError before any request was sent. Co-Authored-By: Claude Fable 5 --- src/roe/api/agents.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/roe/api/agents.py b/src/roe/api/agents.py index aa377c4..754c4f2 100644 --- a/src/roe/api/agents.py +++ b/src/roe/api/agents.py @@ -25,6 +25,7 @@ agents_jobs_artifacts_result_retrieve, agents_jobs_cancel_all_create, agents_jobs_cancel_create, + agents_jobs_webhook_resend_create, agents_jobs_delete_data_create, agents_jobs_list, agents_jobs_references_retrieve, @@ -57,6 +58,7 @@ from roe._generated.models.agent_job_artifact_result import AgentJobArtifactResult from roe._generated.models.agent_job_cancel_all_response import ( AgentJobCancelAllResponse, + AgentJobWebhookResendResponse, ) from roe._generated.models.agent_job_delete_data_response import ( AgentJobDeleteDataResponse, @@ -424,6 +426,21 @@ def cancel(self, job_id: str) -> None: organization_id=self._org_id, ) + def resend_webhook(self, job_id: str) -> AgentJobWebhookResendResponse: + """Re-send a finished job's completion webhook. + + The job is not re-run and its status is unchanged. ``queued`` reports + how many deliveries were queued; zero means the agent has no active + webhook. + """ + response = request_raw( + self._raw, + agents_jobs_webhook_resend_create, + UUID(str(job_id)), + organization_id=self._org_id, + ) + return AgentJobWebhookResendResponse.from_dict(response.json()) + def cancel_all(self, agent_id: str) -> AgentJobCancelAllResponse: response = request_raw( self._raw, From de5a55cd547c8329a4e4a13c7efa2c2b0df2b27f Mon Sep 17 00:00:00 2001 From: Chen-ROE Date: Tue, 18 Aug 2026 00:24:36 -0700 Subject: [PATCH 2/3] Import the resend response from its own generated module The model lives in agent_job_webhook_resend_response, not alongside AgentJobCancelAllResponse; importing it from the wrong module broke every test that imports roe.api.agents. Adds the transport test that would have caught it. Co-Authored-By: Claude Fable 5 --- src/roe/api/agents.py | 4 +++- tests/unit/test_agents_wrapper_transport.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/roe/api/agents.py b/src/roe/api/agents.py index 754c4f2..403921e 100644 --- a/src/roe/api/agents.py +++ b/src/roe/api/agents.py @@ -58,11 +58,13 @@ from roe._generated.models.agent_job_artifact_result import AgentJobArtifactResult from roe._generated.models.agent_job_cancel_all_response import ( AgentJobCancelAllResponse, - AgentJobWebhookResendResponse, ) from roe._generated.models.agent_job_delete_data_response import ( AgentJobDeleteDataResponse, ) +from roe._generated.models.agent_job_webhook_resend_response import ( + AgentJobWebhookResendResponse, +) from roe._generated.models.agent_job_result_many_request import ( AgentJobResultManyRequest, ) diff --git a/tests/unit/test_agents_wrapper_transport.py b/tests/unit/test_agents_wrapper_transport.py index 7bb1088..438e9cd 100644 --- a/tests/unit/test_agents_wrapper_transport.py +++ b/tests/unit/test_agents_wrapper_transport.py @@ -275,6 +275,18 @@ def test_cancel_all_returns_structured_response_body(): assert result.note == "cancelling" +def test_resend_webhook_posts_to_the_job_and_returns_queued_count(): + api, request = _api(httpx.Response(200, json={"status": "queued", "queued": 2})) + + result = api.jobs.resend_webhook(JOB_ID) + + kwargs = request.call_args.kwargs + assert kwargs["method"] == "post" + assert kwargs["url"].endswith(f"/v1/agents/jobs/{JOB_ID}/webhook/resend/") + assert kwargs["params"] == {"organization_id": ORG_ID} + assert result.queued == 2 + + def test_retrieve_status_parses_single_status_shape_without_id(): # GET /v1/agents/jobs/{job_id}/status/ returns AgentJobSingleStatus # ({status, timestamp, error_message?}) with no "id" field — parsing it From 2b1a0b786b2555b1df4b900a70b3c4b6bd02e57b Mon Sep 17 00:00:00 2001 From: Chen-ROE Date: Tue, 18 Aug 2026 10:00:55 -0700 Subject: [PATCH 3/3] Let resend_webhook target a single webhook The endpoint takes an optional webhook_id to reach one subscription instead of every one. Co-Authored-By: Claude Fable 5 --- src/roe/api/agents.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/roe/api/agents.py b/src/roe/api/agents.py index 403921e..3c1cfcd 100644 --- a/src/roe/api/agents.py +++ b/src/roe/api/agents.py @@ -59,6 +59,9 @@ from roe._generated.models.agent_job_cancel_all_response import ( AgentJobCancelAllResponse, ) +from roe._generated.models.resend_agent_job_webhook_request import ( + ResendAgentJobWebhookRequest, +) from roe._generated.models.agent_job_delete_data_response import ( AgentJobDeleteDataResponse, ) @@ -428,17 +431,24 @@ def cancel(self, job_id: str) -> None: organization_id=self._org_id, ) - def resend_webhook(self, job_id: str) -> AgentJobWebhookResendResponse: + def resend_webhook( + self, job_id: str, webhook_id: str | None = None + ) -> AgentJobWebhookResendResponse: """Re-send a finished job's completion webhook. - The job is not re-run and its status is unchanged. ``queued`` reports - how many deliveries were queued; zero means the agent has no active - webhook. + Sends to every webhook attached to the job's agent, or only to + ``webhook_id`` when given. The job is not re-run and its status is + unchanged. ``queued`` reports how many deliveries were queued; zero + means nothing was eligible. """ + body = ResendAgentJobWebhookRequest( + webhook_id=UUID(str(webhook_id)) if webhook_id is not None else UNSET, + ) response = request_raw( self._raw, agents_jobs_webhook_resend_create, UUID(str(job_id)), + body=body, organization_id=self._org_id, ) return AgentJobWebhookResendResponse.from_dict(response.json())