radhiops 0.0.1__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.
Files changed (68) hide show
  1. radhiops-0.0.1/.gitignore +32 -0
  2. radhiops-0.0.1/PKG-INFO +220 -0
  3. radhiops-0.0.1/README.md +191 -0
  4. radhiops-0.0.1/pyproject.toml +49 -0
  5. radhiops-0.0.1/radhiops/__init__.py +59 -0
  6. radhiops-0.0.1/radhiops/agents/__init__.py +19 -0
  7. radhiops-0.0.1/radhiops/agents/base.py +52 -0
  8. radhiops-0.0.1/radhiops/agents/cyberdefense.py +134 -0
  9. radhiops-0.0.1/radhiops/agents/deployment.py +132 -0
  10. radhiops-0.0.1/radhiops/agents/monitor.py +169 -0
  11. radhiops-0.0.1/radhiops/agents/repo.py +247 -0
  12. radhiops-0.0.1/radhiops/agents/soc.py +53 -0
  13. radhiops-0.0.1/radhiops/backend.py +146 -0
  14. radhiops-0.0.1/radhiops/cli.py +226 -0
  15. radhiops-0.0.1/radhiops/client.py +258 -0
  16. radhiops-0.0.1/radhiops/config.py +64 -0
  17. radhiops-0.0.1/radhiops/credits.py +91 -0
  18. radhiops-0.0.1/radhiops/defense/__init__.py +21 -0
  19. radhiops-0.0.1/radhiops/defense/behavior.py +86 -0
  20. radhiops-0.0.1/radhiops/defense/engine.py +102 -0
  21. radhiops-0.0.1/radhiops/defense/request.py +34 -0
  22. radhiops-0.0.1/radhiops/defense/signatures.py +103 -0
  23. radhiops-0.0.1/radhiops/deploy/__init__.py +23 -0
  24. radhiops-0.0.1/radhiops/deploy/base.py +157 -0
  25. radhiops-0.0.1/radhiops/deploy/diagnose.py +119 -0
  26. radhiops-0.0.1/radhiops/deploy/netlify.py +80 -0
  27. radhiops-0.0.1/radhiops/deploy/railway.py +89 -0
  28. radhiops-0.0.1/radhiops/deploy/registry.py +72 -0
  29. radhiops-0.0.1/radhiops/deploy/render.py +86 -0
  30. radhiops-0.0.1/radhiops/deploy/surge.py +70 -0
  31. radhiops-0.0.1/radhiops/deploy/vercel.py +74 -0
  32. radhiops-0.0.1/radhiops/exceptions.py +58 -0
  33. radhiops-0.0.1/radhiops/monitor/__init__.py +24 -0
  34. radhiops-0.0.1/radhiops/monitor/anomaly.py +90 -0
  35. radhiops-0.0.1/radhiops/monitor/crash.py +38 -0
  36. radhiops-0.0.1/radhiops/monitor/health.py +75 -0
  37. radhiops-0.0.1/radhiops/monitor/incident.py +97 -0
  38. radhiops-0.0.1/radhiops/monitor/metrics.py +69 -0
  39. radhiops-0.0.1/radhiops/orchestrator/__init__.py +9 -0
  40. radhiops-0.0.1/radhiops/orchestrator/autonomy.py +30 -0
  41. radhiops-0.0.1/radhiops/orchestrator/core.py +314 -0
  42. radhiops-0.0.1/radhiops/orchestrator/playbooks.py +83 -0
  43. radhiops-0.0.1/radhiops/plans.py +43 -0
  44. radhiops-0.0.1/radhiops/providers/__init__.py +20 -0
  45. radhiops-0.0.1/radhiops/providers/anthropic_provider.py +51 -0
  46. radhiops-0.0.1/radhiops/providers/base.py +92 -0
  47. radhiops-0.0.1/radhiops/providers/google_provider.py +40 -0
  48. radhiops-0.0.1/radhiops/providers/huggingface_provider.py +50 -0
  49. radhiops-0.0.1/radhiops/providers/ollama_provider.py +48 -0
  50. radhiops-0.0.1/radhiops/providers/openai_provider.py +42 -0
  51. radhiops-0.0.1/radhiops/providers/registry.py +85 -0
  52. radhiops-0.0.1/radhiops/repo/__init__.py +8 -0
  53. radhiops-0.0.1/radhiops/repo/git.py +149 -0
  54. radhiops-0.0.1/radhiops/repo/intents.py +100 -0
  55. radhiops-0.0.1/radhiops/security/__init__.py +19 -0
  56. radhiops-0.0.1/radhiops/security/secrets.py +199 -0
  57. radhiops-0.0.1/radhiops/userconfig.py +58 -0
  58. radhiops-0.0.1/tests/conftest.py +14 -0
  59. radhiops-0.0.1/tests/test_backend.py +102 -0
  60. radhiops-0.0.1/tests/test_client.py +55 -0
  61. radhiops-0.0.1/tests/test_defense.py +158 -0
  62. radhiops-0.0.1/tests/test_deploy.py +125 -0
  63. radhiops-0.0.1/tests/test_diagnose.py +34 -0
  64. radhiops-0.0.1/tests/test_intents.py +56 -0
  65. radhiops-0.0.1/tests/test_monitor.py +143 -0
  66. radhiops-0.0.1/tests/test_orchestrator.py +121 -0
  67. radhiops-0.0.1/tests/test_repo_agent.py +92 -0
  68. radhiops-0.0.1/tests/test_secrets.py +34 -0
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ env/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ htmlcov/
16
+
17
+ # Node
18
+ node_modules/
19
+ *.log
20
+ npm-debug.log*
21
+
22
+ # Env / secrets — never commit these
23
+ .env
24
+ .env.*
25
+ *.pem
26
+ *.key
27
+ secrets/
28
+
29
+ # IDE / OS
30
+ .DS_Store
31
+ .idea/
32
+ *.swp
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: radhiops
3
+ Version: 0.0.1
4
+ Summary: RadhiOps — BYOE AI Engineering Platform SDK
5
+ Author: RadhiOps
6
+ License: Apache-2.0
7
+ Keywords: agents,ai,byoe,devops,mcp,security
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: httpx>=0.27
10
+ Requires-Dist: pydantic>=2.6
11
+ Provides-Extra: all
12
+ Requires-Dist: anthropic>=0.34; extra == 'all'
13
+ Requires-Dist: google-generativeai>=0.7; extra == 'all'
14
+ Requires-Dist: huggingface-hub>=0.24; extra == 'all'
15
+ Requires-Dist: openai>=1.30; extra == 'all'
16
+ Provides-Extra: anthropic
17
+ Requires-Dist: anthropic>=0.34; extra == 'anthropic'
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
20
+ Requires-Dist: pytest>=8.0; extra == 'dev'
21
+ Requires-Dist: ruff>=0.5; extra == 'dev'
22
+ Provides-Extra: google
23
+ Requires-Dist: google-generativeai>=0.7; extra == 'google'
24
+ Provides-Extra: huggingface
25
+ Requires-Dist: huggingface-hub>=0.24; extra == 'huggingface'
26
+ Provides-Extra: openai
27
+ Requires-Dist: openai>=1.30; extra == 'openai'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # radhiops
31
+
32
+ The Python SDK for **RadhiOps** — the BYOE (Bring Your Own Everything) AI
33
+ Engineering Platform.
34
+
35
+ ```bash
36
+ pip install radhiops
37
+ # providers are optional extras — install only what you use:
38
+ pip install 'radhiops[openai]' # or [anthropic], [google], [huggingface], [all]
39
+ # ollama needs no extra (talks to your local server)
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ from radhiops import RadhiOps
46
+
47
+ # New here? A demo key seeds 500 free credits, fully offline.
48
+ ops = RadhiOps(access_key="radhi_demo_yourtrialkey123")
49
+
50
+ # Run a local security audit (no AI, no network needed).
51
+ report = ops.soc.audit("./my-project")
52
+ print(report.counts()) # {'low': 0, 'medium': 1, 'high': 0, 'critical': 0}
53
+ print(report.passed) # gate result for pre-push / pre-deploy
54
+
55
+ # Bring your own model for AI-assisted remediation.
56
+ ops.use_model("openai", model="gpt-4o-mini", api_key="sk-...")
57
+ print(ops.soc.remediate(report))
58
+
59
+ # Or run a fully local model via Ollama — no API key:
60
+ ops.use_model("ollama", model="llama3.1")
61
+ ```
62
+
63
+ ## Repo agent — Git in plain English
64
+
65
+ ```python
66
+ repo = ops.repo("./my-project")
67
+
68
+ repo.command("what changed?")
69
+ repo.command('commit "fix: handle null user"')
70
+ repo.command("create a new branch feature/login")
71
+ repo.command("merge dev into main")
72
+
73
+ # push() runs a RadhiSOC security gate first and BLOCKS on high/critical
74
+ # findings unless you explicitly override.
75
+ result = repo.push()
76
+ if not result.ok:
77
+ print(result.message) # e.g. "Security gate blocked the push: 1 finding"
78
+ ```
79
+
80
+ Common verbs are parsed by rules (free, offline). Ambiguous phrasing falls back
81
+ to your BYOE model. Protected branches (main/master/prod) require
82
+ `allow_protected=True`, and force pushes use `--force-with-lease`.
83
+
84
+ ```bash
85
+ radhiops repo "push my changes" --path ./my-project
86
+ radhiops repo "merge dev into main"
87
+ ```
88
+
89
+ ## Deployment agent — BYOE deploy targets
90
+
91
+ Bring your own platform token. RadhiOps never stores it.
92
+
93
+ ```python
94
+ # Vercel / Netlify / Render / Railway / Surge
95
+ dep = ops.deploy("vercel", token="<vercel-token>", team_id="team_...")
96
+
97
+ dep.list(limit=5) # recent deployments (normalized)
98
+ d = dep.trigger() # kick a new deployment (where supported)
99
+ final = dep.watch(d.id) # poll until ready/failed
100
+ if final.status.failed:
101
+ diag = dep.diagnose(d.id) # rule-based + AI root-cause from the logs
102
+ print(diag.rule_based["suggestion"])
103
+ ```
104
+
105
+ | Platform | name | Scope option | Triggers deploys |
106
+ |----------|------|--------------|------------------|
107
+ | Vercel | `vercel` | `team_id` (optional) | via git integration |
108
+ | Netlify | `netlify` | `site_id` | yes (build) |
109
+ | Render | `render` | `service_id` | yes |
110
+ | Railway | `railway` | `service_id` | (monitor) |
111
+ | Surge | `surge` | `domain` | yes (CLI) |
112
+
113
+ The log diagnoser recognises common failures (missing modules, unset env vars,
114
+ OOM, port conflicts, lockfile mismatches) with zero credits; anything it can't
115
+ classify is escalated to your BYOE model.
116
+
117
+ ```bash
118
+ radhiops deploy render status --id dep_123 --token $RENDER_TOKEN --opt service_id=srv_abc
119
+ radhiops deploy vercel diagnose --id dpl_123 --token $VERCEL_TOKEN
120
+ ```
121
+
122
+ ## Runtime Monitor — production health & incidents
123
+
124
+ ```python
125
+ mon = ops.monitor()
126
+ mon.add_target("api", "https://myapp.com/health", contains="ok")
127
+ mon.add_target("web", "https://myapp.com")
128
+
129
+ mon.poll() # probe every target once
130
+ for inc in mon.evaluate(): # anomalies -> incidents
131
+ print(inc.severity, inc.summary, "->", inc.escalate_to)
132
+
133
+ # crash detection from a runtime log stream
134
+ crash = mon.ingest_logs("api", ["Traceback (most recent call last):", "MemoryError"])
135
+
136
+ # or run a monitoring loop with a callback per incident
137
+ mon.watch(rounds=10, interval=30, on_incident=lambda i: print(i.to_dict()))
138
+ ```
139
+
140
+ Detects: endpoint down (consecutive failures), error-rate spikes, latency
141
+ degradation (p95), and runtime crashes (OOM, segfault, unhandled exceptions,
142
+ restart loops, DB connection failures). Each incident is tagged with the agent
143
+ that should handle it next (`DeploymentAgent`, `CyberDefenseAgent`), ready for
144
+ the autonomous loop. Thresholds are tunable via `Thresholds`.
145
+
146
+ ## Cyber Defense agent — runtime attack detection
147
+
148
+ Feed inbound requests through the guard; it returns an allow/challenge/block
149
+ verdict and auto-blocklists serious offenders.
150
+
151
+ ```python
152
+ guard = ops.defense()
153
+
154
+ verdict = guard.analyze({
155
+ "ip": "203.0.113.9",
156
+ "path": "/search",
157
+ "query": "q=' UNION SELECT password FROM users--",
158
+ })
159
+ if verdict.blocked:
160
+ return Response(status=403)
161
+
162
+ # behavioral: repeated failed logins from one IP -> brute force / stuffing
163
+ verdict, incident = guard.inspect({"ip": "203.0.113.9", "auth_failed": True, "user": "admin"})
164
+
165
+ # framework hook
166
+ guard_fn = guard.middleware(on_block=lambda v: log.warning("blocked %s", v.ip))
167
+ ```
168
+
169
+ Detects: SQL injection, XSS, SSRF, path traversal, command injection, header
170
+ (CRLF) injection, brute force, credential stuffing, rate-limit abuse, and DDoS.
171
+ Code-level attacks escalate to RadhiSOC (fix the code); volumetric attacks are
172
+ blocked directly. Scoring/thresholds are tunable via `DefenseConfig`.
173
+
174
+ ## CLI
175
+
176
+ ```bash
177
+ export RADHIOPS_ACCESS_KEY=radhi_demo_yourtrialkey123
178
+ radhiops audit ./my-project
179
+ radhiops audit . --json
180
+ ```
181
+
182
+ The `audit` command exits non-zero when high/critical findings are present, so
183
+ it drops straight into CI or a Kiro pre-push hook.
184
+
185
+ ## Supported model providers (BYOE)
186
+
187
+ | Provider | name | Needs key? | Extra |
188
+ |----------|------|-----------|-------|
189
+ | OpenAI / compatible | `openai` | yes | `[openai]` |
190
+ | Anthropic | `anthropic` | yes | `[anthropic]` |
191
+ | Google Gemini | `google` | yes | `[google]` |
192
+ | Ollama (local) | `ollama` | no | — |
193
+ | Hugging Face | `huggingface` | yes | `[huggingface]` |
194
+
195
+ Register your own (e.g. an MCP-backed model) with
196
+ `radhiops.register_provider("mymodel", MyProviderClass)`.
197
+
198
+ ## Status
199
+
200
+ Phase 0–5: BYOE model layer, access-key client, credit ledger (local + hosted),
201
+ and all five agents — RadhiSOC (security), Repo (Git + pre-push gate),
202
+ Deployment (multi-platform + log diagnosis), Runtime Monitor (health, anomalies,
203
+ crashes), and Cyber Defense (runtime attack detection) — plus the Supabase
204
+ backend. The autonomous cross-agent loop (incidents routing Monitor → Deployment
205
+ → RadhiSOC → Repo automatically) is next.
206
+
207
+ ### Online vs offline
208
+
209
+ ```python
210
+ # Offline (default): local credit ledger, demo keys seeded with 500 credits.
211
+ ops = RadhiOps(access_key="radhi_demo_...")
212
+
213
+ # Online: validate + meter against the hosted backend (Supabase edge functions).
214
+ ops = RadhiOps(
215
+ access_key="radhi_live_...",
216
+ offline=False,
217
+ api_base="https://<project-ref>.supabase.co",
218
+ anon_key="<supabase-anon-key>",
219
+ )
220
+ ```
@@ -0,0 +1,191 @@
1
+ # radhiops
2
+
3
+ The Python SDK for **RadhiOps** — the BYOE (Bring Your Own Everything) AI
4
+ Engineering Platform.
5
+
6
+ ```bash
7
+ pip install radhiops
8
+ # providers are optional extras — install only what you use:
9
+ pip install 'radhiops[openai]' # or [anthropic], [google], [huggingface], [all]
10
+ # ollama needs no extra (talks to your local server)
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```python
16
+ from radhiops import RadhiOps
17
+
18
+ # New here? A demo key seeds 500 free credits, fully offline.
19
+ ops = RadhiOps(access_key="radhi_demo_yourtrialkey123")
20
+
21
+ # Run a local security audit (no AI, no network needed).
22
+ report = ops.soc.audit("./my-project")
23
+ print(report.counts()) # {'low': 0, 'medium': 1, 'high': 0, 'critical': 0}
24
+ print(report.passed) # gate result for pre-push / pre-deploy
25
+
26
+ # Bring your own model for AI-assisted remediation.
27
+ ops.use_model("openai", model="gpt-4o-mini", api_key="sk-...")
28
+ print(ops.soc.remediate(report))
29
+
30
+ # Or run a fully local model via Ollama — no API key:
31
+ ops.use_model("ollama", model="llama3.1")
32
+ ```
33
+
34
+ ## Repo agent — Git in plain English
35
+
36
+ ```python
37
+ repo = ops.repo("./my-project")
38
+
39
+ repo.command("what changed?")
40
+ repo.command('commit "fix: handle null user"')
41
+ repo.command("create a new branch feature/login")
42
+ repo.command("merge dev into main")
43
+
44
+ # push() runs a RadhiSOC security gate first and BLOCKS on high/critical
45
+ # findings unless you explicitly override.
46
+ result = repo.push()
47
+ if not result.ok:
48
+ print(result.message) # e.g. "Security gate blocked the push: 1 finding"
49
+ ```
50
+
51
+ Common verbs are parsed by rules (free, offline). Ambiguous phrasing falls back
52
+ to your BYOE model. Protected branches (main/master/prod) require
53
+ `allow_protected=True`, and force pushes use `--force-with-lease`.
54
+
55
+ ```bash
56
+ radhiops repo "push my changes" --path ./my-project
57
+ radhiops repo "merge dev into main"
58
+ ```
59
+
60
+ ## Deployment agent — BYOE deploy targets
61
+
62
+ Bring your own platform token. RadhiOps never stores it.
63
+
64
+ ```python
65
+ # Vercel / Netlify / Render / Railway / Surge
66
+ dep = ops.deploy("vercel", token="<vercel-token>", team_id="team_...")
67
+
68
+ dep.list(limit=5) # recent deployments (normalized)
69
+ d = dep.trigger() # kick a new deployment (where supported)
70
+ final = dep.watch(d.id) # poll until ready/failed
71
+ if final.status.failed:
72
+ diag = dep.diagnose(d.id) # rule-based + AI root-cause from the logs
73
+ print(diag.rule_based["suggestion"])
74
+ ```
75
+
76
+ | Platform | name | Scope option | Triggers deploys |
77
+ |----------|------|--------------|------------------|
78
+ | Vercel | `vercel` | `team_id` (optional) | via git integration |
79
+ | Netlify | `netlify` | `site_id` | yes (build) |
80
+ | Render | `render` | `service_id` | yes |
81
+ | Railway | `railway` | `service_id` | (monitor) |
82
+ | Surge | `surge` | `domain` | yes (CLI) |
83
+
84
+ The log diagnoser recognises common failures (missing modules, unset env vars,
85
+ OOM, port conflicts, lockfile mismatches) with zero credits; anything it can't
86
+ classify is escalated to your BYOE model.
87
+
88
+ ```bash
89
+ radhiops deploy render status --id dep_123 --token $RENDER_TOKEN --opt service_id=srv_abc
90
+ radhiops deploy vercel diagnose --id dpl_123 --token $VERCEL_TOKEN
91
+ ```
92
+
93
+ ## Runtime Monitor — production health & incidents
94
+
95
+ ```python
96
+ mon = ops.monitor()
97
+ mon.add_target("api", "https://myapp.com/health", contains="ok")
98
+ mon.add_target("web", "https://myapp.com")
99
+
100
+ mon.poll() # probe every target once
101
+ for inc in mon.evaluate(): # anomalies -> incidents
102
+ print(inc.severity, inc.summary, "->", inc.escalate_to)
103
+
104
+ # crash detection from a runtime log stream
105
+ crash = mon.ingest_logs("api", ["Traceback (most recent call last):", "MemoryError"])
106
+
107
+ # or run a monitoring loop with a callback per incident
108
+ mon.watch(rounds=10, interval=30, on_incident=lambda i: print(i.to_dict()))
109
+ ```
110
+
111
+ Detects: endpoint down (consecutive failures), error-rate spikes, latency
112
+ degradation (p95), and runtime crashes (OOM, segfault, unhandled exceptions,
113
+ restart loops, DB connection failures). Each incident is tagged with the agent
114
+ that should handle it next (`DeploymentAgent`, `CyberDefenseAgent`), ready for
115
+ the autonomous loop. Thresholds are tunable via `Thresholds`.
116
+
117
+ ## Cyber Defense agent — runtime attack detection
118
+
119
+ Feed inbound requests through the guard; it returns an allow/challenge/block
120
+ verdict and auto-blocklists serious offenders.
121
+
122
+ ```python
123
+ guard = ops.defense()
124
+
125
+ verdict = guard.analyze({
126
+ "ip": "203.0.113.9",
127
+ "path": "/search",
128
+ "query": "q=' UNION SELECT password FROM users--",
129
+ })
130
+ if verdict.blocked:
131
+ return Response(status=403)
132
+
133
+ # behavioral: repeated failed logins from one IP -> brute force / stuffing
134
+ verdict, incident = guard.inspect({"ip": "203.0.113.9", "auth_failed": True, "user": "admin"})
135
+
136
+ # framework hook
137
+ guard_fn = guard.middleware(on_block=lambda v: log.warning("blocked %s", v.ip))
138
+ ```
139
+
140
+ Detects: SQL injection, XSS, SSRF, path traversal, command injection, header
141
+ (CRLF) injection, brute force, credential stuffing, rate-limit abuse, and DDoS.
142
+ Code-level attacks escalate to RadhiSOC (fix the code); volumetric attacks are
143
+ blocked directly. Scoring/thresholds are tunable via `DefenseConfig`.
144
+
145
+ ## CLI
146
+
147
+ ```bash
148
+ export RADHIOPS_ACCESS_KEY=radhi_demo_yourtrialkey123
149
+ radhiops audit ./my-project
150
+ radhiops audit . --json
151
+ ```
152
+
153
+ The `audit` command exits non-zero when high/critical findings are present, so
154
+ it drops straight into CI or a Kiro pre-push hook.
155
+
156
+ ## Supported model providers (BYOE)
157
+
158
+ | Provider | name | Needs key? | Extra |
159
+ |----------|------|-----------|-------|
160
+ | OpenAI / compatible | `openai` | yes | `[openai]` |
161
+ | Anthropic | `anthropic` | yes | `[anthropic]` |
162
+ | Google Gemini | `google` | yes | `[google]` |
163
+ | Ollama (local) | `ollama` | no | — |
164
+ | Hugging Face | `huggingface` | yes | `[huggingface]` |
165
+
166
+ Register your own (e.g. an MCP-backed model) with
167
+ `radhiops.register_provider("mymodel", MyProviderClass)`.
168
+
169
+ ## Status
170
+
171
+ Phase 0–5: BYOE model layer, access-key client, credit ledger (local + hosted),
172
+ and all five agents — RadhiSOC (security), Repo (Git + pre-push gate),
173
+ Deployment (multi-platform + log diagnosis), Runtime Monitor (health, anomalies,
174
+ crashes), and Cyber Defense (runtime attack detection) — plus the Supabase
175
+ backend. The autonomous cross-agent loop (incidents routing Monitor → Deployment
176
+ → RadhiSOC → Repo automatically) is next.
177
+
178
+ ### Online vs offline
179
+
180
+ ```python
181
+ # Offline (default): local credit ledger, demo keys seeded with 500 credits.
182
+ ops = RadhiOps(access_key="radhi_demo_...")
183
+
184
+ # Online: validate + meter against the hosted backend (Supabase edge functions).
185
+ ops = RadhiOps(
186
+ access_key="radhi_live_...",
187
+ offline=False,
188
+ api_base="https://<project-ref>.supabase.co",
189
+ anon_key="<supabase-anon-key>",
190
+ )
191
+ ```
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "radhiops"
7
+ version = "0.0.1"
8
+ description = "RadhiOps — BYOE AI Engineering Platform SDK"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "Apache-2.0" }
12
+ authors = [{ name = "RadhiOps" }]
13
+ keywords = ["ai", "agents", "devops", "security", "byoe", "mcp"]
14
+ dependencies = [
15
+ "httpx>=0.27",
16
+ "pydantic>=2.6",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ openai = ["openai>=1.30"]
21
+ anthropic = ["anthropic>=0.34"]
22
+ google = ["google-generativeai>=0.7"]
23
+ huggingface = ["huggingface-hub>=0.24"]
24
+ # ollama uses its local HTTP API via httpx — no extra dep required.
25
+ all = [
26
+ "openai>=1.30",
27
+ "anthropic>=0.34",
28
+ "google-generativeai>=0.7",
29
+ "huggingface-hub>=0.24",
30
+ ]
31
+ dev = [
32
+ "pytest>=8.0",
33
+ "pytest-asyncio>=0.23",
34
+ "ruff>=0.5",
35
+ ]
36
+
37
+ [project.scripts]
38
+ radhiops = "radhiops.cli:main"
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["radhiops"]
42
+
43
+ [tool.pytest.ini_options]
44
+ asyncio_mode = "auto"
45
+ testpaths = ["tests"]
46
+
47
+ [tool.ruff]
48
+ line-length = 100
49
+ target-version = "py310"
@@ -0,0 +1,59 @@
1
+ """RadhiOps — BYOE AI Engineering Platform SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.0.1"
6
+
7
+ from .client import RadhiOps
8
+ from .exceptions import (
9
+ AgentError,
10
+ AuthError,
11
+ InsufficientCreditsError,
12
+ ProviderError,
13
+ RadhiOpsError,
14
+ SubscriptionRequiredError,
15
+ )
16
+ from .plans import PLANS, Plan, upgrade_hint
17
+ from .orchestrator import AutonomyMode, Orchestrator
18
+ from .providers import (
19
+ ChatResult,
20
+ Message,
21
+ ModelProvider,
22
+ available_providers,
23
+ get_provider,
24
+ register_provider,
25
+ )
26
+ from .deploy import (
27
+ Deployment,
28
+ DeployStatus,
29
+ available_deploy_providers,
30
+ get_deploy_provider,
31
+ register_deploy_provider,
32
+ )
33
+
34
+ __all__ = [
35
+ "__version__",
36
+ "RadhiOps",
37
+ "RadhiOpsError",
38
+ "AuthError",
39
+ "AgentError",
40
+ "ProviderError",
41
+ "InsufficientCreditsError",
42
+ "SubscriptionRequiredError",
43
+ "PLANS",
44
+ "Plan",
45
+ "upgrade_hint",
46
+ "AutonomyMode",
47
+ "Orchestrator",
48
+ "ChatResult",
49
+ "Message",
50
+ "ModelProvider",
51
+ "available_providers",
52
+ "get_provider",
53
+ "register_provider",
54
+ "Deployment",
55
+ "DeployStatus",
56
+ "available_deploy_providers",
57
+ "get_deploy_provider",
58
+ "register_deploy_provider",
59
+ ]
@@ -0,0 +1,19 @@
1
+ """RadhiOps agents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .base import Agent
6
+ from .cyberdefense import CyberDefenseAgent
7
+ from .deployment import DeploymentAgent
8
+ from .monitor import RuntimeMonitor
9
+ from .repo import RepoAgent
10
+ from .soc import RadhiSOC
11
+
12
+ __all__ = [
13
+ "Agent",
14
+ "RadhiSOC",
15
+ "RepoAgent",
16
+ "DeploymentAgent",
17
+ "RuntimeMonitor",
18
+ "CyberDefenseAgent",
19
+ ]
@@ -0,0 +1,52 @@
1
+ """Base class shared by every RadhiOps agent.
2
+
3
+ An agent is given:
4
+ - a reference to the :class:`RadhiOps` client (for credits/auth/telemetry)
5
+ - an optional BYOE model provider (the user's own model)
6
+
7
+ Agents expose high-level capabilities (audit, deploy, monitor, ...). Each
8
+ capability that consumes platform resources reports its credit cost through
9
+ ``self._charge(...)`` so usage stays transparent.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from ..providers.base import Message, ModelProvider
17
+
18
+ if TYPE_CHECKING:
19
+ from ..client import RadhiOps
20
+
21
+
22
+ class Agent:
23
+ #: Human-facing name, e.g. "RadhiSOC".
24
+ name: str = "Agent"
25
+
26
+ def __init__(self, client: "RadhiOps", model: ModelProvider | None = None) -> None:
27
+ self.client = client
28
+ self._model = model
29
+
30
+ @property
31
+ def model(self) -> ModelProvider:
32
+ """The BYOE model bound to this agent (falls back to the client default)."""
33
+ m = self._model or self.client.default_model
34
+ if m is None:
35
+ from ..exceptions import ProviderError
36
+
37
+ raise ProviderError(
38
+ f"{self.name} needs a model. Pass model=... or set a default "
39
+ "provider/model on the RadhiOps client."
40
+ )
41
+ return m
42
+
43
+ def _ask(self, system: str, user: str, **opts: Any) -> str:
44
+ """Convenience: single-turn prompt to the bound model."""
45
+ result = self.model.chat(
46
+ [Message("system", system), Message("user", user)], **opts
47
+ )
48
+ return result.text
49
+
50
+ def _charge(self, credits: int, action: str) -> None:
51
+ """Record credit usage for an action via the client."""
52
+ self.client._consume_credits(credits, f"{self.name}:{action}")