55import os
66from typing import Any , Optional
77
8+ from ._http import normalize_base_url
89from .exceptions import (
910 DelegaAPIError ,
1011 DelegaAuthError ,
@@ -34,7 +35,7 @@ class _AsyncHTTPClient:
3435
3536 def __init__ (self , base_url : str , api_key : str , timeout : int = 30 ) -> None :
3637 httpx = _require_httpx ()
37- self ._base_url = base_url . rstrip ( "/" )
38+ self ._base_url = normalize_base_url ( base_url )
3839 self ._api_key = api_key
3940 self ._client = httpx .AsyncClient (
4041 base_url = self ._base_url ,
@@ -136,7 +137,7 @@ async def list(
136137 "due_before" : due_before ,
137138 "completed" : completed ,
138139 }
139- data = await self ._http .get ("/v1/ tasks" , params = params )
140+ data = await self ._http .get ("/tasks" , params = params )
140141 return [Task .from_dict (t ) for t in data ]
141142
142143 async def create (
@@ -159,32 +160,32 @@ async def create(
159160 body ["due_date" ] = due_date
160161 if project_id is not None :
161162 body ["project_id" ] = project_id
162- data = await self ._http .post ("/v1/ tasks" , body = body )
163+ data = await self ._http .post ("/tasks" , body = body )
163164 return Task .from_dict (data )
164165
165166 async def get (self , task_id : str ) -> Task :
166167 """Get a task by ID."""
167- data = await self ._http .get (f"/v1/ tasks/{ task_id } " )
168+ data = await self ._http .get (f"/tasks/{ task_id } " )
168169 return Task .from_dict (data )
169170
170171 async def update (self , task_id : str , ** fields : Any ) -> Task :
171172 """Update a task."""
172- data = await self ._http .patch (f"/v1/ tasks/{ task_id } " , body = fields )
173+ data = await self ._http .patch (f"/tasks/{ task_id } " , body = fields )
173174 return Task .from_dict (data )
174175
175176 async def delete (self , task_id : str ) -> bool :
176177 """Delete a task."""
177- await self ._http .delete (f"/v1/ tasks/{ task_id } " )
178+ await self ._http .delete (f"/tasks/{ task_id } " )
178179 return True
179180
180181 async def complete (self , task_id : str ) -> Task :
181182 """Mark a task as completed."""
182- data = await self ._http .post (f"/v1/ tasks/{ task_id } /complete" )
183+ data = await self ._http .post (f"/tasks/{ task_id } /complete" )
183184 return Task .from_dict (data )
184185
185186 async def uncomplete (self , task_id : str ) -> Task :
186187 """Mark a task as not completed."""
187- data = await self ._http .post (f"/v1/ tasks/{ task_id } /uncomplete" )
188+ data = await self ._http .post (f"/tasks/{ task_id } /uncomplete" )
188189 return Task .from_dict (data )
189190
190191 async def search (self , query : str ) -> list [Task ]:
@@ -205,17 +206,17 @@ async def delegate(
205206 body ["description" ] = description
206207 if priority is not None :
207208 body ["priority" ] = priority
208- data = await self ._http .post (f"/v1/ tasks/{ parent_task_id } /delegate" , body = body )
209+ data = await self ._http .post (f"/tasks/{ parent_task_id } /delegate" , body = body )
209210 return Task .from_dict (data )
210211
211212 async def add_comment (self , task_id : str , content : str ) -> Comment :
212213 """Add a comment to a task."""
213- data = await self ._http .post (f"/v1/ tasks/{ task_id } /comments" , body = {"content" : content })
214+ data = await self ._http .post (f"/tasks/{ task_id } /comments" , body = {"content" : content })
214215 return Comment .from_dict (data )
215216
216217 async def list_comments (self , task_id : str ) -> list [Comment ]:
217218 """List all comments on a task."""
218- data = await self ._http .get (f"/v1/ tasks/{ task_id } /comments" )
219+ data = await self ._http .get (f"/tasks/{ task_id } /comments" )
219220 return [Comment .from_dict (c ) for c in data ]
220221
221222
@@ -227,7 +228,7 @@ def __init__(self, http: _AsyncHTTPClient) -> None:
227228
228229 async def list (self ) -> list [Agent ]:
229230 """List all agents."""
230- data = await self ._http .get ("/v1/ agents" )
231+ data = await self ._http .get ("/agents" )
231232 return [Agent .from_dict (a ) for a in data ]
232233
233234 async def create (
@@ -243,22 +244,22 @@ async def create(
243244 body ["display_name" ] = display_name
244245 if description is not None :
245246 body ["description" ] = description
246- data = await self ._http .post ("/v1/ agents" , body = body )
247+ data = await self ._http .post ("/agents" , body = body )
247248 return Agent .from_dict (data )
248249
249250 async def update (self , agent_id : str , ** fields : Any ) -> Agent :
250251 """Update an agent."""
251- data = await self ._http .patch (f"/v1/ agents/{ agent_id } " , body = fields )
252+ data = await self ._http .patch (f"/agents/{ agent_id } " , body = fields )
252253 return Agent .from_dict (data )
253254
254255 async def delete (self , agent_id : str ) -> bool :
255256 """Delete an agent."""
256- await self ._http .delete (f"/v1/ agents/{ agent_id } " )
257+ await self ._http .delete (f"/agents/{ agent_id } " )
257258 return True
258259
259260 async def rotate_key (self , agent_id : str ) -> dict [str , Any ]:
260261 """Rotate an agent's API key."""
261- data = await self ._http .post (f"/v1/ agents/{ agent_id } /rotate-key" )
262+ data = await self ._http .post (f"/agents/{ agent_id } /rotate-key" )
262263 return data # type: ignore[no-any-return]
263264
264265
@@ -270,7 +271,7 @@ def __init__(self, http: _AsyncHTTPClient) -> None:
270271
271272 async def list (self ) -> list [Project ]:
272273 """List all projects."""
273- data = await self ._http .get ("/v1/ projects" )
274+ data = await self ._http .get ("/projects" )
274275 return [Project .from_dict (p ) for p in data ]
275276
276277 async def create (
@@ -286,7 +287,7 @@ async def create(
286287 body ["emoji" ] = emoji
287288 if color is not None :
288289 body ["color" ] = color
289- data = await self ._http .post ("/v1/ projects" , body = body )
290+ data = await self ._http .post ("/projects" , body = body )
290291 return Project .from_dict (data )
291292
292293
@@ -298,7 +299,7 @@ def __init__(self, http: _AsyncHTTPClient) -> None:
298299
299300 async def list (self ) -> list [Any ]:
300301 """List all webhooks."""
301- return await self ._http .get ("/v1/ webhooks" ) # type: ignore[no-any-return]
302+ return await self ._http .get ("/webhooks" ) # type: ignore[no-any-return]
302303
303304 async def create (
304305 self ,
@@ -313,7 +314,7 @@ async def create(
313314 body ["events" ] = events
314315 if secret is not None :
315316 body ["secret" ] = secret
316- return await self ._http .post ("/v1/ webhooks" , body = body ) # type: ignore[no-any-return]
317+ return await self ._http .post ("/webhooks" , body = body ) # type: ignore[no-any-return]
317318
318319
319320class AsyncDelega :
@@ -332,7 +333,9 @@ class AsyncDelega:
332333 api_key: API key for authentication. If not provided, reads from
333334 the ``DELEGA_API_KEY`` environment variable.
334335 base_url: Base URL of the Delega API. Defaults to
335- ``https://api.delega.dev``.
336+ ``https://api.delega.dev`` (normalized to ``/v1``). For
337+ self-hosted deployments, use ``http://localhost:18890`` or an
338+ explicit ``.../api`` base URL.
336339 timeout: Request timeout in seconds. Defaults to 30.
337340
338341 Raises:
@@ -360,11 +363,11 @@ def __init__(
360363
361364 async def me (self ) -> dict [str , Any ]:
362365 """Get information about the authenticated agent."""
363- return await self ._http .get ("/v1/ agent/me" ) # type: ignore[no-any-return]
366+ return await self ._http .get ("/agent/me" ) # type: ignore[no-any-return]
364367
365368 async def usage (self ) -> dict [str , Any ]:
366369 """Get API usage information."""
367- return await self ._http .get ("/v1/ usage" ) # type: ignore[no-any-return]
370+ return await self ._http .get ("/usage" ) # type: ignore[no-any-return]
368371
369372 async def aclose (self ) -> None :
370373 """Close the underlying HTTP client."""
0 commit comments