solvent-agent 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.
- solvent_agent-0.1.0/LICENSE +21 -0
- solvent_agent-0.1.0/PKG-INFO +422 -0
- solvent_agent-0.1.0/README.md +387 -0
- solvent_agent-0.1.0/pyproject.toml +58 -0
- solvent_agent-0.1.0/setup.cfg +4 -0
- solvent_agent-0.1.0/solvent/__init__.py +3 -0
- solvent_agent-0.1.0/solvent/__main__.py +172 -0
- solvent_agent-0.1.0/solvent/agent.py +90 -0
- solvent_agent-0.1.0/solvent/channels/__init__.py +1 -0
- solvent_agent-0.1.0/solvent/channels/telegram.py +104 -0
- solvent_agent-0.1.0/solvent/chat.py +279 -0
- solvent_agent-0.1.0/solvent/cli.py +354 -0
- solvent_agent-0.1.0/solvent/config.py +124 -0
- solvent_agent-0.1.0/solvent/config_cmd.py +151 -0
- solvent_agent-0.1.0/solvent/dashboard.py +1496 -0
- solvent_agent-0.1.0/solvent/dashboard_chat.py +316 -0
- solvent_agent-0.1.0/solvent/delivery.py +398 -0
- solvent_agent-0.1.0/solvent/doctor.py +132 -0
- solvent_agent-0.1.0/solvent/event_hub.py +49 -0
- solvent_agent-0.1.0/solvent/finance.py +424 -0
- solvent_agent-0.1.0/solvent/gateway.py +189 -0
- solvent_agent-0.1.0/solvent/guardrails.py +195 -0
- solvent_agent-0.1.0/solvent/init.py +146 -0
- solvent_agent-0.1.0/solvent/job_cmd.py +258 -0
- solvent_agent-0.1.0/solvent/jobs.py +60 -0
- solvent_agent-0.1.0/solvent/logs.py +211 -0
- solvent_agent-0.1.0/solvent/memory.py +26 -0
- solvent_agent-0.1.0/solvent/nemotron.py +418 -0
- solvent_agent-0.1.0/solvent/notifications.py +69 -0
- solvent_agent-0.1.0/solvent/observability.py +54 -0
- solvent_agent-0.1.0/solvent/onboarding.py +234 -0
- solvent_agent-0.1.0/solvent/pairing.py +94 -0
- solvent_agent-0.1.0/solvent/paths.py +63 -0
- solvent_agent-0.1.0/solvent/pricing.py +152 -0
- solvent_agent-0.1.0/solvent/py.typed +0 -0
- solvent_agent-0.1.0/solvent/qr.py +62 -0
- solvent_agent-0.1.0/solvent/queue.py +37 -0
- solvent_agent-0.1.0/solvent/rate_limit.py +187 -0
- solvent_agent-0.1.0/solvent/receipt.py +129 -0
- solvent_agent-0.1.0/solvent/reconcile.py +97 -0
- solvent_agent-0.1.0/solvent/security.py +427 -0
- solvent_agent-0.1.0/solvent/server.py +454 -0
- solvent_agent-0.1.0/solvent/service.py +119 -0
- solvent_agent-0.1.0/solvent/stages.py +694 -0
- solvent_agent-0.1.0/solvent/status.py +194 -0
- solvent_agent-0.1.0/solvent/stripe_client.py +519 -0
- solvent_agent-0.1.0/solvent/templates/workspace/AGENTS.md +34 -0
- solvent_agent-0.1.0/solvent/templates/workspace/BRAIN.md +26 -0
- solvent_agent-0.1.0/solvent/templates/workspace/SOUL.md +33 -0
- solvent_agent-0.1.0/solvent/templates/workspace/skills/commission-research/SKILL.md +23 -0
- solvent_agent-0.1.0/solvent/tools.py +195 -0
- solvent_agent-0.1.0/solvent/treasury.py +900 -0
- solvent_agent-0.1.0/solvent/upgrade.py +171 -0
- solvent_agent-0.1.0/solvent/webhook_log.py +158 -0
- solvent_agent-0.1.0/solvent/worker.py +56 -0
- solvent_agent-0.1.0/solvent/workspace.py +342 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/PKG-INFO +422 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/SOURCES.txt +107 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/dependency_links.txt +1 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/entry_points.txt +2 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/requires.txt +24 -0
- solvent_agent-0.1.0/solvent_agent.egg-info/top_level.txt +1 -0
- solvent_agent-0.1.0/tests/test_agent.py +51 -0
- solvent_agent-0.1.0/tests/test_chat_tools.py +192 -0
- solvent_agent-0.1.0/tests/test_cli_routing.py +256 -0
- solvent_agent-0.1.0/tests/test_config.py +101 -0
- solvent_agent-0.1.0/tests/test_config_cmd.py +229 -0
- solvent_agent-0.1.0/tests/test_dashboard_chat.py +38 -0
- solvent_agent-0.1.0/tests/test_dashboard_financials.py +105 -0
- solvent_agent-0.1.0/tests/test_dashboard_security.py +74 -0
- solvent_agent-0.1.0/tests/test_delivery.py +65 -0
- solvent_agent-0.1.0/tests/test_doctor.py +55 -0
- solvent_agent-0.1.0/tests/test_event_hub.py +69 -0
- solvent_agent-0.1.0/tests/test_finance.py +212 -0
- solvent_agent-0.1.0/tests/test_gateway.py +64 -0
- solvent_agent-0.1.0/tests/test_guardrails.py +191 -0
- solvent_agent-0.1.0/tests/test_init.py +155 -0
- solvent_agent-0.1.0/tests/test_job_cmd.py +255 -0
- solvent_agent-0.1.0/tests/test_jobs.py +85 -0
- solvent_agent-0.1.0/tests/test_logs.py +263 -0
- solvent_agent-0.1.0/tests/test_memory.py +54 -0
- solvent_agent-0.1.0/tests/test_metrics_block.py +56 -0
- solvent_agent-0.1.0/tests/test_nemotron_parse.py +170 -0
- solvent_agent-0.1.0/tests/test_notifications.py +62 -0
- solvent_agent-0.1.0/tests/test_observability.py +128 -0
- solvent_agent-0.1.0/tests/test_onboarding.py +98 -0
- solvent_agent-0.1.0/tests/test_packaging.py +60 -0
- solvent_agent-0.1.0/tests/test_paths.py +62 -0
- solvent_agent-0.1.0/tests/test_pricing.py +192 -0
- solvent_agent-0.1.0/tests/test_qr.py +58 -0
- solvent_agent-0.1.0/tests/test_queue.py +149 -0
- solvent_agent-0.1.0/tests/test_rate_limit.py +267 -0
- solvent_agent-0.1.0/tests/test_receipt.py +281 -0
- solvent_agent-0.1.0/tests/test_reconcile.py +240 -0
- solvent_agent-0.1.0/tests/test_research_brief.py +53 -0
- solvent_agent-0.1.0/tests/test_retry.py +332 -0
- solvent_agent-0.1.0/tests/test_security.py +437 -0
- solvent_agent-0.1.0/tests/test_server.py +116 -0
- solvent_agent-0.1.0/tests/test_stages.py +95 -0
- solvent_agent-0.1.0/tests/test_status.py +221 -0
- solvent_agent-0.1.0/tests/test_stripe_client.py +454 -0
- solvent_agent-0.1.0/tests/test_telegram_pairing.py +73 -0
- solvent_agent-0.1.0/tests/test_tools.py +52 -0
- solvent_agent-0.1.0/tests/test_treasury.py +87 -0
- solvent_agent-0.1.0/tests/test_upgrade.py +169 -0
- solvent_agent-0.1.0/tests/test_upgrade_hint.py +164 -0
- solvent_agent-0.1.0/tests/test_webhook_log.py +127 -0
- solvent_agent-0.1.0/tests/test_worker.py +181 -0
- solvent_agent-0.1.0/tests/test_workspace.py +70 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Ian Alloway
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solvent-agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A self-funding analyst agent: earns on Stripe, fulfils with NVIDIA Nemotron, spends within guardrails.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/ianalloway/solvent-agent
|
|
7
|
+
Project-URL: Repository, https://github.com/ianalloway/solvent-agent
|
|
8
|
+
Keywords: agent,stripe,nvidia,nemotron,llm,treasury
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Provides-Extra: stripe
|
|
17
|
+
Requires-Dist: stripe>=9.0.0; extra == "stripe"
|
|
18
|
+
Provides-Extra: serve
|
|
19
|
+
Requires-Dist: fastapi>=0.110.0; extra == "serve"
|
|
20
|
+
Requires-Dist: uvicorn[standard]>=0.27.0; extra == "serve"
|
|
21
|
+
Provides-Extra: qr
|
|
22
|
+
Requires-Dist: qrcode[pil]>=7.0; extra == "qr"
|
|
23
|
+
Provides-Extra: telegram
|
|
24
|
+
Requires-Dist: python-telegram-bot>=21.0; extra == "telegram"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.3; extra == "dev"
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: stripe>=9.0.0; extra == "all"
|
|
30
|
+
Requires-Dist: fastapi>=0.110.0; extra == "all"
|
|
31
|
+
Requires-Dist: uvicorn[standard]>=0.27.0; extra == "all"
|
|
32
|
+
Requires-Dist: qrcode[pil]>=7.0; extra == "all"
|
|
33
|
+
Requires-Dist: python-telegram-bot>=21.0; extra == "all"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
<div align="center">
|
|
37
|
+
|
|
38
|
+
# 🪙 SOLVENT
|
|
39
|
+
|
|
40
|
+
**An AI agent that runs as a profitable, self-funding business.**
|
|
41
|
+
|
|
42
|
+
It sells research briefs. It collects payment on Stripe. It spends its own revenue to provision the compute it needs. And it refuses any job that doesn't clear a margin.
|
|
43
|
+
|
|
44
|
+
[](https://www.python.org/downloads/)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
[](https://www.nvidia.com)
|
|
47
|
+
[](https://github.com/ianalloway/solvent-agent/stargazers)
|
|
48
|
+
|
|
49
|
+
[**Quick Start**](#-quick-start) · [**How It Works**](#-how-it-works) · [**Live Demo**](#-the-demo) · [**Make It Real**](#-make-it-real)
|
|
50
|
+
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## The Big Idea
|
|
56
|
+
|
|
57
|
+
Most agents can spend money. Almost none can **run as a business.**
|
|
58
|
+
|
|
59
|
+
SOLVENT closes the full loop:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Client pays Stripe → Agent earns revenue → Agent fulfils the work
|
|
63
|
+
→ Agent pays its own vendor bills → P&L booked → balance sheet grows
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every job is **profit-gated before it starts**. Unprofitable work is declined without touching Stripe. Vendor payments are screened by a NemoClaw-style policy sandbox. The agent literally cannot spend more than it earns.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 🚀 Quick Start
|
|
71
|
+
|
|
72
|
+
**Zero dependencies. No API keys. Works right now.**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/ianalloway/solvent-agent.git
|
|
76
|
+
cd solvent-agent
|
|
77
|
+
python3 run_demo.py
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The agent will run a full batch of 4 analyst jobs — complete with margin gating, Stripe payment simulation, NVIDIA Nemotron fulfillment, guardrail screening, and live P&L — in about 30 seconds.
|
|
81
|
+
|
|
82
|
+
### Install as a package (optional)
|
|
83
|
+
|
|
84
|
+
The core runs on the **standard library alone**, so a bare install pulls in
|
|
85
|
+
nothing extra and gives you a `solvent` command:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install -e . # editable install from a checkout
|
|
89
|
+
# PyPI / pipx publish pending — not on PyPI yet:
|
|
90
|
+
# pip install git+https://github.com/ianalloway/solvent-agent.git
|
|
91
|
+
|
|
92
|
+
solvent # run the demo
|
|
93
|
+
solvent finance # financial report (income, runway, forecast)
|
|
94
|
+
solvent --help # list all commands
|
|
95
|
+
solvent --version
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Third-party features are **opt-in extras** — install only what you need:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install -e ".[stripe]" # real Stripe test-mode payment links
|
|
102
|
+
pip install -e ".[serve]" # FastAPI webhooks + hosted briefs
|
|
103
|
+
pip install -e ".[telegram]" # Telegram bot channel
|
|
104
|
+
pip install -e ".[qr]" # scannable QR codes for OpenClaw pairing
|
|
105
|
+
pip install -e ".[dev]" # pytest, for running the test suite
|
|
106
|
+
pip install -e ".[all]" # everything
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
When run from a source checkout, runtime data stays under `<repo>/data`. When
|
|
110
|
+
installed elsewhere, SOLVENT writes to `~/.solvent` instead of into
|
|
111
|
+
`site-packages` — override either with `SOLVENT_HOME=/path/to/dir`.
|
|
112
|
+
|
|
113
|
+
> **First run**: A short onboarding wizard asks you to choose a model, interaction mode, and whether to enable Stripe test mode. Preferences are saved to `.solvent/config.json` and never committed.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 📊 The Demo
|
|
118
|
+
|
|
119
|
+
After a run, open the live treasury dashboard:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
open treasury_dashboard.html # macOS
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+

|
|
126
|
+
|
|
127
|
+
A typical **offline demo** batch (illustrative numbers from the simulated run — not production revenue):
|
|
128
|
+
|
|
129
|
+
| Metric | Demo value |
|
|
130
|
+
|---|---|
|
|
131
|
+
| Revenue | ~$223 |
|
|
132
|
+
| Operating spend | ~$13 |
|
|
133
|
+
| Net profit | high-margin demo loop |
|
|
134
|
+
| Jobs declined | 1 (below margin floor) |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## ⚙️ How It Works
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
inbound job
|
|
142
|
+
│
|
|
143
|
+
▼
|
|
144
|
+
┌─────────────┐ margin < floor? ┌───────────┐
|
|
145
|
+
│ MARGIN GATE│ ─────────────────▶ │ DECLINE │
|
|
146
|
+
│ (pricing) │ └───────────┘
|
|
147
|
+
└─────┬───────┘ accept
|
|
148
|
+
▼
|
|
149
|
+
┌─────────────┐ EARN
|
|
150
|
+
│ STRIPE │ ── Payment Link → poll/webhook until paid ──▶ + revenue
|
|
151
|
+
└─────┬───────┘ (records cs_... + pi_... on ledger)
|
|
152
|
+
▼
|
|
153
|
+
┌─────────────┐ FULFIL
|
|
154
|
+
│ NEMOTRON │ ── Llama-3.1-Nemotron-Ultra produces the brief ──▶ resource usage
|
|
155
|
+
└─────┬───────┘
|
|
156
|
+
▼
|
|
157
|
+
┌─────────────┐ SPEND (every payment screened first)
|
|
158
|
+
│ GUARDRAILS │ ── NemoClaw policy: allowlist · caps · reserve · ROI
|
|
159
|
+
│ → STRIPE │ ── Issuing virtual card (test) or simulated spend ──▶ − expense
|
|
160
|
+
└─────┬───────┘
|
|
161
|
+
▼
|
|
162
|
+
BOOK P&L ──▶ treasury updated · dashboard refreshed
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Revenue is **always collected before cost is incurred**, and no payment can violate policy. The business is safe by construction and profitable by rule.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 🏗️ Architecture
|
|
170
|
+
|
|
171
|
+
| Layer | Technology | File |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| **Analyst / reasoning** | NVIDIA Nemotron (Llama-3.1-Nemotron-Ultra) | `solvent/nemotron.py` |
|
|
174
|
+
| **Spend safety** | NVIDIA NemoClaw-style policy sandbox | `solvent/guardrails.py` |
|
|
175
|
+
| **Earn** | Stripe Payment Links + Checkout Session polling | `solvent/stripe_client.py` |
|
|
176
|
+
| **Spend** | Stripe Issuing virtual cards (test mode) | `solvent/stripe_client.py` |
|
|
177
|
+
| **Orchestration** | Hermes / Nous tool-calling agent loop | `solvent/agent.py` |
|
|
178
|
+
| **Memory** | SQLite treasury + pricing ledger | `solvent/treasury.py` · `solvent/pricing.py` |
|
|
179
|
+
|
|
180
|
+
**Key design choices:**
|
|
181
|
+
|
|
182
|
+
- **Structural profitability** — `pricing.py` computes unit cost before quoting. If margin < floor, the job never reaches Stripe.
|
|
183
|
+
- **Spend policy** — `guardrails.py` enforces vendor allowlist, per-transaction cap, rolling 24h budget, minimum cash reserve, and no-negative-ROI rule.
|
|
184
|
+
- **Offline-first** — without API keys the demo runs on deterministic stubs. Add `NVIDIA_API_KEY` + `STRIPE_API_KEY=sk_test_...` to unlock live inference and real Payment Links.
|
|
185
|
+
- **Audit trail** — every `cs_...` checkout session ID and `pi_...` PaymentIntent ID is recorded on the ledger before fulfilment begins.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 🎮 Running Modes
|
|
190
|
+
|
|
191
|
+
### Batch demo (default — best for judges)
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
python3 run_demo.py
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
4 pre-loaded jobs. ~30 seconds. Shows margin gating, Stripe earn/spend, Nemotron fulfillment, and guardrails in action.
|
|
198
|
+
|
|
199
|
+
### Interactive — your own jobs
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
python3 run_demo.py --interactive
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Type a research topic and client budget at the prompt. The agent quotes, pays, fulfils, and books P&L for each one in real time. Keep going until you quit.
|
|
206
|
+
|
|
207
|
+
### Add funds mid-session
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
python3 run_demo.py --seed 500 # start with $500 instead of $100
|
|
211
|
+
python3 run_demo.py --keep-balance # resume existing treasury balance
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
In interactive mode, type `/fund 200` at the prompt to deposit $200 into the live treasury without restarting.
|
|
215
|
+
|
|
216
|
+
### Programmatic
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from solvent.agent import Solvent
|
|
220
|
+
from solvent.jobs import SAMPLE_JOBS
|
|
221
|
+
|
|
222
|
+
agent = Solvent(seed_cents=10_000) # reset treasury, seed $100
|
|
223
|
+
agent.handle_job(SAMPLE_JOBS[0]) # process one job
|
|
224
|
+
snap = agent.run(SAMPLE_JOBS[1:]) # process a list; returns snapshot
|
|
225
|
+
|
|
226
|
+
print(snap["balance_cents"], snap["margin_pct"])
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Production mode (webhooks + async worker)
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
pip install -e ".[serve]"
|
|
233
|
+
export SOLVENT_DASHBOARD_TOKEN=$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')
|
|
234
|
+
|
|
235
|
+
python3 -m solvent serve --port 8787 # webhooks + job API + hosted briefs
|
|
236
|
+
python3 -m solvent worker # resume incomplete jobs, process queue
|
|
237
|
+
|
|
238
|
+
# Interactive voice dashboard (chat + live SSE updates):
|
|
239
|
+
open "http://127.0.0.1:8787/?token=$SOLVENT_DASHBOARD_TOKEN"
|
|
240
|
+
|
|
241
|
+
# Or dev convenience:
|
|
242
|
+
python3 run_demo.py --serve --no-onboard
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The hosted dashboard at `/` includes a **chat panel** (type or use the mic with Web Speech API) and **live treasury updates** via Server-Sent Events (`/api/events`). Dashboard/control routes require `SOLVENT_DASHBOARD_TOKEN` via `?token=...` or the `X-Solvent-Dashboard-Token` header before they expose status data or route chat through the Nemotron agent loop.
|
|
246
|
+
|
|
247
|
+
See [docs/PRODUCTION.md](docs/PRODUCTION.md) for Stripe webhook setup, SMTP delivery, and reconciliation.
|
|
248
|
+
|
|
249
|
+
### Operations
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
python3 -m solvent reconcile --since 7d # Stripe ↔ ledger drift check
|
|
253
|
+
python3 -m solvent finance # income statement, unit economics, runway
|
|
254
|
+
python3 -m solvent finance --json # machine-readable report
|
|
255
|
+
python3 -m solvent finance --reserve 50 # runway to a $50 cash-reserve floor
|
|
256
|
+
python3 -m solvent finance --period week # net P&L trend by day | week | month
|
|
257
|
+
python3 -m solvent finance --horizon 60 # forecast the balance 60 days out
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`finance` (alias `report`) turns the treasury ledger into the numbers a
|
|
261
|
+
business steers by: revenue/cost/net-margin, average profit per job, a cash
|
|
262
|
+
**runway** — days of burn remaining, or `cash-flow positive` once the agent
|
|
263
|
+
funds itself — a **net-P&L trend** bucketed by day/week/month, and a
|
|
264
|
+
**balance forecast** (central projection with a best/worst band whose width
|
|
265
|
+
grows with daily volatility). The income statement, runway, trend, and
|
|
266
|
+
forecast also render as a **Financial Statement** panel in the HTML dashboard.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 🔑 Make It Real
|
|
271
|
+
|
|
272
|
+
To use live Nemotron inference and real Stripe test-mode payment links:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pip install -e ".[stripe]"
|
|
276
|
+
|
|
277
|
+
export NVIDIA_API_KEY=nvapi-... # from build.nvidia.com
|
|
278
|
+
export STRIPE_API_KEY=sk_test_... # Stripe test mode only (live keys refused)
|
|
279
|
+
|
|
280
|
+
python3 run_demo.py
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
With both keys set:
|
|
284
|
+
|
|
285
|
+
- Briefs are written by **NVIDIA Nemotron** (Llama-3.1-Nemotron-Ultra).
|
|
286
|
+
- Each job creates a real **Stripe Payment Link**. Pay with test card `4242 4242 4242 4242`.
|
|
287
|
+
- SOLVENT **polls** the Checkout Session (`cs_...`) until `payment_status == paid` before fulfilling — no instant confirm.
|
|
288
|
+
- Optional: set `STRIPE_WEBHOOK_SECRET` and forward `checkout.session.completed` events via `StripeClient.process_webhook()`.
|
|
289
|
+
- Optional: enable **Stripe Issuing** on your test account to provision capped single-use virtual debit cards for each vendor payment.
|
|
290
|
+
|
|
291
|
+
### Environment variables
|
|
292
|
+
|
|
293
|
+
| Variable | Purpose |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `SOLVENT_HOME` | Where runtime data (treasury DB, reports, dashboard, logs) is stored. Defaults to the repo when run from a checkout, else `~/.solvent` |
|
|
296
|
+
| `NVIDIA_API_KEY` | Live Nemotron inference (`nvapi-...`) |
|
|
297
|
+
| `STRIPE_API_KEY` | Stripe test key (`sk_test_...`) |
|
|
298
|
+
| `STRIPE_WEBHOOK_SECRET` | Optional webhook verification |
|
|
299
|
+
| `STRIPE_PAYMENT_POLL_TIMEOUT` | Seconds to wait for payment (default `120`) |
|
|
300
|
+
| `STRIPE_PAYMENT_POLL_INTERVAL` | Poll interval in seconds (default `2`) |
|
|
301
|
+
| `SOLVENT_FORCE_STRIPE_SIMULATE` | Force offline simulate mode even with a key |
|
|
302
|
+
| `SOLVENT_DASHBOARD_TOKEN` | Shared secret required for hosted dashboard/control routes |
|
|
303
|
+
| `TELEGRAM_BOT_TOKEN` | Telegram bot token from BotFather |
|
|
304
|
+
| `SOLVENT_TELEGRAM_DM_POLICY` | `pairing` · `allowlist` · `open` (default `pairing`) |
|
|
305
|
+
| `SOLVENT_TELEGRAM_ALLOW_FROM` | Comma-separated Telegram user IDs for allowlist mode |
|
|
306
|
+
| `SOLVENT_PORT` | Port for the `serve` API server (default `8787`) |
|
|
307
|
+
| `SOLVENT_BASE_URL` | Base URL for hosted brief links and Stripe webhook callbacks |
|
|
308
|
+
| `NEMOTRON_MODEL` | Nemotron model override (default: `nvidia/llama-3.1-nemotron-ultra-253b-v1`) |
|
|
309
|
+
| `SOLVENT_DELIVERY_SECRET` | HMAC token secret for `/briefs/{job_id}`; at least 32 characters, high entropy |
|
|
310
|
+
| `SOLVENT_SKIP_ONBOARD` | Set to `1` to skip the first-run wizard |
|
|
311
|
+
| `SOLVENT_ALLOW_POLL` | When set to `1`/`true`/`yes`, actively poll Stripe Checkout Sessions for payment status instead of awaiting webhook confirmation (default: off) |
|
|
312
|
+
| `SOLVENT_ASYNC` | Run job fulfillment asynchronously instead of blocking on payment polling (default: off / synchronous) |
|
|
313
|
+
| `SOLVENT_LIVE_SEARCH` | Enable live web search integration in the agent chat loop (default: off) |
|
|
314
|
+
| `SOLVENT_LOG_JSON` | Emit structured JSON log lines to stderr in addition to the log file (default: off) |
|
|
315
|
+
| `SOLVENT_UPDATE_CHECK` | Opt-in: run a background version-update hint on CLI startup when set to `1`/`true`/`yes` |
|
|
316
|
+
| `SOLVENT_NO_UPDATE_CHECK` | Set to any value to suppress the background version-update hint |
|
|
317
|
+
| `SOLVENT_WORKSPACE` | Override path for the agent workspace directory (SOUL/BRAIN/AGENTS files) |
|
|
318
|
+
| `SOLVENT_WORKSPACE_MAX_CHARS` | Max characters loaded per workspace context file (default `8000`) |
|
|
319
|
+
| `SOLVENT_WORKSPACE_TOTAL_MAX_CHARS` | Max total characters across all workspace context files (default `40000`) |
|
|
320
|
+
| `SMTP_HOST` | SMTP server hostname. When empty (default), brief delivery is **simulated** — research briefs are written to the outbox directory instead of emailed. When set, briefs are emailed to the customer |
|
|
321
|
+
| `SMTP_PORT` | SMTP server port (default `587`) |
|
|
322
|
+
| `SMTP_USER` | SMTP authentication username |
|
|
323
|
+
| `SMTP_PASS` | SMTP authentication password |
|
|
324
|
+
| `SMTP_FROM` | "From" address for outgoing brief emails (default: `SMTP_USER`, else `agent@solvent.local`) |
|
|
325
|
+
|
|
326
|
+
Product/Price objects are cached in `.solvent/stripe_catalog.json` so repeated runs reuse a single **SOLVENT Research Brief** product instead of cluttering your Stripe dashboard.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 💬 Telegram (conversational channel)
|
|
331
|
+
|
|
332
|
+
Full chat on Telegram with OpenClaw-style pairing and Hermes-style tool/memory patterns. See **[docs/TELEGRAM.md](docs/TELEGRAM.md)**.
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
pip install -e ".[telegram]"
|
|
336
|
+
export TELEGRAM_BOT_TOKEN=...
|
|
337
|
+
|
|
338
|
+
python -m solvent serve & # Stripe webhooks + checkout
|
|
339
|
+
python -m solvent worker & # fulfill jobs
|
|
340
|
+
python -m solvent telegram # long-poll bot
|
|
341
|
+
|
|
342
|
+
python -m solvent doctor # diagnostics
|
|
343
|
+
python -m solvent pairing list # pending DM codes
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Users pair via `/start`, commission briefs in natural language, receive checkout links, and get push updates when jobs are paid and delivered.
|
|
347
|
+
|
|
348
|
+
Personality and operating rules come from the **agent workspace** (`SOUL.md`, `BRAIN.md`, `AGENTS.md`) — see **[docs/WORKSPACE.md](docs/WORKSPACE.md)**.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## 🧪 Tests
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
pip install -e ".[dev]"
|
|
356
|
+
python3 -m pytest tests/ -v
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Unit tests cover: pricing & margin gate · guardrail policy · treasury ledger · Stripe client (simulate + test mode) · config/onboarding.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 📁 Repository Layout
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
solvent/
|
|
367
|
+
agent.py the orchestrator (earn → fulfil → spend → book)
|
|
368
|
+
stages.py idempotent stage machine (quote→paid→fulfill→deliver→spend)
|
|
369
|
+
treasury.py SQLite ledger / balance sheet
|
|
370
|
+
pricing.py the margin gate
|
|
371
|
+
guardrails.py NemoClaw-style spend policy
|
|
372
|
+
stripe_client.py two-sided Stripe layer (earn + spend)
|
|
373
|
+
nemotron.py NVIDIA Nemotron client (+ offline stub)
|
|
374
|
+
service.py the product: an on-demand research brief
|
|
375
|
+
jobs.py sample inbound work
|
|
376
|
+
dashboard.py renders the treasury to HTML + JSON
|
|
377
|
+
finance.py income statement · unit economics · runway · forecast
|
|
378
|
+
config.py onboarding wizard and config persistence
|
|
379
|
+
server.py FastAPI webhooks + job API + hosted briefs (serve)
|
|
380
|
+
worker.py async job processor + resume incomplete jobs
|
|
381
|
+
gateway.py channel router (Telegram → chat sessions)
|
|
382
|
+
chat.py conversational loop + business tools
|
|
383
|
+
memory.py Hermes-style session memory
|
|
384
|
+
doctor.py stack diagnostics
|
|
385
|
+
workspace.py SOUL/BRAIN/AGENTS prompt assembly
|
|
386
|
+
channels/ Telegram long-poll adapter
|
|
387
|
+
run_demo.py the full business loop (CLI entry point)
|
|
388
|
+
tests/ pytest suite
|
|
389
|
+
docs/ screenshots and supporting docs
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## 🏆 Built For
|
|
395
|
+
|
|
396
|
+
**Hermes Agent Accelerated Business Hackathon** — NVIDIA × Stripe × Nous Research
|
|
397
|
+
|
|
398
|
+
The agent was designed to demonstrate:
|
|
399
|
+
|
|
400
|
+
- An agent that is **economically self-aware** — it has a treasury, prices against its own costs, and gates every action on projected profit
|
|
401
|
+
- A **complete two-sided Stripe integration** — earns via Payment Links, spends via Issuing virtual cards
|
|
402
|
+
- **Provable spend safety** — a NemoClaw-style policy sandbox that makes "give an agent a payment credential" a reasonable thing to do
|
|
403
|
+
- **Live inference with NVIDIA Nemotron** — the offline stub means the demo always works, even without API keys
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 🤝 Contributing
|
|
408
|
+
|
|
409
|
+
Issues, PRs, and ideas are very welcome. Some good starting points:
|
|
410
|
+
|
|
411
|
+
- Add more sample research topics in `solvent/jobs.py`
|
|
412
|
+
- Improve the Nemotron prompt template in `solvent/service.py`
|
|
413
|
+
- Add a new guardrail policy to `solvent/guardrails.py`
|
|
414
|
+
- Extend the dashboard with charts or new metrics in `solvent/dashboard.py`
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
<div align="center">
|
|
419
|
+
|
|
420
|
+
**If SOLVENT gave you ideas, give it a ⭐**
|
|
421
|
+
|
|
422
|
+
</div>
|