dobby-ai-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,82 @@
1
+ # ============================================
2
+ # Dobby Platform - Git Ignore
3
+ # ============================================
4
+
5
+ # Environment Variables (CRITICAL - Never commit!)
6
+ .env
7
+ .env.local
8
+ .env.dev
9
+ .env.prod
10
+ .env.*.local
11
+ .env.*.backup
12
+ *.backup
13
+
14
+ # Credentials & Secrets
15
+ /credentials/
16
+ *.pem
17
+ *.key
18
+ service-account.json
19
+
20
+ # Python
21
+ __pycache__/
22
+ *.py[cod]
23
+ *$py.class
24
+ *.so
25
+ .Python
26
+ *.egg-info/
27
+ .eggs/
28
+
29
+ # Node
30
+ node_modules/
31
+ npm-debug.log*
32
+ yarn-debug.log*
33
+ yarn-error.log*
34
+ .pnpm-debug.log*
35
+
36
+ # Next.js
37
+ .next/
38
+ out/
39
+ build/
40
+ dist/
41
+
42
+ # Debug
43
+ *.log
44
+
45
+ # IDE
46
+ .vscode/
47
+ .idea/
48
+ *.swp
49
+ *.swo
50
+ *~
51
+ .DS_Store
52
+
53
+ # Testing
54
+ coverage/
55
+ .nyc_output/
56
+ test-results-*.json
57
+ testing_sessions/
58
+
59
+ # Build output artifacts
60
+ tsc-*.txt
61
+ test_write.txt
62
+
63
+ # Docker
64
+ docker-compose.override.yml
65
+
66
+ # OS
67
+ Thumbs.db
68
+
69
+ # Backups
70
+ backups/
71
+
72
+ # Claude settings (local)
73
+ .claude/settings.local.json
74
+
75
+ # ============================================
76
+ # Render Monitor
77
+ # ============================================
78
+ render-monitor/.env
79
+ render-monitor/logs/
80
+ render-monitor/*.log
81
+ render-monitor/*.jsonl
82
+ .venv/
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: dobby-ai-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Dobby AI Platform — Home for your AI agents
5
+ Project-URL: Homepage, https://dobby-ai.com
6
+ Project-URL: Documentation, https://dobby-ai.com/docs/sdk
7
+ Project-URL: Repository, https://github.com/gil-dobby/dobby-sdk-python
8
+ Author-email: Dobby AI <dev@dobby-ai.com>
9
+ License-Expression: MIT
10
+ Keywords: a2a,agents,ai,dobby,gateway,llm,mcp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: httpx>=0.25.0
23
+ Requires-Dist: openai>=1.0.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
28
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Dobby SDK for Python
34
+
35
+ Official Python SDK for the [Dobby AI Platform](https://dobby-ai.com) — Home for your AI agents.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install dobby-ai-sdk
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ from dobby_sdk import DobbyClient
47
+
48
+ client = DobbyClient(api_key="gk_user_...")
49
+
50
+ # LLM calls (OpenAI-compatible)
51
+ response = client.chat.completions.create(
52
+ model="claude-sonnet-4-20250514",
53
+ messages=[{"role": "user", "content": "Hello from Dobby!"}],
54
+ )
55
+ print(response.choices[0].message.content)
56
+
57
+ # Streaming
58
+ stream = client.chat.completions.create(
59
+ model="gpt-4o-mini",
60
+ messages=[{"role": "user", "content": "Explain AI agents"}],
61
+ stream=True,
62
+ )
63
+ for chunk in stream:
64
+ print(chunk.choices[0].delta.content or "", end="")
65
+ ```
66
+
67
+ ## Task Management
68
+
69
+ ```python
70
+ # Create a task
71
+ task = client.tasks.create(
72
+ title="Review PR #42",
73
+ priority="high",
74
+ agent_name="dobby-code-reviewer-agent",
75
+ )
76
+
77
+ # List pending tasks
78
+ tasks = client.tasks.list(status="pending")
79
+
80
+ # Approve a task (HITL)
81
+ client.approvals.approve(task["id"], comment="Looks good!")
82
+ ```
83
+
84
+ ## Agent Fleet
85
+
86
+ ```python
87
+ # List all agents
88
+ agents = client.agents.list()
89
+
90
+ # Register an external agent
91
+ agent = client.agents.register(
92
+ display_name="Research Agent",
93
+ framework="crewai",
94
+ protocol="a2a",
95
+ endpoint_url="https://my-agent.example.com",
96
+ )
97
+
98
+ # Pause/resume
99
+ client.agents.pause("agent_abc123")
100
+ ```
101
+
102
+ ## Cost Tracking
103
+
104
+ ```python
105
+ # Organization cost summary
106
+ costs = client.costs.summary(period="30d")
107
+
108
+ # Per-agent breakdown
109
+ agent_costs = client.costs.by_agent(period="7d")
110
+ ```
111
+
112
+ ## Async Support
113
+
114
+ ```python
115
+ from dobby_sdk import AsyncDobbyClient
116
+
117
+ async with AsyncDobbyClient(api_key="gk_user_...") as client:
118
+ response = await client.chat.completions.create(
119
+ model="claude-sonnet-4-20250514",
120
+ messages=[{"role": "user", "content": "Hello async!"}],
121
+ )
122
+ ```
123
+
124
+ ## Configuration
125
+
126
+ ```python
127
+ client = DobbyClient(
128
+ api_key="gk_user_...", # or DOBBY_API_KEY env var
129
+ base_url="https://dobby-ai.com", # or DOBBY_BASE_URL
130
+ org_id="org_...", # or DOBBY_ORG_ID
131
+ tenant_id="tenant_...", # or DOBBY_TENANT_ID
132
+ timeout=120.0,
133
+ max_retries=2,
134
+ )
135
+ ```
136
+
137
+ ## Error Handling
138
+
139
+ ```python
140
+ from dobby_sdk import DobbyAuthError, DobbyRateLimitError, DobbyBudgetExceededError
141
+
142
+ try:
143
+ response = client.chat.completions.create(...)
144
+ except DobbyAuthError:
145
+ print("Invalid or expired API key")
146
+ except DobbyRateLimitError as e:
147
+ print(f"Rate limited. Retry after: {e.retry_after}s")
148
+ except DobbyBudgetExceededError:
149
+ print("Organization budget limit reached")
150
+ ```
@@ -0,0 +1,118 @@
1
+ # Dobby SDK for Python
2
+
3
+ Official Python SDK for the [Dobby AI Platform](https://dobby-ai.com) — Home for your AI agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install dobby-ai-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from dobby_sdk import DobbyClient
15
+
16
+ client = DobbyClient(api_key="gk_user_...")
17
+
18
+ # LLM calls (OpenAI-compatible)
19
+ response = client.chat.completions.create(
20
+ model="claude-sonnet-4-20250514",
21
+ messages=[{"role": "user", "content": "Hello from Dobby!"}],
22
+ )
23
+ print(response.choices[0].message.content)
24
+
25
+ # Streaming
26
+ stream = client.chat.completions.create(
27
+ model="gpt-4o-mini",
28
+ messages=[{"role": "user", "content": "Explain AI agents"}],
29
+ stream=True,
30
+ )
31
+ for chunk in stream:
32
+ print(chunk.choices[0].delta.content or "", end="")
33
+ ```
34
+
35
+ ## Task Management
36
+
37
+ ```python
38
+ # Create a task
39
+ task = client.tasks.create(
40
+ title="Review PR #42",
41
+ priority="high",
42
+ agent_name="dobby-code-reviewer-agent",
43
+ )
44
+
45
+ # List pending tasks
46
+ tasks = client.tasks.list(status="pending")
47
+
48
+ # Approve a task (HITL)
49
+ client.approvals.approve(task["id"], comment="Looks good!")
50
+ ```
51
+
52
+ ## Agent Fleet
53
+
54
+ ```python
55
+ # List all agents
56
+ agents = client.agents.list()
57
+
58
+ # Register an external agent
59
+ agent = client.agents.register(
60
+ display_name="Research Agent",
61
+ framework="crewai",
62
+ protocol="a2a",
63
+ endpoint_url="https://my-agent.example.com",
64
+ )
65
+
66
+ # Pause/resume
67
+ client.agents.pause("agent_abc123")
68
+ ```
69
+
70
+ ## Cost Tracking
71
+
72
+ ```python
73
+ # Organization cost summary
74
+ costs = client.costs.summary(period="30d")
75
+
76
+ # Per-agent breakdown
77
+ agent_costs = client.costs.by_agent(period="7d")
78
+ ```
79
+
80
+ ## Async Support
81
+
82
+ ```python
83
+ from dobby_sdk import AsyncDobbyClient
84
+
85
+ async with AsyncDobbyClient(api_key="gk_user_...") as client:
86
+ response = await client.chat.completions.create(
87
+ model="claude-sonnet-4-20250514",
88
+ messages=[{"role": "user", "content": "Hello async!"}],
89
+ )
90
+ ```
91
+
92
+ ## Configuration
93
+
94
+ ```python
95
+ client = DobbyClient(
96
+ api_key="gk_user_...", # or DOBBY_API_KEY env var
97
+ base_url="https://dobby-ai.com", # or DOBBY_BASE_URL
98
+ org_id="org_...", # or DOBBY_ORG_ID
99
+ tenant_id="tenant_...", # or DOBBY_TENANT_ID
100
+ timeout=120.0,
101
+ max_retries=2,
102
+ )
103
+ ```
104
+
105
+ ## Error Handling
106
+
107
+ ```python
108
+ from dobby_sdk import DobbyAuthError, DobbyRateLimitError, DobbyBudgetExceededError
109
+
110
+ try:
111
+ response = client.chat.completions.create(...)
112
+ except DobbyAuthError:
113
+ print("Invalid or expired API key")
114
+ except DobbyRateLimitError as e:
115
+ print(f"Rate limited. Retry after: {e.retry_after}s")
116
+ except DobbyBudgetExceededError:
117
+ print("Organization budget limit reached")
118
+ ```
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "dobby-ai-sdk"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for the Dobby AI Platform — Home for your AI agents"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Dobby AI", email = "dev@dobby-ai.com" },
14
+ ]
15
+ keywords = ["ai", "agents", "llm", "gateway", "dobby", "a2a", "mcp"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ ]
28
+ dependencies = [
29
+ "openai>=1.0.0",
30
+ "httpx>=0.25.0",
31
+ "pydantic>=2.0.0",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=7.0.0",
37
+ "pytest-asyncio>=0.23.0",
38
+ "pytest-httpx>=0.30.0",
39
+ "ruff>=0.3.0",
40
+ "mypy>=1.8.0",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://dobby-ai.com"
45
+ Documentation = "https://dobby-ai.com/docs/sdk"
46
+ Repository = "https://github.com/gil-dobby/dobby-sdk-python"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/dobby_sdk"]
50
+
51
+ [tool.ruff]
52
+ line-length = 100
53
+ target-version = "py39"
54
+
55
+ [tool.ruff.lint]
56
+ select = ["E", "F", "I", "N", "W", "UP"]
57
+
58
+ [tool.mypy]
59
+ strict = true
60
+ python_version = "3.9"
61
+
62
+ [tool.pytest.ini_options]
63
+ asyncio_mode = "auto"
64
+ testpaths = ["tests"]
@@ -0,0 +1,50 @@
1
+ """
2
+ Dobby AI SDK — Official Python client for the Dobby AI Platform.
3
+
4
+ Usage:
5
+ from dobby_sdk import DobbyClient
6
+
7
+ client = DobbyClient(api_key="gk_user_...")
8
+
9
+ # LLM calls (OpenAI-compatible)
10
+ response = client.chat.completions.create(
11
+ model="claude-sonnet-4-20250514",
12
+ messages=[{"role": "user", "content": "Hello"}]
13
+ )
14
+
15
+ # Task management
16
+ task = client.tasks.create(title="Review PR #42", priority="high")
17
+
18
+ # Agent operations
19
+ agents = client.agents.list()
20
+
21
+ # Approvals
22
+ pending = client.approvals.list(status="pending")
23
+
24
+ # Cost tracking
25
+ costs = client.costs.summary(period="30d")
26
+ """
27
+
28
+ from dobby_sdk._config import DobbyConfig
29
+ from dobby_sdk._exceptions import (
30
+ DobbyAuthError,
31
+ DobbyBudgetExceededError,
32
+ DobbyError,
33
+ DobbyNotFoundError,
34
+ DobbyRateLimitError,
35
+ DobbyServerError,
36
+ )
37
+ from dobby_sdk.client import AsyncDobbyClient, DobbyClient
38
+
39
+ __version__ = "0.1.0"
40
+ __all__ = [
41
+ "DobbyClient",
42
+ "AsyncDobbyClient",
43
+ "DobbyConfig",
44
+ "DobbyError",
45
+ "DobbyAuthError",
46
+ "DobbyRateLimitError",
47
+ "DobbyBudgetExceededError",
48
+ "DobbyNotFoundError",
49
+ "DobbyServerError",
50
+ ]
@@ -0,0 +1,83 @@
1
+ """Base HTTP client for Dobby API calls."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from typing import Any
7
+
8
+ import httpx
9
+
10
+ from dobby_sdk._config import DobbyConfig
11
+ from dobby_sdk._exceptions import raise_for_status
12
+
13
+
14
+ class BaseResource:
15
+ """Base class for all API resource namespaces."""
16
+
17
+ def __init__(self, config: DobbyConfig, http_client: httpx.Client) -> None:
18
+ self._config = config
19
+ self._http = http_client
20
+
21
+ def _request(
22
+ self,
23
+ method: str,
24
+ path: str,
25
+ *,
26
+ json: dict[str, Any] | None = None,
27
+ params: dict[str, Any] | None = None,
28
+ ) -> dict[str, Any]:
29
+ """Make an authenticated API request."""
30
+ url = f"{self._config.api_url}{path}"
31
+ headers = {
32
+ **self._config.auth_headers,
33
+ "X-Request-Id": str(uuid.uuid4()),
34
+ }
35
+
36
+ response = self._http.request(
37
+ method=method,
38
+ url=url,
39
+ json=json,
40
+ params=params,
41
+ headers=headers,
42
+ timeout=self._config.timeout,
43
+ )
44
+
45
+ body = response.json() if response.content else {}
46
+ raise_for_status(response.status_code, body)
47
+ return body
48
+
49
+
50
+ class AsyncBaseResource:
51
+ """Async version of BaseResource."""
52
+
53
+ def __init__(self, config: DobbyConfig, http_client: httpx.AsyncClient) -> None:
54
+ self._config = config
55
+ self._http = http_client
56
+
57
+ async def _request(
58
+ self,
59
+ method: str,
60
+ path: str,
61
+ *,
62
+ json: dict[str, Any] | None = None,
63
+ params: dict[str, Any] | None = None,
64
+ ) -> dict[str, Any]:
65
+ """Make an authenticated async API request."""
66
+ url = f"{self._config.api_url}{path}"
67
+ headers = {
68
+ **self._config.auth_headers,
69
+ "X-Request-Id": str(uuid.uuid4()),
70
+ }
71
+
72
+ response = await self._http.request(
73
+ method=method,
74
+ url=url,
75
+ json=json,
76
+ params=params,
77
+ headers=headers,
78
+ timeout=self._config.timeout,
79
+ )
80
+
81
+ body = response.json() if response.content else {}
82
+ raise_for_status(response.status_code, body)
83
+ return body
@@ -0,0 +1,50 @@
1
+ """SDK configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass, field
7
+
8
+
9
+ @dataclass
10
+ class DobbyConfig:
11
+ """Configuration for the Dobby SDK client."""
12
+
13
+ api_key: str = field(default_factory=lambda: os.environ.get("DOBBY_API_KEY", ""))
14
+ base_url: str = field(
15
+ default_factory=lambda: os.environ.get("DOBBY_BASE_URL", "https://dobby-ai.com")
16
+ )
17
+ org_id: str | None = field(default_factory=lambda: os.environ.get("DOBBY_ORG_ID"))
18
+ tenant_id: str | None = field(default_factory=lambda: os.environ.get("DOBBY_TENANT_ID"))
19
+ timeout: float = 120.0
20
+ max_retries: int = 2
21
+
22
+ def __post_init__(self) -> None:
23
+ if not self.api_key:
24
+ raise ValueError(
25
+ "API key is required. Pass api_key= or set DOBBY_API_KEY environment variable."
26
+ )
27
+ self.base_url = self.base_url.rstrip("/")
28
+
29
+ @property
30
+ def gateway_url(self) -> str:
31
+ """Base URL for gateway API calls."""
32
+ return f"{self.base_url}/api/v1/gateway"
33
+
34
+ @property
35
+ def api_url(self) -> str:
36
+ """Base URL for platform API calls."""
37
+ return f"{self.base_url}/api/v1"
38
+
39
+ @property
40
+ def auth_headers(self) -> dict[str, str]:
41
+ """Headers required for all API calls."""
42
+ headers: dict[str, str] = {
43
+ "Authorization": f"Bearer {self.api_key}",
44
+ "User-Agent": "dobby-sdk-python/0.1.0",
45
+ }
46
+ if self.org_id:
47
+ headers["X-Org-Id"] = self.org_id
48
+ if self.tenant_id:
49
+ headers["X-Tenant-Id"] = self.tenant_id
50
+ return headers
@@ -0,0 +1,84 @@
1
+ """SDK exception hierarchy."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ class DobbyError(Exception):
9
+ """Base exception for all Dobby SDK errors."""
10
+
11
+ def __init__(
12
+ self,
13
+ message: str,
14
+ status_code: int | None = None,
15
+ body: dict[str, Any] | None = None,
16
+ ) -> None:
17
+ super().__init__(message)
18
+ self.status_code = status_code
19
+ self.body = body or {}
20
+
21
+ @property
22
+ def error_code(self) -> str | None:
23
+ return self.body.get("error")
24
+
25
+ @property
26
+ def error_message(self) -> str | None:
27
+ return self.body.get("message")
28
+
29
+
30
+ class DobbyAuthError(DobbyError):
31
+ """Authentication failed — invalid, expired, or revoked API key."""
32
+ pass
33
+
34
+
35
+ class DobbyRateLimitError(DobbyError):
36
+ """Rate limit exceeded for this API key tier."""
37
+
38
+ def __init__(
39
+ self,
40
+ message: str,
41
+ retry_after: float | None = None,
42
+ **kwargs: object,
43
+ ):
44
+ super().__init__(message, **kwargs) # type: ignore[arg-type]
45
+ self.retry_after = retry_after
46
+
47
+
48
+ class DobbyBudgetExceededError(DobbyError):
49
+ """Organization or tenant budget limit reached."""
50
+ pass
51
+
52
+
53
+ class DobbyNotFoundError(DobbyError):
54
+ """Requested resource not found."""
55
+ pass
56
+
57
+
58
+ class DobbyServerError(DobbyError):
59
+ """Server-side error (5xx)."""
60
+ pass
61
+
62
+
63
+ def raise_for_status(status_code: int, body: dict[str, Any]) -> None:
64
+ """Raise appropriate exception based on HTTP status code."""
65
+ if status_code < 400:
66
+ return
67
+
68
+ message = body.get("message") or body.get("error") or f"HTTP {status_code}"
69
+
70
+ if status_code == 401:
71
+ raise DobbyAuthError(message, status_code=status_code, body=body)
72
+ elif status_code == 403:
73
+ error_code = body.get("error", "")
74
+ if "budget" in error_code.lower() or "budget" in message.lower():
75
+ raise DobbyBudgetExceededError(message, status_code=status_code, body=body)
76
+ raise DobbyAuthError(message, status_code=status_code, body=body)
77
+ elif status_code == 404:
78
+ raise DobbyNotFoundError(message, status_code=status_code, body=body)
79
+ elif status_code == 429:
80
+ raise DobbyRateLimitError(message, status_code=status_code, body=body)
81
+ elif status_code >= 500:
82
+ raise DobbyServerError(message, status_code=status_code, body=body)
83
+ else:
84
+ raise DobbyError(message, status_code=status_code, body=body)