dexcost 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.
- dexcost-0.1.0/.gitignore +68 -0
- dexcost-0.1.0/CHANGELOG.md +96 -0
- dexcost-0.1.0/LICENSE +21 -0
- dexcost-0.1.0/Makefile +21 -0
- dexcost-0.1.0/PKG-INFO +250 -0
- dexcost-0.1.0/README.md +214 -0
- dexcost-0.1.0/examples/agent_cost.py +130 -0
- dexcost-0.1.0/examples/customer_attribution.py +74 -0
- dexcost-0.1.0/examples/quickstart/__main__.py +52 -0
- dexcost-0.1.0/examples/quickstart.py +40 -0
- dexcost-0.1.0/examples/waste_detection.py +81 -0
- dexcost-0.1.0/fixtures/batch_payload.v1.json +68 -0
- dexcost-0.1.0/fixtures/event_external_cost.v1.json +26 -0
- dexcost-0.1.0/fixtures/event_late.v1.json +24 -0
- dexcost-0.1.0/fixtures/event_llm_call.v1.json +26 -0
- dexcost-0.1.0/fixtures/ingest_request.v1.json +73 -0
- dexcost-0.1.0/fixtures/ingest_response.v1.json +5 -0
- dexcost-0.1.0/fixtures/task.v1.json +30 -0
- dexcost-0.1.0/pyproject.toml +179 -0
- dexcost-0.1.0/schemas/README.md +49 -0
- dexcost-0.1.0/schemas/dexcost-event.v1.json +111 -0
- dexcost-0.1.0/schemas/dexcost-task.v1.json +160 -0
- dexcost-0.1.0/src/dexcost/__init__.py +537 -0
- dexcost-0.1.0/src/dexcost/adapters/__init__.py +18 -0
- dexcost-0.1.0/src/dexcost/adapters/_netbytes.py +53 -0
- dexcost-0.1.0/src/dexcost/adapters/aws_lambda.py +122 -0
- dexcost-0.1.0/src/dexcost/adapters/browser.py +171 -0
- dexcost-0.1.0/src/dexcost/adapters/data/aws_lambda_pricing.json +61 -0
- dexcost-0.1.0/src/dexcost/adapters/http.py +810 -0
- dexcost-0.1.0/src/dexcost/auto_task.py +74 -0
- dexcost-0.1.0/src/dexcost/cgroup_reader.py +121 -0
- dexcost-0.1.0/src/dexcost/cgroup_walker.py +184 -0
- dexcost-0.1.0/src/dexcost/cli.py +222 -0
- dexcost-0.1.0/src/dexcost/clients.py +270 -0
- dexcost-0.1.0/src/dexcost/cloud_detect.py +573 -0
- dexcost-0.1.0/src/dexcost/compute_accountant.py +220 -0
- dexcost-0.1.0/src/dexcost/compute_pricing.py +624 -0
- dexcost-0.1.0/src/dexcost/compute_runtime.py +79 -0
- dexcost-0.1.0/src/dexcost/compute_wrap.py +209 -0
- dexcost-0.1.0/src/dexcost/config.py +111 -0
- dexcost-0.1.0/src/dexcost/context.py +202 -0
- dexcost-0.1.0/src/dexcost/data/compute_prices.json +180 -0
- dexcost-0.1.0/src/dexcost/data/egress_prices.json +418 -0
- dexcost-0.1.0/src/dexcost/data/gpu_prices.json +412 -0
- dexcost-0.1.0/src/dexcost/data/model_cost_map.json +37665 -0
- dexcost-0.1.0/src/dexcost/data/service_prices.json +2595 -0
- dexcost-0.1.0/src/dexcost/dev_console.py +99 -0
- dexcost-0.1.0/src/dexcost/egress_pricing.py +185 -0
- dexcost-0.1.0/src/dexcost/fargate_metadata.py +110 -0
- dexcost-0.1.0/src/dexcost/gpu_accountant.py +470 -0
- dexcost-0.1.0/src/dexcost/gpu_pricing.py +506 -0
- dexcost-0.1.0/src/dexcost/gpu_runtime.py +152 -0
- dexcost-0.1.0/src/dexcost/gpu_wrap.py +144 -0
- dexcost-0.1.0/src/dexcost/heuristics.py +168 -0
- dexcost-0.1.0/src/dexcost/instruments/__init__.py +30 -0
- dexcost-0.1.0/src/dexcost/instruments/anthropic.py +566 -0
- dexcost-0.1.0/src/dexcost/instruments/bedrock.py +579 -0
- dexcost-0.1.0/src/dexcost/instruments/cohere.py +544 -0
- dexcost-0.1.0/src/dexcost/instruments/gemini.py +430 -0
- dexcost-0.1.0/src/dexcost/instruments/litellm.py +594 -0
- dexcost-0.1.0/src/dexcost/instruments/mcp.py +608 -0
- dexcost-0.1.0/src/dexcost/instruments/openai.py +505 -0
- dexcost-0.1.0/src/dexcost/integrations/__init__.py +15 -0
- dexcost-0.1.0/src/dexcost/integrations/langchain.py +252 -0
- dexcost-0.1.0/src/dexcost/integrations/traces.py +56 -0
- dexcost-0.1.0/src/dexcost/models/__init__.py +23 -0
- dexcost-0.1.0/src/dexcost/models/_serde.py +43 -0
- dexcost-0.1.0/src/dexcost/models/enums.py +50 -0
- dexcost-0.1.0/src/dexcost/models/event.py +117 -0
- dexcost-0.1.0/src/dexcost/models/task.py +173 -0
- dexcost-0.1.0/src/dexcost/network_accountant.py +159 -0
- dexcost-0.1.0/src/dexcost/nvml_reader.py +315 -0
- dexcost-0.1.0/src/dexcost/pricing.py +389 -0
- dexcost-0.1.0/src/dexcost/py.typed +0 -0
- dexcost-0.1.0/src/dexcost/rates.py +146 -0
- dexcost-0.1.0/src/dexcost/redaction.py +135 -0
- dexcost-0.1.0/src/dexcost/scanner.py +607 -0
- dexcost-0.1.0/src/dexcost/schema.py +55 -0
- dexcost-0.1.0/src/dexcost/service_catalog.py +421 -0
- dexcost-0.1.0/src/dexcost/session.py +149 -0
- dexcost-0.1.0/src/dexcost/storage/__init__.py +14 -0
- dexcost-0.1.0/src/dexcost/storage/migrations.py +280 -0
- dexcost-0.1.0/src/dexcost/storage/protocol.py +109 -0
- dexcost-0.1.0/src/dexcost/storage/sqlite.py +694 -0
- dexcost-0.1.0/src/dexcost/sync.py +385 -0
- dexcost-0.1.0/src/dexcost/tracker.py +1406 -0
- dexcost-0.1.0/tests/__init__.py +0 -0
- dexcost-0.1.0/tests/conftest.py +17 -0
- dexcost-0.1.0/tests/test_anthropic_instrument.py +1003 -0
- dexcost-0.1.0/tests/test_auto_instrument.py +637 -0
- dexcost-0.1.0/tests/test_auto_task.py +144 -0
- dexcost-0.1.0/tests/test_batch_splitting.py +208 -0
- dexcost-0.1.0/tests/test_bedrock_instrument.py +645 -0
- dexcost-0.1.0/tests/test_browser_adapter.py +264 -0
- dexcost-0.1.0/tests/test_cgroup_reader.py +114 -0
- dexcost-0.1.0/tests/test_cgroup_walker.py +164 -0
- dexcost-0.1.0/tests/test_cli.py +225 -0
- dexcost-0.1.0/tests/test_clients.py +229 -0
- dexcost-0.1.0/tests/test_cloud_detect.py +583 -0
- dexcost-0.1.0/tests/test_cloud_detect_instance_type.py +158 -0
- dexcost-0.1.0/tests/test_cohere_instrument.py +625 -0
- dexcost-0.1.0/tests/test_compat_smoke.py +698 -0
- dexcost-0.1.0/tests/test_compute_accountant.py +181 -0
- dexcost-0.1.0/tests/test_compute_auto_emission_long_running.py +101 -0
- dexcost-0.1.0/tests/test_compute_catalog_integrity.py +181 -0
- dexcost-0.1.0/tests/test_compute_cross_runtime_matrix.py +182 -0
- dexcost-0.1.0/tests/test_compute_idle_gap.py +132 -0
- dexcost-0.1.0/tests/test_compute_invariants.py +130 -0
- dexcost-0.1.0/tests/test_compute_math_fixes.py +114 -0
- dexcost-0.1.0/tests/test_compute_pricing.py +313 -0
- dexcost-0.1.0/tests/test_compute_runtime.py +144 -0
- dexcost-0.1.0/tests/test_compute_wrap.py +150 -0
- dexcost-0.1.0/tests/test_config.py +99 -0
- dexcost-0.1.0/tests/test_context.py +349 -0
- dexcost-0.1.0/tests/test_cross_sdk_parity.py +316 -0
- dexcost-0.1.0/tests/test_e2e_local.py +292 -0
- dexcost-0.1.0/tests/test_egress_catalog_integrity.py +69 -0
- dexcost-0.1.0/tests/test_egress_pricing.py +112 -0
- dexcost-0.1.0/tests/test_endpoint_allowlist.py +50 -0
- dexcost-0.1.0/tests/test_error_handling.py +126 -0
- dexcost-0.1.0/tests/test_examples.py +94 -0
- dexcost-0.1.0/tests/test_fargate_metadata.py +139 -0
- dexcost-0.1.0/tests/test_gemini_instrument.py +536 -0
- dexcost-0.1.0/tests/test_gpu_accountant.py +386 -0
- dexcost-0.1.0/tests/test_gpu_auto_emission_and_back_fill.py +183 -0
- dexcost-0.1.0/tests/test_gpu_catalog_integrity.py +274 -0
- dexcost-0.1.0/tests/test_gpu_catalog_sync_consistency.py +55 -0
- dexcost-0.1.0/tests/test_gpu_cross_billing_model_matrix.py +152 -0
- dexcost-0.1.0/tests/test_gpu_idle_gap.py +118 -0
- dexcost-0.1.0/tests/test_gpu_invariants.py +150 -0
- dexcost-0.1.0/tests/test_gpu_pricing.py +289 -0
- dexcost-0.1.0/tests/test_gpu_runtime.py +213 -0
- dexcost-0.1.0/tests/test_gpu_sm_time_integration.py +187 -0
- dexcost-0.1.0/tests/test_gpu_utilization_signal_observability.py +157 -0
- dexcost-0.1.0/tests/test_gpu_wrap.py +195 -0
- dexcost-0.1.0/tests/test_http_adapter.py +293 -0
- dexcost-0.1.0/tests/test_http_adapter_v2.py +364 -0
- dexcost-0.1.0/tests/test_http_external_byte_attribution.py +148 -0
- dexcost-0.1.0/tests/test_init_cloud_detection_wiring.py +41 -0
- dexcost-0.1.0/tests/test_init_idempotent_and_fork.py +106 -0
- dexcost-0.1.0/tests/test_lambda_adapter.py +99 -0
- dexcost-0.1.0/tests/test_langchain_integration.py +240 -0
- dexcost-0.1.0/tests/test_litellm_instrument.py +941 -0
- dexcost-0.1.0/tests/test_mcp_instrument.py +365 -0
- dexcost-0.1.0/tests/test_migrations.py +697 -0
- dexcost-0.1.0/tests/test_models.py +351 -0
- dexcost-0.1.0/tests/test_netbytes.py +56 -0
- dexcost-0.1.0/tests/test_network_accountant.py +135 -0
- dexcost-0.1.0/tests/test_network_accountant_external.py +68 -0
- dexcost-0.1.0/tests/test_network_capture.py +277 -0
- dexcost-0.1.0/tests/test_network_config.py +22 -0
- dexcost-0.1.0/tests/test_network_cost_dual_invoice.py +86 -0
- dexcost-0.1.0/tests/test_network_cost_finalize.py +132 -0
- dexcost-0.1.0/tests/test_network_cost_invariants.py +66 -0
- dexcost-0.1.0/tests/test_network_cost_migration.py +142 -0
- dexcost-0.1.0/tests/test_network_finalize.py +96 -0
- dexcost-0.1.0/tests/test_network_init_wiring.py +38 -0
- dexcost-0.1.0/tests/test_network_llm_suppression.py +21 -0
- dexcost-0.1.0/tests/test_network_migration.py +101 -0
- dexcost-0.1.0/tests/test_network_suppression.py +54 -0
- dexcost-0.1.0/tests/test_new_api_smoke.py +148 -0
- dexcost-0.1.0/tests/test_new_context.py +128 -0
- dexcost-0.1.0/tests/test_non_llm_costs.py +426 -0
- dexcost-0.1.0/tests/test_nvml_reader.py +197 -0
- dexcost-0.1.0/tests/test_openai_instrument.py +737 -0
- dexcost-0.1.0/tests/test_pricing.py +613 -0
- dexcost-0.1.0/tests/test_pricing_refresh.py +96 -0
- dexcost-0.1.0/tests/test_public_api_surface.py +101 -0
- dexcost-0.1.0/tests/test_rates.py +521 -0
- dexcost-0.1.0/tests/test_recorded_events_cap.py +51 -0
- dexcost-0.1.0/tests/test_redaction.py +166 -0
- dexcost-0.1.0/tests/test_retry_detection.py +779 -0
- dexcost-0.1.0/tests/test_retry_heuristics.py +488 -0
- dexcost-0.1.0/tests/test_scanner.py +544 -0
- dexcost-0.1.0/tests/test_schema.py +271 -0
- dexcost-0.1.0/tests/test_service_catalog.py +382 -0
- dexcost-0.1.0/tests/test_session_grouping.py +213 -0
- dexcost-0.1.0/tests/test_set_api_key.py +84 -0
- dexcost-0.1.0/tests/test_sqlite_storage.py +396 -0
- dexcost-0.1.0/tests/test_streaming_response_not_drained.py +92 -0
- dexcost-0.1.0/tests/test_sync.py +851 -0
- dexcost-0.1.0/tests/test_task_gpu_cost_field.py +119 -0
- dexcost-0.1.0/tests/test_task_network_cost_field.py +29 -0
- dexcost-0.1.0/tests/test_task_network_fields.py +38 -0
- dexcost-0.1.0/tests/test_trace_linking.py +126 -0
- dexcost-0.1.0/tests/test_tracker.py +1074 -0
- dexcost-0.1.0/tests/test_version.py +16 -0
- dexcost-0.1.0/uv.lock +2614 -0
dexcost-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# ── Rust ─────────────────────────────────────────────
|
|
2
|
+
rust/target/
|
|
3
|
+
**/*.rs.bk
|
|
4
|
+
# Cargo.lock IS committed (binary + reproducible builds) — not ignored.
|
|
5
|
+
|
|
6
|
+
# ── Node / TypeScript ────────────────────────────────
|
|
7
|
+
node_modules/
|
|
8
|
+
typescript/dist/
|
|
9
|
+
*.tsbuildinfo
|
|
10
|
+
npm-debug.log*
|
|
11
|
+
yarn-debug.log*
|
|
12
|
+
yarn-error.log*
|
|
13
|
+
.npm/
|
|
14
|
+
# package-lock.json IS committed — not ignored.
|
|
15
|
+
|
|
16
|
+
# ── Python ───────────────────────────────────────────
|
|
17
|
+
__pycache__/
|
|
18
|
+
*.py[cod]
|
|
19
|
+
*$py.class
|
|
20
|
+
*.egg-info/
|
|
21
|
+
python/build/
|
|
22
|
+
python/dist/
|
|
23
|
+
.pytest_cache/
|
|
24
|
+
.mypy_cache/
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.tox/
|
|
29
|
+
.venv/
|
|
30
|
+
venv/
|
|
31
|
+
env/
|
|
32
|
+
|
|
33
|
+
# ── Go ───────────────────────────────────────────────
|
|
34
|
+
go/bin/
|
|
35
|
+
*.exe
|
|
36
|
+
*.test
|
|
37
|
+
coverage.out
|
|
38
|
+
*.cover
|
|
39
|
+
|
|
40
|
+
# ── dexcost runtime artifacts ────────────────────────
|
|
41
|
+
# SQLite event buffers — created at runtime, never source.
|
|
42
|
+
*.db
|
|
43
|
+
*.sqlite
|
|
44
|
+
*.sqlite3
|
|
45
|
+
.dexcost/
|
|
46
|
+
|
|
47
|
+
# ── Secrets / environment ────────────────────────────
|
|
48
|
+
.env
|
|
49
|
+
.env.*
|
|
50
|
+
!.env.example
|
|
51
|
+
|
|
52
|
+
# ── Editors / OS ─────────────────────────────────────
|
|
53
|
+
.idea/
|
|
54
|
+
.vscode/
|
|
55
|
+
*.swp
|
|
56
|
+
*~
|
|
57
|
+
.DS_Store
|
|
58
|
+
Thumbs.db
|
|
59
|
+
|
|
60
|
+
# ── Logs ─────────────────────────────────────────────
|
|
61
|
+
*.log
|
|
62
|
+
|
|
63
|
+
# ── Claude Code local workspace ──────────────────────
|
|
64
|
+
# Agent worktrees are ephemeral local checkouts created by the
|
|
65
|
+
# Agent tool with isolation="worktree". Each agent's commits live
|
|
66
|
+
# on its own auto-generated branch and get merged back from the
|
|
67
|
+
# main repo — the worktree dirs themselves are never tracked.
|
|
68
|
+
.claude/worktrees/
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to dexcost will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 (2026-05-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **cloud_detect:** broaden vendor coverage — GPU clouds, PaaS, more IaaS ([feb22fb](https://github.com/DexwoxBusiness/dexcost-sdk/commit/feb22fba4fe3e2665520bb921bcfb0bb83ee6cac))
|
|
11
|
+
* **cloud_detect:** cover ECS, Container Apps region, harden AWS heuristics ([1311fe2](https://github.com/DexwoxBusiness/dexcost-sdk/commit/1311fe21de8345f52f429ece019cc7d1173854ba))
|
|
12
|
+
* **compute:** auto-emit + back-fill compute_cost events at task finalize ([91beccc](https://github.com/DexwoxBusiness/dexcost-sdk/commit/91becccf2062ef6d50df9c48b7310577909e3338))
|
|
13
|
+
* **compute:** bundle compute price catalog (AWS/GCP/Azure/Vercel) ([dc4f419](https://github.com/DexwoxBusiness/dexcost-sdk/commit/dc4f41917b8a3935ecfbb6aee909959423aad440))
|
|
14
|
+
* **compute:** cgroup v2 file readers (cpu.stat, cpu.max, memory.{peak,max,current}) ([1609faf](https://github.com/DexwoxBusiness/dexcost-sdk/commit/1609faf1a35b64628ab31bc90d0d437bc01d223e))
|
|
15
|
+
* **compute:** extend CloudEnv with instance_type from IMDS (Decision [#3](https://github.com/DexwoxBusiness/dexcost-sdk/issues/3)) ([a613924](https://github.com/DexwoxBusiness/dexcost-sdk/commit/a613924f5b58e1bd3a4049f0669284d58ef4ff12))
|
|
16
|
+
* **compute:** Fargate ECS task metadata helper (MiB->bytes per Decision [#7](https://github.com/DexwoxBusiness/dexcost-sdk/issues/7)) ([08f2b22](https://github.com/DexwoxBusiness/dexcost-sdk/commit/08f2b22ce645b349d693b9855708cbe55cffc667))
|
|
17
|
+
* **compute:** per-task accountant — cgroup start/end snapshots, single event ([33cef0f](https://github.com/DexwoxBusiness/dexcost-sdk/commit/33cef0f1386b3a72a73da0b76191c8cab474b0e8))
|
|
18
|
+
* **compute:** pricing engine — per-billing-model math + degradation ladder ([e379f40](https://github.com/DexwoxBusiness/dexcost-sdk/commit/e379f40342e33cedba4bcd46f7e0982ce0bc32ef))
|
|
19
|
+
* **compute:** runtime resolver — serverless env vars > k8s > cloud_detect IaaS ([afbc007](https://github.com/DexwoxBusiness/dexcost-sdk/commit/afbc007a5bd77b3b19dd5f50076b02cc9c1ff48d))
|
|
20
|
+
* **compute:** serverless handler wraps + init knobs ([3babf79](https://github.com/DexwoxBusiness/dexcost-sdk/commit/3babf798f0b026a5524c91ed6dc7b07793b76439))
|
|
21
|
+
* **gpu:** auto-emit dual events + back-fill cost at task finalize ([56d8d43](https://github.com/DexwoxBusiness/dexcost-sdk/commit/56d8d43bf458b2f2acc6abcf06a096c331fa1754))
|
|
22
|
+
* **gpu:** bundle initial gpu_prices.json across four SDKs from live 2026 sources ([79c8745](https://github.com/DexwoxBusiness/dexcost-sdk/commit/79c8745026f92740c5f83d7171080ce98cf81c30))
|
|
23
|
+
* **gpu:** cgroup-scope classifier — Decision [#1](https://github.com/DexwoxBusiness/dexcost-sdk/issues/1) verification-gate impl ([caebcf7](https://github.com/DexwoxBusiness/dexcost-sdk/commit/caebcf7280b9fd3cc3718673d2573b92d2fe990c))
|
|
24
|
+
* **gpu:** EventType.{GPU_COST,GPU_UTILIZATION_SIGNAL} + Task.gpu_cost_usd + v5→v6 migration ([2785158](https://github.com/DexwoxBusiness/dexcost-sdk/commit/278515848606df368f0924c4072557b90ca70f3a))
|
|
25
|
+
* **gpu:** NVML library wrapper — fail-silent + NFC-normalized productName ([b5424ea](https://github.com/DexwoxBusiness/dexcost-sdk/commit/b5424ea0563de78dd773842049084996071bf690))
|
|
26
|
+
* **gpu:** per-task accountant — cgroup walk + NVML snapshot pair + dual emission ([0d47371](https://github.com/DexwoxBusiness/dexcost-sdk/commit/0d47371eac087ed29d3ef81bfb4ac9ce878ccedd))
|
|
27
|
+
* **gpu:** pricing engine — 4 billing models + 5-tier ladder + device-class fallback ([a47c58a](https://github.com/DexwoxBusiness/dexcost-sdk/commit/a47c58adceb1c5146ac74d4f1e297598a22bf43b))
|
|
28
|
+
* **gpu:** runtime cascade — serverless env > IaaS GPU family > NVML presence ([9bcb0c9](https://github.com/DexwoxBusiness/dexcost-sdk/commit/9bcb0c961201ad3e8c30812df18379f6a7d88152))
|
|
29
|
+
* **gpu:** serverless handler wraps (Modal / RunPod / Replicate) + Task._gpu ([fc0860a](https://github.com/DexwoxBusiness/dexcost-sdk/commit/fc0860a3c5eb35a5083548d283eea524dcba63d3))
|
|
30
|
+
* implement compute, network, and GPU cost capture & attribution ([f56f42d](https://github.com/DexwoxBusiness/dexcost-sdk/commit/f56f42d49043eea2569ea062bf2fada5cc4d1f06))
|
|
31
|
+
* **network-cost-v2:** add Task.network_cost_usd field ([e9c8f8e](https://github.com/DexwoxBusiness/dexcost-sdk/commit/e9c8f8ec4013e5a971a3705635620c97be7ef523))
|
|
32
|
+
* **network-cost-v2:** bundle egress price catalog (AWS/GCP/Azure) ([42d00d4](https://github.com/DexwoxBusiness/dexcost-sdk/commit/42d00d4b91459330acc78f8e8e494148f212283d))
|
|
33
|
+
* **network-cost-v2:** egress rate resolver + degradation ladder ([cb7079c](https://github.com/DexwoxBusiness/dexcost-sdk/commit/cb7079c968ee6ed2cbca1ff45de457e9b0c944fd))
|
|
34
|
+
* **network-cost-v2:** finalize-time egress pricing on tasks + events ([420c4c1](https://github.com/DexwoxBusiness/dexcost-sdk/commit/420c4c10e22cbd316720c88d34c4f3742ed73b4d))
|
|
35
|
+
* **network-cost-v2:** forward is_internal into accountant + deferred-cost marker ([c652bc3](https://github.com/DexwoxBusiness/dexcost-sdk/commit/c652bc39cd0606908fae2ad05d8491c6d3950b71))
|
|
36
|
+
* **network-cost-v2:** launch cloud detection from init() ([b381dd4](https://github.com/DexwoxBusiness/dexcost-sdk/commit/b381dd4c9add89ee88a47576cc135cee3f8e499d))
|
|
37
|
+
* **network-cost-v2:** NetworkAccountant external-byte split ([80da35b](https://github.com/DexwoxBusiness/dexcost-sdk/commit/80da35b043ad5f6745575e17e26d222b7356165d))
|
|
38
|
+
* **network-cost-v2:** non-blocking cloud provider/region detection ([ca3574d](https://github.com/DexwoxBusiness/dexcost-sdk/commit/ca3574dcc519a1e7d3b77ccca53381a3be3fc199))
|
|
39
|
+
* **network-cost-v2:** persist network_cost_usd + v4->v5 migration ([1166e51](https://github.com/DexwoxBusiness/dexcost-sdk/commit/1166e513ab571cc7583f7ee7b905b5bfd6590694))
|
|
40
|
+
* **network:** add context-scoped network-event suppression flag ([316df6a](https://github.com/DexwoxBusiness/dexcost-sdk/commit/316df6a53f7e06b80351c852178537fc961e89e2))
|
|
41
|
+
* **network:** add destination classifier + byte measurement helpers ([45d7bbd](https://github.com/DexwoxBusiness/dexcost-sdk/commit/45d7bbd452d9cc28a500c7650c8b1183807f46e5))
|
|
42
|
+
* **network:** add network event type ([6cce486](https://github.com/DexwoxBusiness/dexcost-sdk/commit/6cce4864d2d376219bcb182e1993190cbcf2e817))
|
|
43
|
+
* **network:** add network fields to Task model ([b19da30](https://github.com/DexwoxBusiness/dexcost-sdk/commit/b19da30f6ce7de7150b659eeb0480cdd42eddc37))
|
|
44
|
+
* **network:** add network-capture config fields ([1486d11](https://github.com/DexwoxBusiness/dexcost-sdk/commit/1486d11fca86b57aa30b4cea3f9f95a8a020b65f))
|
|
45
|
+
* **network:** add NetworkAccountant accumulator ([7834120](https://github.com/DexwoxBusiness/dexcost-sdk/commit/7834120d8fc7089abf360ae32661ccd5b205f80a))
|
|
46
|
+
* **network:** attach accountant to Task, finalize at task end ([9533942](https://github.com/DexwoxBusiness/dexcost-sdk/commit/95339422af7bd2e938b1d7342d08fb3c2adc08ce))
|
|
47
|
+
* **network:** HTTP adapter byte accounting + re-typed un-cataloged calls ([e0bc666](https://github.com/DexwoxBusiness/dexcost-sdk/commit/e0bc666645762a454eb6b7e44903722741c932b7))
|
|
48
|
+
* **network:** LLM instruments suppress duplicate network events ([8438780](https://github.com/DexwoxBusiness/dexcost-sdk/commit/843878096a0a039a25fa0f66154341b403a3f667))
|
|
49
|
+
* **network:** persist network fields + v3->v4 migration ([fb0de71](https://github.com/DexwoxBusiness/dexcost-sdk/commit/fb0de71ce3dbfc939566bd245b028a92f8bea0f3))
|
|
50
|
+
* **network:** wire network-capture config through init() ([9089154](https://github.com/DexwoxBusiness/dexcost-sdk/commit/9089154302d49daaa6eb76c08edf2bff3097edc1))
|
|
51
|
+
* **security:** scrub_url across all 4 SDKs (Sprint 1 Theme A, part 1) ([07d1097](https://github.com/DexwoxBusiness/dexcost-sdk/commit/07d10977eebcd77b16e409f9781058e80a5a46ce))
|
|
52
|
+
* **security:** wire scrub_url into URL-capture call sites (Sprint 1 Theme A, part 2) ([56b4cf9](https://github.com/DexwoxBusiness/dexcost-sdk/commit/56b4cf9845c3ecb1a12ec07b75f69c5ee549a07d))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### Bug Fixes
|
|
56
|
+
|
|
57
|
+
* **all:** B14 — public set_api_key for auth-failure recovery across 4 SDKs (Sprint 2 Theme D / §3.2.3) ([bacfacd](https://github.com/DexwoxBusiness/dexcost-sdk/commit/bacfacd2140427bedc036c799d183bf8907794b2))
|
|
58
|
+
* **all:** P1 — canonical timestamp serialisation (Sprint 3 Theme F / §4.1.1) ([03064a7](https://github.com/DexwoxBusiness/dexcost-sdk/commit/03064a7bab0ae461fce2fb6f99842945b32d6e8a))
|
|
59
|
+
* **all:** P3/P4/P5 — parity reconciliation (Sprint 3 Theme F / §4.1.3) ([d82407f](https://github.com/DexwoxBusiness/dexcost-sdk/commit/d82407f8f7ba9b77355ea695f94f6a33342b0597))
|
|
60
|
+
* **cloud_detect:** correctness audit — DMI fields, GCP region, OCI region ([a2fa928](https://github.com/DexwoxBusiness/dexcost-sdk/commit/a2fa9283096a86954f746b3c2529fc5fca94c137))
|
|
61
|
+
* **network:** aiohttp/urllib3 status_code, thread-safe error counter, lint cleanup ([28ae48d](https://github.com/DexwoxBusiness/dexcost-sdk/commit/28ae48d6119ef26de23c2d64217675734d38cd05))
|
|
62
|
+
* **network:** dedupe _other bucket, clamp negative bytes, add accountant tests ([7aab6f4](https://github.com/DexwoxBusiness/dexcost-sdk/commit/7aab6f4d28d5891a40e803708246fa3581cf5720))
|
|
63
|
+
* **network:** honor track_network=False to disable byte capture and network events ([05d9cd4](https://github.com/DexwoxBusiness/dexcost-sdk/commit/05d9cd4344b6a8145ba9c27da797458ed7c0dca9))
|
|
64
|
+
* **network:** isolate init-wiring test instrumentation; document init() network params ([49a918e](https://github.com/DexwoxBusiness/dexcost-sdk/commit/49a918ee29d92336f6a6c46654c03a04c8e692fe))
|
|
65
|
+
* **network:** make _network non-init and copy-safe; cover failed-task finalize ([13c096d](https://github.com/DexwoxBusiness/dexcost-sdk/commit/13c096d2a8759c5744e1f7449c67396e64231a28))
|
|
66
|
+
* **python,rust:** Sprint 3 Theme F mediums — high-impact items (§4.3) ([c1d87a7](https://github.com/DexwoxBusiness/dexcost-sdk/commit/c1d87a70af21b624aa45e39e9a4f7fd3a2a4a713))
|
|
67
|
+
* **python:** B10 — init() idempotency + fork safety (Sprint 1 Theme B / §2.2.4) ([9bb5d35](https://github.com/DexwoxBusiness/dexcost-sdk/commit/9bb5d35fc93381bc0c43690f3d60a16e5fa09e9c))
|
|
68
|
+
* **python:** B11 — HTTP adapter skips body drain on streaming responses (Sprint 2 Theme C / §3.1.2) ([8a2f357](https://github.com/DexwoxBusiness/dexcost-sdk/commit/8a2f35728bbe257c679b4248ec59e11757ea8a16))
|
|
69
|
+
* **python:** B2 — GPU SM-time integration (Sprint 2 Theme C / §3.1.1) ([d37b6b5](https://github.com/DexwoxBusiness/dexcost-sdk/commit/d37b6b576bdf863348e3c4090638e68e2c3d7814))
|
|
70
|
+
* **python:** compute math — memory.peak per-task + vcpu reset confidence (Sprint 2 Theme C / §3.1.3 fixes 1+2) ([a72b8d2](https://github.com/DexwoxBusiness/dexcost-sdk/commit/a72b8d2b0439c1e12e6dee50ffeac7ded1d36012))
|
|
71
|
+
* **security:** A2 — DEXCOST_ENDPOINT https-only allow-list across all 4 SDKs (Sprint 1 Theme A / §2.1) ([64bd3dd](https://github.com/DexwoxBusiness/dexcost-sdk/commit/64bd3dd72bfde3ac475477765ecd22a09fa6f8f7))
|
|
72
|
+
* **storage:** re-mark sync_status='pending' on update_event ([ff96e94](https://github.com/DexwoxBusiness/dexcost-sdk/commit/ff96e94ee6885f48019f956a95ce4c0539a07f11))
|
|
73
|
+
* testpypi workflow and fixes ([7f28512](https://github.com/DexwoxBusiness/dexcost-sdk/commit/7f28512309abba3ba8d974c60b929746a365b24c))
|
|
74
|
+
* **typescript:** clear all 119 lint errors ([f4d9679](https://github.com/DexwoxBusiness/dexcost-sdk/commit/f4d967973a2ec3f69dd728c74e8acac88c1589ab))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
### Documentation
|
|
78
|
+
|
|
79
|
+
* **conventions:** Phase 2 GPU updates — §1 signal-event carve-out, §3 patterns, §8 primitive ([d7d48b6](https://github.com/DexwoxBusiness/dexcost-sdk/commit/d7d48b659c823403ac0e20569992a77b93a43764))
|
|
80
|
+
|
|
81
|
+
## [0.1.0] - 2026-02-25
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
- Task tracking: decorator, context manager, manual start/end (US-005--US-009)
|
|
85
|
+
- Auto-instrumentation for OpenAI, Anthropic, LiteLLM (US-012--US-014)
|
|
86
|
+
- Pricing engine with bundled model costs (US-010)
|
|
87
|
+
- Cost rates registry for non-LLM services (US-011)
|
|
88
|
+
- Retry detection and waste tracking (US-015)
|
|
89
|
+
- Standard Event Schema v1 with JSON Schema validation (US-002)
|
|
90
|
+
- SQLite storage with WAL mode and migrations (US-003)
|
|
91
|
+
- API key infrastructure with dx_live_/dx_test_ format (US-017)
|
|
92
|
+
- PII redaction and metadata policy (US-018)
|
|
93
|
+
- Background event push to Control Layer (US-016)
|
|
94
|
+
- Code scanner: `dexcost scan` CLI command (US-019)
|
|
95
|
+
- Wrapper clients: TrackedOpenAI, TrackedAnthropic (US-021)
|
|
96
|
+
- CLI: status, rates, scan commands
|
dexcost-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dexwox Innovations and contributors
|
|
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.
|
dexcost-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.PHONY: lint format typecheck test build clean
|
|
2
|
+
|
|
3
|
+
lint:
|
|
4
|
+
ruff check src/ tests/
|
|
5
|
+
|
|
6
|
+
format:
|
|
7
|
+
black src/ tests/
|
|
8
|
+
|
|
9
|
+
typecheck:
|
|
10
|
+
mypy src/
|
|
11
|
+
|
|
12
|
+
test:
|
|
13
|
+
python -m pytest
|
|
14
|
+
|
|
15
|
+
build:
|
|
16
|
+
python -m build
|
|
17
|
+
|
|
18
|
+
clean:
|
|
19
|
+
rm -rf dist/ build/ *.egg-info src/*.egg-info
|
|
20
|
+
find . -type d -name __pycache__ -exec rm -rf {} +
|
|
21
|
+
find . -type f -name "*.pyc" -delete
|
dexcost-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dexcost
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agent Unit Economics SDK — track end-to-end business-task costs for AI agents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/DexwoxBusiness/dexcost-sdk
|
|
6
|
+
Project-URL: Documentation, https://github.com/DexwoxBusiness/dexcost-sdk/blob/main/python/README.md
|
|
7
|
+
Project-URL: Repository, https://github.com/DexwoxBusiness/dexcost-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/DexwoxBusiness/dexcost-sdk/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/DexwoxBusiness/dexcost-sdk/blob/main/python/CHANGELOG.md
|
|
10
|
+
Author: Dexwox Innovations
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: agents,ai,cost-tracking,llm,observability,unit-economics
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: click>=8.1
|
|
25
|
+
Requires-Dist: jsonschema>=4.20
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: wrapt>=1.16
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: anthropic>=0.18; extra == 'all'
|
|
30
|
+
Requires-Dist: boto3>=1.34; extra == 'all'
|
|
31
|
+
Requires-Dist: cohere>=5.0; extra == 'all'
|
|
32
|
+
Requires-Dist: google-genai>=1.0; extra == 'all'
|
|
33
|
+
Requires-Dist: litellm>=1.0; extra == 'all'
|
|
34
|
+
Requires-Dist: openai>=1.0; extra == 'all'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# dexcost
|
|
38
|
+
|
|
39
|
+
**Agent Unit Economics SDK** — track end-to-end business-task costs for AI agents.
|
|
40
|
+
|
|
41
|
+
dexcost attributes LLM calls, non-LLM service fees, and retry waste to customers, projects, and workflows so you can answer *"what does each AI task actually cost?"*
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install dexcost
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
With all LLM provider SDKs:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install dexcost[all]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Global API (recommended)
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import dexcost
|
|
61
|
+
|
|
62
|
+
dexcost.init(api_key="dx_live_...") # or set DEXCOST_API_KEY env var
|
|
63
|
+
dexcost.set_context(customer_id="acme-corp")
|
|
64
|
+
|
|
65
|
+
with dexcost.task(task_type="summarise_doc") as t:
|
|
66
|
+
# LLM calls are auto-captured — just use OpenAI/Anthropic/etc normally
|
|
67
|
+
response = openai.chat.completions.create(
|
|
68
|
+
model="gpt-4o",
|
|
69
|
+
messages=[{"role": "user", "content": "Summarise this document"}],
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Record non-LLM costs manually
|
|
73
|
+
t.record_cost(service="pdf_parser", cost_usd="0.002")
|
|
74
|
+
|
|
75
|
+
dexcost.close()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Instance API (for multi-tracker scenarios)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from dexcost import CostTracker
|
|
82
|
+
from dexcost.storage.sqlite import SQLiteStorage
|
|
83
|
+
|
|
84
|
+
tracker = CostTracker(storage=SQLiteStorage("/tmp/demo.db"))
|
|
85
|
+
|
|
86
|
+
with tracker.task(task_type="summarise_doc", customer_id="acme") as t:
|
|
87
|
+
t.record_llm_call("openai", "gpt-4o", input_tokens=800, output_tokens=150)
|
|
88
|
+
t.record_cost(service="pdf_parser", cost_usd="0.002")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Auto-Instrumentation
|
|
92
|
+
|
|
93
|
+
dexcost auto-instruments **6 LLM providers** and **5 HTTP libraries**.
|
|
94
|
+
|
|
95
|
+
### LLM Providers
|
|
96
|
+
|
|
97
|
+
| Provider | Package | Auto-Patched Method |
|
|
98
|
+
|----------|---------|-------------------|
|
|
99
|
+
| OpenAI | `openai` | `chat.completions.create` (sync + async) |
|
|
100
|
+
| Anthropic | `anthropic` | `messages.create` (sync + async) |
|
|
101
|
+
| LiteLLM | `litellm` | `completion` / `acompletion` |
|
|
102
|
+
| Google Gemini | `google-genai` | `models.generate_content` |
|
|
103
|
+
| AWS Bedrock | `boto3` (botocore) | `invoke_model` |
|
|
104
|
+
| Cohere | `cohere` | `chat` / `generate` |
|
|
105
|
+
|
|
106
|
+
Every LLM call inside a tracked task is captured automatically — cost, tokens, latency, model, provider. No manual `record_llm_call` needed.
|
|
107
|
+
|
|
108
|
+
### HTTP Libraries (Non-LLM Cost Capture)
|
|
109
|
+
|
|
110
|
+
| Library | What's Patched |
|
|
111
|
+
|---------|---------------|
|
|
112
|
+
| `requests` | `Session.send` |
|
|
113
|
+
| `httpx` | `Client.send` |
|
|
114
|
+
| `aiohttp` | `ClientSession._request` |
|
|
115
|
+
| `botocore` (boto3) | `URLLib3Session.send` |
|
|
116
|
+
| `urllib3` | `HTTPConnectionPool.urlopen` |
|
|
117
|
+
|
|
118
|
+
HTTP calls to domains in the [163-service catalog](src/dexcost/data/service_prices.json) (Pinecone, Twilio, SendGrid, Stripe, Firecrawl, Exa, etc.) are automatically captured as `external_cost` events with cost extracted from the response.
|
|
119
|
+
|
|
120
|
+
### Controlling Instrumentation
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Instrument only specific providers
|
|
124
|
+
dexcost.init(auto_instrument=["openai", "gemini"])
|
|
125
|
+
|
|
126
|
+
# Disable all auto-instrumentation
|
|
127
|
+
dexcost.init(auto_instrument=[])
|
|
128
|
+
|
|
129
|
+
# Disable HTTP tracking
|
|
130
|
+
dexcost.init(track_http=False)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
### `dexcost.init()` Parameters
|
|
136
|
+
|
|
137
|
+
| Parameter | Type | Default | Description |
|
|
138
|
+
|-----------|------|---------|-------------|
|
|
139
|
+
| `api_key` | `str` | `DEXCOST_API_KEY` env | API key for cloud push |
|
|
140
|
+
| `auto_instrument` | `list[str]` | All 6 providers | Which LLM SDKs to patch |
|
|
141
|
+
| `track_http` | `bool` | `True` | Patch HTTP libraries for non-LLM cost capture |
|
|
142
|
+
| `batch_size` | `int` | `100` | Events per sync batch |
|
|
143
|
+
| `flush_interval` | `float` | `5.0` | Seconds between sync pushes |
|
|
144
|
+
| `redact_fields` | `list[str]` | `None` | Field names to redact from event details |
|
|
145
|
+
| `hash_customer_id` | `bool` | `False` | SHA-256 hash customer_id before storage |
|
|
146
|
+
| `environment` | `str` | `None` | Set to `"development"` for dev console mode |
|
|
147
|
+
| `storage` | `str` | `None` | Storage mode (`"local"` or auto-detect) |
|
|
148
|
+
| `buffer_path` | `str` | `~/.dexcost/buffer.db` | Path to local SQLite buffer |
|
|
149
|
+
|
|
150
|
+
### Environment Variables
|
|
151
|
+
|
|
152
|
+
| Variable | Description |
|
|
153
|
+
|----------|-------------|
|
|
154
|
+
| `DEXCOST_API_KEY` | API key (if not passed to `init()`) |
|
|
155
|
+
| `DEXCOST_ENDPOINT` | Control Layer URL (default: `https://api.dexcost.io`) |
|
|
156
|
+
| `DEXCOST_ENV` | Set to `development` for dev console output |
|
|
157
|
+
|
|
158
|
+
## Task Tracking
|
|
159
|
+
|
|
160
|
+
### Context Manager
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
with dexcost.task(task_type="resolve_ticket") as t:
|
|
164
|
+
# All LLM/HTTP calls inside are automatically captured
|
|
165
|
+
pass
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Decorator
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
@tracker.track_task(task_type="generate_report", customer_id="acme")
|
|
172
|
+
def generate_report(data):
|
|
173
|
+
# LLM calls here are tracked
|
|
174
|
+
pass
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Manual Start/End
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
t = tracker.start_task(task_type="batch_job", customer_id="acme")
|
|
181
|
+
# ... do work ...
|
|
182
|
+
t.end(status="success")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## TrackedTask Methods
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
with dexcost.task(task_type="...") as t:
|
|
189
|
+
# Record LLM call manually (usually auto-captured)
|
|
190
|
+
t.record_llm_call("openai", "gpt-4o", input_tokens=800, output_tokens=150)
|
|
191
|
+
|
|
192
|
+
# Record non-LLM cost
|
|
193
|
+
t.record_cost(service="pinecone", cost_usd="0.001")
|
|
194
|
+
|
|
195
|
+
# Record usage (cost computed from registered rates)
|
|
196
|
+
t.record_usage(service="s3_storage", units=1024)
|
|
197
|
+
|
|
198
|
+
# Mark a retry
|
|
199
|
+
t.mark_retry(reason="rate_limit", cost_usd="0.005")
|
|
200
|
+
|
|
201
|
+
# Link to external trace
|
|
202
|
+
t.link_trace(provider="datadog", trace_id="abc123")
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Customer Attribution
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
dexcost.set_context(customer_id="acme-corp", project_id="proj-alpha")
|
|
209
|
+
|
|
210
|
+
# All tasks created after this inherit customer_id and project_id
|
|
211
|
+
with dexcost.task(task_type="...") as t:
|
|
212
|
+
pass # t.task.customer_id == "acme-corp"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Dev Mode
|
|
216
|
+
|
|
217
|
+
Set `DEXCOST_ENV=development` or pass `environment="development"` to `init()`. In dev mode:
|
|
218
|
+
- Cost events are printed to the terminal
|
|
219
|
+
- No data is pushed to the cloud
|
|
220
|
+
- Useful for local development and debugging
|
|
221
|
+
|
|
222
|
+
## CLI
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
dexcost status # DB location, event count, sync status
|
|
226
|
+
dexcost rates --list # Show registered cost rates
|
|
227
|
+
dexcost scan . # Find untracked cost points in your code
|
|
228
|
+
dexcost scan . --generate-stubs # Generate record_cost() stubs for manual points
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Development
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
pip install -e ".[all]"
|
|
235
|
+
pip install ruff black mypy pytest
|
|
236
|
+
|
|
237
|
+
make lint # ruff
|
|
238
|
+
make format # black
|
|
239
|
+
make typecheck # mypy strict
|
|
240
|
+
make test # pytest
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Privacy
|
|
244
|
+
|
|
245
|
+
When you connect to the Dexcost Control Layer, the SDK transmits usage data
|
|
246
|
+
subject to our [Privacy Policy](https://dexcost.io/privacy).
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT — see [LICENSE](LICENSE).
|
dexcost-0.1.0/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# dexcost
|
|
2
|
+
|
|
3
|
+
**Agent Unit Economics SDK** — track end-to-end business-task costs for AI agents.
|
|
4
|
+
|
|
5
|
+
dexcost attributes LLM calls, non-LLM service fees, and retry waste to customers, projects, and workflows so you can answer *"what does each AI task actually cost?"*
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install dexcost
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
With all LLM provider SDKs:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install dexcost[all]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Global API (recommended)
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import dexcost
|
|
25
|
+
|
|
26
|
+
dexcost.init(api_key="dx_live_...") # or set DEXCOST_API_KEY env var
|
|
27
|
+
dexcost.set_context(customer_id="acme-corp")
|
|
28
|
+
|
|
29
|
+
with dexcost.task(task_type="summarise_doc") as t:
|
|
30
|
+
# LLM calls are auto-captured — just use OpenAI/Anthropic/etc normally
|
|
31
|
+
response = openai.chat.completions.create(
|
|
32
|
+
model="gpt-4o",
|
|
33
|
+
messages=[{"role": "user", "content": "Summarise this document"}],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Record non-LLM costs manually
|
|
37
|
+
t.record_cost(service="pdf_parser", cost_usd="0.002")
|
|
38
|
+
|
|
39
|
+
dexcost.close()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Instance API (for multi-tracker scenarios)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from dexcost import CostTracker
|
|
46
|
+
from dexcost.storage.sqlite import SQLiteStorage
|
|
47
|
+
|
|
48
|
+
tracker = CostTracker(storage=SQLiteStorage("/tmp/demo.db"))
|
|
49
|
+
|
|
50
|
+
with tracker.task(task_type="summarise_doc", customer_id="acme") as t:
|
|
51
|
+
t.record_llm_call("openai", "gpt-4o", input_tokens=800, output_tokens=150)
|
|
52
|
+
t.record_cost(service="pdf_parser", cost_usd="0.002")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Auto-Instrumentation
|
|
56
|
+
|
|
57
|
+
dexcost auto-instruments **6 LLM providers** and **5 HTTP libraries**.
|
|
58
|
+
|
|
59
|
+
### LLM Providers
|
|
60
|
+
|
|
61
|
+
| Provider | Package | Auto-Patched Method |
|
|
62
|
+
|----------|---------|-------------------|
|
|
63
|
+
| OpenAI | `openai` | `chat.completions.create` (sync + async) |
|
|
64
|
+
| Anthropic | `anthropic` | `messages.create` (sync + async) |
|
|
65
|
+
| LiteLLM | `litellm` | `completion` / `acompletion` |
|
|
66
|
+
| Google Gemini | `google-genai` | `models.generate_content` |
|
|
67
|
+
| AWS Bedrock | `boto3` (botocore) | `invoke_model` |
|
|
68
|
+
| Cohere | `cohere` | `chat` / `generate` |
|
|
69
|
+
|
|
70
|
+
Every LLM call inside a tracked task is captured automatically — cost, tokens, latency, model, provider. No manual `record_llm_call` needed.
|
|
71
|
+
|
|
72
|
+
### HTTP Libraries (Non-LLM Cost Capture)
|
|
73
|
+
|
|
74
|
+
| Library | What's Patched |
|
|
75
|
+
|---------|---------------|
|
|
76
|
+
| `requests` | `Session.send` |
|
|
77
|
+
| `httpx` | `Client.send` |
|
|
78
|
+
| `aiohttp` | `ClientSession._request` |
|
|
79
|
+
| `botocore` (boto3) | `URLLib3Session.send` |
|
|
80
|
+
| `urllib3` | `HTTPConnectionPool.urlopen` |
|
|
81
|
+
|
|
82
|
+
HTTP calls to domains in the [163-service catalog](src/dexcost/data/service_prices.json) (Pinecone, Twilio, SendGrid, Stripe, Firecrawl, Exa, etc.) are automatically captured as `external_cost` events with cost extracted from the response.
|
|
83
|
+
|
|
84
|
+
### Controlling Instrumentation
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# Instrument only specific providers
|
|
88
|
+
dexcost.init(auto_instrument=["openai", "gemini"])
|
|
89
|
+
|
|
90
|
+
# Disable all auto-instrumentation
|
|
91
|
+
dexcost.init(auto_instrument=[])
|
|
92
|
+
|
|
93
|
+
# Disable HTTP tracking
|
|
94
|
+
dexcost.init(track_http=False)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
### `dexcost.init()` Parameters
|
|
100
|
+
|
|
101
|
+
| Parameter | Type | Default | Description |
|
|
102
|
+
|-----------|------|---------|-------------|
|
|
103
|
+
| `api_key` | `str` | `DEXCOST_API_KEY` env | API key for cloud push |
|
|
104
|
+
| `auto_instrument` | `list[str]` | All 6 providers | Which LLM SDKs to patch |
|
|
105
|
+
| `track_http` | `bool` | `True` | Patch HTTP libraries for non-LLM cost capture |
|
|
106
|
+
| `batch_size` | `int` | `100` | Events per sync batch |
|
|
107
|
+
| `flush_interval` | `float` | `5.0` | Seconds between sync pushes |
|
|
108
|
+
| `redact_fields` | `list[str]` | `None` | Field names to redact from event details |
|
|
109
|
+
| `hash_customer_id` | `bool` | `False` | SHA-256 hash customer_id before storage |
|
|
110
|
+
| `environment` | `str` | `None` | Set to `"development"` for dev console mode |
|
|
111
|
+
| `storage` | `str` | `None` | Storage mode (`"local"` or auto-detect) |
|
|
112
|
+
| `buffer_path` | `str` | `~/.dexcost/buffer.db` | Path to local SQLite buffer |
|
|
113
|
+
|
|
114
|
+
### Environment Variables
|
|
115
|
+
|
|
116
|
+
| Variable | Description |
|
|
117
|
+
|----------|-------------|
|
|
118
|
+
| `DEXCOST_API_KEY` | API key (if not passed to `init()`) |
|
|
119
|
+
| `DEXCOST_ENDPOINT` | Control Layer URL (default: `https://api.dexcost.io`) |
|
|
120
|
+
| `DEXCOST_ENV` | Set to `development` for dev console output |
|
|
121
|
+
|
|
122
|
+
## Task Tracking
|
|
123
|
+
|
|
124
|
+
### Context Manager
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
with dexcost.task(task_type="resolve_ticket") as t:
|
|
128
|
+
# All LLM/HTTP calls inside are automatically captured
|
|
129
|
+
pass
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Decorator
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
@tracker.track_task(task_type="generate_report", customer_id="acme")
|
|
136
|
+
def generate_report(data):
|
|
137
|
+
# LLM calls here are tracked
|
|
138
|
+
pass
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Manual Start/End
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
t = tracker.start_task(task_type="batch_job", customer_id="acme")
|
|
145
|
+
# ... do work ...
|
|
146
|
+
t.end(status="success")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## TrackedTask Methods
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
with dexcost.task(task_type="...") as t:
|
|
153
|
+
# Record LLM call manually (usually auto-captured)
|
|
154
|
+
t.record_llm_call("openai", "gpt-4o", input_tokens=800, output_tokens=150)
|
|
155
|
+
|
|
156
|
+
# Record non-LLM cost
|
|
157
|
+
t.record_cost(service="pinecone", cost_usd="0.001")
|
|
158
|
+
|
|
159
|
+
# Record usage (cost computed from registered rates)
|
|
160
|
+
t.record_usage(service="s3_storage", units=1024)
|
|
161
|
+
|
|
162
|
+
# Mark a retry
|
|
163
|
+
t.mark_retry(reason="rate_limit", cost_usd="0.005")
|
|
164
|
+
|
|
165
|
+
# Link to external trace
|
|
166
|
+
t.link_trace(provider="datadog", trace_id="abc123")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Customer Attribution
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
dexcost.set_context(customer_id="acme-corp", project_id="proj-alpha")
|
|
173
|
+
|
|
174
|
+
# All tasks created after this inherit customer_id and project_id
|
|
175
|
+
with dexcost.task(task_type="...") as t:
|
|
176
|
+
pass # t.task.customer_id == "acme-corp"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Dev Mode
|
|
180
|
+
|
|
181
|
+
Set `DEXCOST_ENV=development` or pass `environment="development"` to `init()`. In dev mode:
|
|
182
|
+
- Cost events are printed to the terminal
|
|
183
|
+
- No data is pushed to the cloud
|
|
184
|
+
- Useful for local development and debugging
|
|
185
|
+
|
|
186
|
+
## CLI
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
dexcost status # DB location, event count, sync status
|
|
190
|
+
dexcost rates --list # Show registered cost rates
|
|
191
|
+
dexcost scan . # Find untracked cost points in your code
|
|
192
|
+
dexcost scan . --generate-stubs # Generate record_cost() stubs for manual points
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Development
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install -e ".[all]"
|
|
199
|
+
pip install ruff black mypy pytest
|
|
200
|
+
|
|
201
|
+
make lint # ruff
|
|
202
|
+
make format # black
|
|
203
|
+
make typecheck # mypy strict
|
|
204
|
+
make test # pytest
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Privacy
|
|
208
|
+
|
|
209
|
+
When you connect to the Dexcost Control Layer, the SDK transmits usage data
|
|
210
|
+
subject to our [Privacy Policy](https://dexcost.io/privacy).
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT — see [LICENSE](LICENSE).
|