openclacky 1.1.6 → 1.2.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/CONTRIBUTING.md +92 -0
- data/README.md +10 -0
- data/README_CN.md +10 -0
- data/ROADMAP.md +29 -0
- data/docs/billing-system.md +340 -0
- data/docs/mcp-architecture.md +114 -0
- data/docs/mcp.example.json +22 -0
- data/lib/clacky/agent/cost_tracker.rb +37 -0
- data/lib/clacky/agent/llm_caller.rb +0 -1
- data/lib/clacky/agent/session_serializer.rb +2 -11
- data/lib/clacky/agent/skill_manager.rb +73 -26
- data/lib/clacky/agent/system_prompt_builder.rb +0 -5
- data/lib/clacky/agent/time_machine.rb +6 -0
- data/lib/clacky/agent.rb +26 -1
- data/lib/clacky/agent_config.rb +9 -19
- data/lib/clacky/billing/billing_record.rb +67 -0
- data/lib/clacky/billing/billing_store.rb +193 -0
- data/lib/clacky/cli.rb +108 -6
- data/lib/clacky/default_skills/browser-setup/SKILL.md +26 -4
- data/lib/clacky/default_skills/mcp-manager/SKILL.md +343 -0
- data/lib/clacky/idle_compression_timer.rb +4 -2
- data/lib/clacky/mcp/client.rb +204 -0
- data/lib/clacky/mcp/http_transport.rb +155 -0
- data/lib/clacky/mcp/registry.rb +229 -0
- data/lib/clacky/mcp/skill_provider.rb +75 -0
- data/lib/clacky/mcp/stdio_transport.rb +112 -0
- data/lib/clacky/mcp/transport.rb +23 -0
- data/lib/clacky/mcp/virtual_skill.rb +131 -0
- data/lib/clacky/message_history.rb +0 -1
- data/lib/clacky/server/channel/adapters/weixin/adapter.rb +2 -35
- data/lib/clacky/server/http_server.rb +519 -15
- data/lib/clacky/server/server_master.rb +8 -14
- data/lib/clacky/server/session_registry.rb +24 -2
- data/lib/clacky/server/web_ui_controller.rb +4 -0
- data/lib/clacky/session_manager.rb +41 -12
- data/lib/clacky/skill.rb +1 -5
- data/lib/clacky/skill_loader.rb +36 -5
- data/lib/clacky/tools/browser.rb +217 -38
- data/lib/clacky/tools/trash_manager.rb +154 -3
- data/lib/clacky/ui2/components/command_suggestions.rb +6 -2
- data/lib/clacky/ui_interface.rb +1 -0
- data/lib/clacky/utils/model_pricing.rb +11 -7
- data/lib/clacky/utils/trash_directory.rb +37 -6
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +2907 -1764
- data/lib/clacky/web/app.js +84 -10
- data/lib/clacky/web/billing.js +275 -0
- data/lib/clacky/web/brand.js +3 -0
- data/lib/clacky/web/i18n.js +242 -24
- data/lib/clacky/web/index.html +351 -134
- data/lib/clacky/web/mcp.js +328 -0
- data/lib/clacky/web/sessions.js +193 -11
- data/lib/clacky/web/settings.js +686 -174
- data/lib/clacky/web/sidebar.js +2 -0
- data/lib/clacky/web/trash.js +323 -60
- data/lib/clacky/web/ws-dispatcher.js +14 -1
- data/lib/clacky.rb +4 -0
- data/scripts/install.ps1 +23 -11
- metadata +30 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e470c0165e741ffd7827e204f2c12dac2e20fe71f1a48431e991558edf3a501c
|
|
4
|
+
data.tar.gz: be96ec9301fa064406f8bb7e01182406f295899b75c319c1410891d9feaa2925
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2f14deab190852f14139556115888daf8cabac65a49274732d67f05c8e20d942ddb70a009c5fd5c970e9af97b3ec4b9cbe5292392b8c90c838df9c2f1c790f9
|
|
7
|
+
data.tar.gz: f9afcded8e63a1b2aad78b254ce70c5eddc8554cf1390d08a71ef334a1ecd260ad0e242cc97952eeb5aeb767d9b02443514dccef44548f466f58cff0186c6242
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.0] - 2026-05-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- MCP (Model Context Protocol) support with HTTP server transport
|
|
12
|
+
- MCP management skill for adding, listing, probing, and reconfiguring MCP servers
|
|
13
|
+
- Settings panel restructure with new "UI" and "About" tabs
|
|
14
|
+
- Advanced settings toggles for compression, prompt caching, and memory update
|
|
15
|
+
- Session recycle bin with soft-delete, restore, and bulk-empty operations (#172)
|
|
16
|
+
- Billing system with USD/CNY currency settings (#166)
|
|
17
|
+
- Configurable default working directory (#170)
|
|
18
|
+
- Model ID select for switching between configured model IDs
|
|
19
|
+
- Sequential image naming with upload order guarantee in Web UI (#188)
|
|
20
|
+
- Browser link tips in agent output
|
|
21
|
+
- Fallback URL support for model providers
|
|
22
|
+
- ROADMAP.md outlining four focus areas
|
|
23
|
+
|
|
24
|
+
### Improved
|
|
25
|
+
- Browser tool reliability and ergonomics
|
|
26
|
+
- Idle compression interval increased to 314s for fewer interruptions
|
|
27
|
+
- Removed dead WeChat split_message and markdown_to_plain code paths (#187)
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- Brand setting persistence
|
|
31
|
+
- Interactive feedback card now restored during history replay (C-5599) (#190)
|
|
32
|
+
- Model switcher disabled while agent is responding (C-5559) (#189)
|
|
33
|
+
- Stale function call no longer breaks interrupt handling
|
|
34
|
+
- Trash tool now supports directory deletion (#173)
|
|
35
|
+
- Command suggestions dropdown scrolling (#157)
|
|
36
|
+
- Comprehensive mobile Web UI fixes (#165)
|
|
37
|
+
- WSL_UTF8=1 vs OutputEncoding=Unicode conflict in Test-UbuntuInstalled (#164)
|
|
38
|
+
- USR1 hot-reload session info drop bug (#142)
|
|
39
|
+
|
|
40
|
+
### More
|
|
41
|
+
- DeepSeek price update
|
|
42
|
+
- Contributors list and contributing readme
|
|
43
|
+
- Session translation polish
|
|
44
|
+
|
|
8
45
|
## [1.1.6] - 2026-05-22
|
|
9
46
|
|
|
10
47
|
### Added
|
data/CODE_OF_CONDUCT.md
CHANGED
|
@@ -60,7 +60,7 @@ representative at an online or offline event.
|
|
|
60
60
|
|
|
61
61
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
62
62
|
reported to the community leaders responsible for enforcement at
|
|
63
|
-
|
|
63
|
+
opening an issue at https://github.com/clacky-ai/open-clacky/issues.
|
|
64
64
|
All complaints will be reviewed and investigated promptly and fairly.
|
|
65
65
|
|
|
66
66
|
All community leaders are obligated to respect the privacy and security of the
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Contributing to OpenClacky
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time to contribute. Every PR will be reviewed. We evaluate
|
|
4
|
+
each contribution along three dimensions:
|
|
5
|
+
|
|
6
|
+
1. **Value of the need** — is this useful, and to whom?
|
|
7
|
+
2. **Architectural impact** — does it fit the existing design?
|
|
8
|
+
3. **Code standards** — does it meet our quality bar?
|
|
9
|
+
|
|
10
|
+
Read the sections below before opening a PR. If your contribution clearly
|
|
11
|
+
delivers outsized value, the rules here can bend — see [Exceptions](#exceptions).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Architecture First
|
|
16
|
+
|
|
17
|
+
Improvements built on top of the existing, stable architecture are accepted
|
|
18
|
+
quickly. By "stable architecture" we mean a change that:
|
|
19
|
+
|
|
20
|
+
- Solves the need with the **smallest possible diff**.
|
|
21
|
+
- **Adds no new configuration knobs** unless strictly required.
|
|
22
|
+
- **Adds no new dependencies** unless strictly required (see also §3).
|
|
23
|
+
- **Respects the existing design intent** — same layering, same abstractions,
|
|
24
|
+
same naming conventions.
|
|
25
|
+
- Ideally **simplifies** the architecture rather than expanding it.
|
|
26
|
+
|
|
27
|
+
PRs that introduce parallel mechanisms, speculative abstractions, or "just in
|
|
28
|
+
case" flexibility will be sent back for trimming.
|
|
29
|
+
|
|
30
|
+
## 2. Needs Should Be Shared and Side-Effect-Free
|
|
31
|
+
|
|
32
|
+
We prefer changes that benefit **most users** and have **no side effects** on
|
|
33
|
+
others.
|
|
34
|
+
|
|
35
|
+
- **Common needs** (broadly applicable, opt-in by nature, isolated blast
|
|
36
|
+
radius) → fast track.
|
|
37
|
+
- **Niche needs** (valuable to a few, but with potential to affect others'
|
|
38
|
+
workflows, performance, or defaults) → reviewed more cautiously. Expect
|
|
39
|
+
questions about scope, defaults, and rollout.
|
|
40
|
+
|
|
41
|
+
If your change alters existing default behavior, call it out explicitly in the
|
|
42
|
+
PR description.
|
|
43
|
+
|
|
44
|
+
## 3. Code Standards
|
|
45
|
+
|
|
46
|
+
### Tests
|
|
47
|
+
|
|
48
|
+
- All tests **must pass** before a PR can be merged.
|
|
49
|
+
- **Coverage must not drop.** New code needs new tests.
|
|
50
|
+
|
|
51
|
+
### Commits & PRs
|
|
52
|
+
|
|
53
|
+
- **Write commit messages and PR titles/descriptions in English.** This applies
|
|
54
|
+
to everyone, regardless of working language.
|
|
55
|
+
- Keep commits focused; squash noise before requesting review.
|
|
56
|
+
- PR descriptions should briefly state: what, why, and any user-visible impact.
|
|
57
|
+
|
|
58
|
+
### Built with OpenClacky
|
|
59
|
+
|
|
60
|
+
- PRs **authored using OpenClacky itself** are prioritized for review and
|
|
61
|
+
merge. Mention it in the PR description if applicable. We dogfood our own
|
|
62
|
+
tool.
|
|
63
|
+
|
|
64
|
+
### Dependencies
|
|
65
|
+
|
|
66
|
+
- **Avoid adding new libraries.** Prefer the standard library, existing
|
|
67
|
+
dependencies, or a few lines of code over pulling in another gem/package.
|
|
68
|
+
- If a new dependency is genuinely necessary, justify it in the PR description:
|
|
69
|
+
why this library, why not write it ourselves, license, maintenance status.
|
|
70
|
+
|
|
71
|
+
### Style
|
|
72
|
+
|
|
73
|
+
- Follow the conventions already present in the file you're editing.
|
|
74
|
+
- See each sub-project's `.clackyrules` for project-specific rules
|
|
75
|
+
(`openclacky/`, `platform/`, `installer/`).
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Exceptions
|
|
80
|
+
|
|
81
|
+
Rules exist to keep the project healthy, not to block valuable work. For
|
|
82
|
+
contributions that deliver **substantial, clear value**, the standards above
|
|
83
|
+
can be relaxed at the maintainers' discretion. When in doubt, open an issue or
|
|
84
|
+
draft PR first to discuss the trade-offs.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Code of Conduct
|
|
89
|
+
|
|
90
|
+
Participation in this project is governed by the
|
|
91
|
+
[Code of Conduct](./CODE_OF_CONDUCT.md). By contributing, you agree to uphold
|
|
92
|
+
it.
|
data/README.md
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
<a href="README.md">English</a> · <a href="README_CN.md">简体中文</a>
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
+
> Contributing? Read **[CONTRIBUTING.md](./CONTRIBUTING.md)** before opening a PR.
|
|
14
|
+
|
|
13
15
|
**The most Token-efficient open-source AI Agent.**
|
|
14
16
|
|
|
15
17
|
OpenClacky matches Claude Code on capability at comparable cost, and saves significantly against other open-source agents (~50% vs OpenClaw, ~3× cheaper than Hermes). 100% open source (MIT), BYOK with any OpenAI-compatible model, built on two years of Agentic R&D and harness engineering.
|
|
@@ -184,6 +186,14 @@ bin/clacky
|
|
|
184
186
|
- **16 core tools** — minimal by design
|
|
185
187
|
- **Backed by** MiraclePlus · ZhenFund · Sequoia China · Hillhouse Capital
|
|
186
188
|
|
|
189
|
+
## Contributors
|
|
190
|
+
|
|
191
|
+
Every line of code, bug report, and thoughtful review matters. Thank you for making OpenClacky better.
|
|
192
|
+
|
|
193
|
+
<a href="https://github.com/clacky-ai/openclacky/graphs/contributors">
|
|
194
|
+
<img src="https://contrib.rocks/image?repo=clacky-ai/openclacky" />
|
|
195
|
+
</a>
|
|
196
|
+
|
|
187
197
|
## Contributing
|
|
188
198
|
|
|
189
199
|
Bug reports and pull requests are welcome on GitHub at https://github.com/clacky-ai/openclacky. Contributors are expected to adhere to the [code of conduct](https://github.com/clacky-ai/openclacky/blob/main/CODE_OF_CONDUCT.md).
|
data/README_CN.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
[](https://rubygems.org/gems/openclacky)
|
|
7
7
|
[](LICENSE.txt)
|
|
8
8
|
|
|
9
|
+
> 想贡献代码?提 PR 前请先读 **[CONTRIBUTING.md](./CONTRIBUTING.md)**。
|
|
10
|
+
|
|
9
11
|
**最省 Token 的开源 AI Agent。**
|
|
10
12
|
|
|
11
13
|
OpenClacky 在任务能力上对齐 Claude Code,成本相当,同时相比其他开源 Agent 有显著优势(约节省 50% vs OpenClaw,约便宜 3× vs Hermes)。100% 开源(MIT),支持 BYOK 接入任意 OpenAI 兼容模型,背后是两年 Agentic 研发与 Harness 工程积累。
|
|
@@ -189,6 +191,14 @@ bin/clacky
|
|
|
189
191
|
- [我把 AI 账单从 30 美金打到 5 美金](https://mp.weixin.qq.com/s/BDhE0y8xbX0ea3vLlV37Ig)
|
|
190
192
|
- [100% Cache 命中的 Harness 怎么设计:一个开源 AI Agent 的 7 个工程决策](https://mp.weixin.qq.com/s/Rc1xk0Qw168D4Y07kkBiGQ)
|
|
191
193
|
|
|
194
|
+
## 贡献者
|
|
195
|
+
|
|
196
|
+
每一行代码、每一个 Bug 报告、每一次认真的 Review,都让 OpenClacky 变得更好。感谢你们!
|
|
197
|
+
|
|
198
|
+
<a href="https://github.com/clacky-ai/openclacky/graphs/contributors">
|
|
199
|
+
<img src="https://contrib.rocks/image?repo=clacky-ai/openclacky" />
|
|
200
|
+
</a>
|
|
201
|
+
|
|
192
202
|
## 参与贡献
|
|
193
203
|
|
|
194
204
|
欢迎在 GitHub 提交 Bug 报告和 Pull Request:https://github.com/clacky-ai/openclacky 。参与贡献者须遵守[行为准则](https://github.com/clacky-ai/openclacky/blob/main/CODE_OF_CONDUCT.md)。
|
data/ROADMAP.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
We're currently focused on four areas. If you'd like to contribute, start here.
|
|
4
|
+
|
|
5
|
+
## 1. Zero-Extra-Token MCP Integration
|
|
6
|
+
|
|
7
|
+
Connect OpenClacky to the MCP (Model Context Protocol) ecosystem — plug-and-play MCP Server support, with protocol-level token overhead minimized via caching and compression strategies.
|
|
8
|
+
|
|
9
|
+
## 2. Plugin System
|
|
10
|
+
|
|
11
|
+
Design a plugin architecture that lets the community develop, publish, and install plugins without touching core code. Think VS Code Extension-like developer experience.
|
|
12
|
+
|
|
13
|
+
## 3. Skill UI Extension
|
|
14
|
+
|
|
15
|
+
Provide visual configuration and interactive extension capabilities for Skills, lowering the barrier to creating and customizing Skills.
|
|
16
|
+
|
|
17
|
+
## 4. Image & Video Model Support
|
|
18
|
+
|
|
19
|
+
Native support for image and video generation models (DALL·E, Midjourney, Sora, etc.), enabling agents to generate and orchestrate multimedia content directly in conversations.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## How to Contribute
|
|
24
|
+
|
|
25
|
+
Each direction breaks down into specific tasks tracked as [Issues](https://github.com/clacky-ai/openclacky/issues), labeled with `enhancement`.
|
|
26
|
+
|
|
27
|
+
New to the project? Start with a [`good first issue`](https://github.com/clacky-ai/openclacky/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
|
28
|
+
|
|
29
|
+
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a PR.
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Billing System
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Billing System provides persistent tracking of API usage and costs across all
|
|
6
|
+
sessions. It records every LLM API call with token counts and calculated costs,
|
|
7
|
+
storing them in monthly JSONL files for easy querying and analysis.
|
|
8
|
+
|
|
9
|
+
## Design Principles
|
|
10
|
+
|
|
11
|
+
- **Non-blocking** — Billing persistence is fire-and-forget; failures never interrupt agent flow
|
|
12
|
+
- **Minimal footprint** — JSONL format, one file per month, no database dependency
|
|
13
|
+
- **Privacy-first** — Data stored locally in `~/.clacky/billing/`, never uploaded
|
|
14
|
+
- **Accurate costing** — Uses the same `ModelPricing` module as real-time display
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
22
|
+
│ Agent │
|
|
23
|
+
│ CostTracker module │
|
|
24
|
+
│ └── track_cost() │
|
|
25
|
+
│ ├── Calculate cost (ModelPricing) │
|
|
26
|
+
│ ├── Update UI (real-time) │
|
|
27
|
+
│ └── persist_billing_record() ──────┐ │
|
|
28
|
+
└─────────────────────────────────────────────┼───────────────────┘
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
32
|
+
│ Billing Module │
|
|
33
|
+
│ lib/clacky/billing/ │
|
|
34
|
+
│ ├── billing_record.rb (data structure) │
|
|
35
|
+
│ └── billing_store.rb (JSONL persistence) │
|
|
36
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
37
|
+
│
|
|
38
|
+
▼
|
|
39
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ Storage │
|
|
41
|
+
│ ~/.clacky/billing/ │
|
|
42
|
+
│ ├── 2026-05.jsonl │
|
|
43
|
+
│ ├── 2026-04.jsonl │
|
|
44
|
+
│ └── ... │
|
|
45
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Components
|
|
51
|
+
|
|
52
|
+
### BillingRecord (`lib/clacky/billing/billing_record.rb`)
|
|
53
|
+
|
|
54
|
+
A Struct representing a single API call:
|
|
55
|
+
|
|
56
|
+
| Field | Type | Description |
|
|
57
|
+
|-------|------|-------------|
|
|
58
|
+
| `id` | String | UUID, auto-generated |
|
|
59
|
+
| `session_id` | String | Associated session |
|
|
60
|
+
| `timestamp` | Time | When the call was made |
|
|
61
|
+
| `model` | String | Model name (e.g., "claude-sonnet-4.5") |
|
|
62
|
+
| `prompt_tokens` | Integer | Input tokens |
|
|
63
|
+
| `completion_tokens` | Integer | Output tokens |
|
|
64
|
+
| `cache_read_tokens` | Integer | Tokens read from cache |
|
|
65
|
+
| `cache_write_tokens` | Integer | Tokens written to cache |
|
|
66
|
+
| `cost_usd` | Float | Calculated cost in USD |
|
|
67
|
+
| `cost_source` | Symbol | `:api`, `:price`, or `:estimated` |
|
|
68
|
+
|
|
69
|
+
### BillingStore (`lib/clacky/billing/billing_store.rb`)
|
|
70
|
+
|
|
71
|
+
Handles persistence and querying:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
store = Clacky::Billing::BillingStore.new
|
|
75
|
+
|
|
76
|
+
# Append a record
|
|
77
|
+
store.append(record)
|
|
78
|
+
|
|
79
|
+
# Query with filters
|
|
80
|
+
records = store.query(from: 1.week.ago, model: "claude-sonnet-4.5", limit: 100)
|
|
81
|
+
|
|
82
|
+
# Get summary statistics
|
|
83
|
+
summary = store.summary(period: :month)
|
|
84
|
+
# => { total_cost: 12.34, total_tokens: 500000, by_model: {...}, ... }
|
|
85
|
+
|
|
86
|
+
# Daily breakdown for charts
|
|
87
|
+
daily = store.daily_breakdown(days: 30)
|
|
88
|
+
# => [{ date: "2026-05-01", cost: 1.23, tokens: 50000, requests: 42 }, ...]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Storage Format
|
|
94
|
+
|
|
95
|
+
Records are stored as JSON Lines (one JSON object per line):
|
|
96
|
+
|
|
97
|
+
```jsonl
|
|
98
|
+
{"id":"abc123","session_id":"def456","timestamp":"2026-05-22T15:30:00+08:00","model":"claude-sonnet-4.5","prompt_tokens":1500,"completion_tokens":500,"cache_read_tokens":1000,"cache_write_tokens":0,"cost_usd":0.0045,"cost_source":"price"}
|
|
99
|
+
{"id":"abc124","session_id":"def456","timestamp":"2026-05-22T15:31:00+08:00","model":"claude-sonnet-4.5","prompt_tokens":2000,"completion_tokens":800,"cache_read_tokens":1500,"cache_write_tokens":0,"cost_usd":0.0052,"cost_source":"price"}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Why JSONL?**
|
|
103
|
+
- Append-only writes (no file locking needed)
|
|
104
|
+
- Easy to parse line-by-line (memory efficient)
|
|
105
|
+
- Human-readable for debugging
|
|
106
|
+
- Simple monthly rotation
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## API Endpoints
|
|
111
|
+
|
|
112
|
+
### GET /api/billing/summary
|
|
113
|
+
|
|
114
|
+
Returns aggregated statistics for a time period.
|
|
115
|
+
|
|
116
|
+
**Query Parameters:**
|
|
117
|
+
- `period` — `day`, `week`, `month`, `year`, or `all` (default: `month`)
|
|
118
|
+
|
|
119
|
+
**Response:**
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"period": "month",
|
|
123
|
+
"from": "2026-05-01T00:00:00+08:00",
|
|
124
|
+
"to": "2026-05-22T15:30:00+08:00",
|
|
125
|
+
"total_cost": 12.3456,
|
|
126
|
+
"total_tokens": 500000,
|
|
127
|
+
"prompt_tokens": 350000,
|
|
128
|
+
"completion_tokens": 150000,
|
|
129
|
+
"cache_read_tokens": 200000,
|
|
130
|
+
"cache_write_tokens": 50000,
|
|
131
|
+
"by_model": {
|
|
132
|
+
"claude-sonnet-4.5": { "cost": 10.00, "requests": 100 },
|
|
133
|
+
"deepseek-v4-flash": { "cost": 2.34, "requests": 50 }
|
|
134
|
+
},
|
|
135
|
+
"by_day": {
|
|
136
|
+
"2026-05-22": 1.23,
|
|
137
|
+
"2026-05-21": 2.34
|
|
138
|
+
},
|
|
139
|
+
"record_count": 150
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### GET /api/billing/daily
|
|
144
|
+
|
|
145
|
+
Returns daily cost breakdown for charting.
|
|
146
|
+
|
|
147
|
+
**Query Parameters:**
|
|
148
|
+
- `days` — Number of days (default: 30, max: 90)
|
|
149
|
+
|
|
150
|
+
**Response:**
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"days": [
|
|
154
|
+
{ "date": "2026-05-22", "cost": 1.2345, "tokens": 50000, "requests": 42 },
|
|
155
|
+
{ "date": "2026-05-21", "cost": 2.3456, "tokens": 80000, "requests": 65 }
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### GET /api/billing/records
|
|
161
|
+
|
|
162
|
+
Returns raw billing records.
|
|
163
|
+
|
|
164
|
+
**Query Parameters:**
|
|
165
|
+
- `limit` — Max records (default: 100, max: 500)
|
|
166
|
+
- `model` — Filter by model name
|
|
167
|
+
- `session_id` — Filter by session ID
|
|
168
|
+
|
|
169
|
+
**Response:**
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"records": [
|
|
173
|
+
{ "id": "...", "timestamp": "...", "model": "...", "cost_usd": 0.01, ... }
|
|
174
|
+
],
|
|
175
|
+
"count": 100
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## CLI Command
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Show current month's billing
|
|
185
|
+
clacky billing
|
|
186
|
+
|
|
187
|
+
# Show specific period
|
|
188
|
+
clacky billing --period week
|
|
189
|
+
clacky billing --period day
|
|
190
|
+
clacky billing --period all
|
|
191
|
+
|
|
192
|
+
# Output as JSON (for scripting)
|
|
193
|
+
clacky billing --json
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Sample Output:**
|
|
197
|
+
```
|
|
198
|
+
📊 Billing Summary (month)
|
|
199
|
+
──────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
💰 Total Cost: $12.3456
|
|
202
|
+
📝 Total Tokens: 500,000
|
|
203
|
+
📥 Prompt Tokens: 350,000
|
|
204
|
+
📤 Completion: 150,000
|
|
205
|
+
🗄️ Cache Read: 200,000
|
|
206
|
+
📝 Cache Write: 50,000
|
|
207
|
+
🔢 API Requests: 150
|
|
208
|
+
|
|
209
|
+
📈 By Model:
|
|
210
|
+
──────────────────────────────────────────────────
|
|
211
|
+
claude-sonnet-4.5
|
|
212
|
+
Cost: $10.0000 | Requests: 100
|
|
213
|
+
deepseek-v4-flash
|
|
214
|
+
Cost: $2.3456 | Requests: 50
|
|
215
|
+
|
|
216
|
+
📅 Recent Daily Usage:
|
|
217
|
+
──────────────────────────────────────────────────
|
|
218
|
+
2026-05-22 $1.2345 ████████████
|
|
219
|
+
2026-05-21 $2.3456 ████████████████████████
|
|
220
|
+
|
|
221
|
+
──────────────────────────────────────────────────
|
|
222
|
+
Data stored in: ~/.clacky/billing/
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Web UI
|
|
228
|
+
|
|
229
|
+
The Billing panel is accessible from the sidebar under "My Data":
|
|
230
|
+
|
|
231
|
+
- **Summary cards** — Total cost, tokens, API requests
|
|
232
|
+
- **Token breakdown** — Prompt, completion, cache read/write
|
|
233
|
+
- **By Model table** — Cost and request count per model
|
|
234
|
+
- **Daily chart** — Visual bar chart of recent usage with detailed tooltips
|
|
235
|
+
- **Period selector** — Filter by day/week/month/year/all
|
|
236
|
+
|
|
237
|
+
### Daily Chart Tooltips
|
|
238
|
+
|
|
239
|
+
Hover over any bar in the daily chart to see detailed information:
|
|
240
|
+
- Date and total cost
|
|
241
|
+
- Input tokens (prompt)
|
|
242
|
+
- Output tokens (completion)
|
|
243
|
+
- Cache read tokens with hit rate percentage
|
|
244
|
+
- Cache write tokens
|
|
245
|
+
- Number of API requests
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Currency Settings
|
|
250
|
+
|
|
251
|
+
The Web UI supports multiple currencies for cost display:
|
|
252
|
+
|
|
253
|
+
| Currency | Symbol | Default Exchange Rate |
|
|
254
|
+
|----------|--------|----------------------|
|
|
255
|
+
| USD | $ | 1.0 (base) |
|
|
256
|
+
| CNY | ¥ | 6.7944 (customizable) |
|
|
257
|
+
|
|
258
|
+
### Configuration
|
|
259
|
+
|
|
260
|
+
1. Go to **Settings** page
|
|
261
|
+
2. Find the **Currency** section
|
|
262
|
+
3. Select `$ USD` or `¥ CNY`
|
|
263
|
+
4. When CNY is selected, you can customize the exchange rate
|
|
264
|
+
|
|
265
|
+
### Custom Exchange Rate
|
|
266
|
+
|
|
267
|
+
When CNY is selected, an exchange rate input field appears:
|
|
268
|
+
- Default rate: 6.7944 (1 USD = 6.7944 CNY)
|
|
269
|
+
- Enter any positive number to customize
|
|
270
|
+
- Changes take effect immediately
|
|
271
|
+
- Rate is saved to browser localStorage
|
|
272
|
+
|
|
273
|
+
### Scope
|
|
274
|
+
|
|
275
|
+
Currency settings apply to:
|
|
276
|
+
- Billing panel (total cost, model costs, daily chart)
|
|
277
|
+
- Session info bar (top cost display)
|
|
278
|
+
- Token usage lines (per-API-call cost)
|
|
279
|
+
- Task completion messages
|
|
280
|
+
|
|
281
|
+
**Note:** CLI always displays costs in USD (API's native currency).
|
|
282
|
+
|
|
283
|
+
### Implementation
|
|
284
|
+
|
|
285
|
+
Currency preference is stored in browser `localStorage`:
|
|
286
|
+
- `clacky-currency`: Currency code ("USD" or "CNY")
|
|
287
|
+
- `clacky-exchange-rate`: Custom exchange rate (number)
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
// Access currency utilities from Billing module
|
|
291
|
+
Billing.getCurrency() // "USD" or "CNY"
|
|
292
|
+
Billing.getCurrencySymbol() // "$" or "¥"
|
|
293
|
+
Billing.convertCost(usd) // Convert USD to selected currency
|
|
294
|
+
Billing.getExchangeRate() // Get current exchange rate
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Integration with CostTracker
|
|
300
|
+
|
|
301
|
+
The billing system hooks into `Agent::CostTracker#track_cost`:
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
def track_cost(usage, raw_api_usage: nil)
|
|
305
|
+
# ... existing cost calculation ...
|
|
306
|
+
|
|
307
|
+
# Persist billing record (skip for subagents to avoid double-counting)
|
|
308
|
+
unless @is_subagent
|
|
309
|
+
persist_billing_record(usage, iteration_cost)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
token_data
|
|
313
|
+
end
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Key behaviors:**
|
|
317
|
+
- Subagent costs are NOT recorded separately (parent agent merges them)
|
|
318
|
+
- Unknown model costs (nil) are skipped
|
|
319
|
+
- Persistence failures are logged but never raise
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Data Retention
|
|
324
|
+
|
|
325
|
+
- Records are stored indefinitely by default
|
|
326
|
+
- Monthly files can be manually deleted from `~/.clacky/billing/`
|
|
327
|
+
- Future: `BillingStore#cleanup(before: 1.year.ago)` for automated retention
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Future Enhancements
|
|
332
|
+
|
|
333
|
+
- [ ] Export to CSV/JSON
|
|
334
|
+
- [ ] Budget alerts (daily/monthly limits)
|
|
335
|
+
- [ ] Cost comparison across models
|
|
336
|
+
- [ ] Session-level cost breakdown in UI
|
|
337
|
+
- [x] i18n support for billing labels (English/Chinese)
|
|
338
|
+
- [x] Currency settings (USD/CNY)
|
|
339
|
+
- [ ] Dynamic exchange rate updates
|
|
340
|
+
- [ ] More currency options (EUR, JPY, etc.)
|