@clawpump/claw-agent 0.1.0 → 0.1.2
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.
- package/LICENSE +32 -0
- package/agent/README.md +2 -2
- package/agent/docs/UPSTREAM_SYNC.md +58 -0
- package/agent/hermes_cli/auth.py +31 -0
- package/agent/hermes_cli/banner.py +4 -1
- package/agent/hermes_cli/clawpump_cli.py +6 -5
- package/agent/hermes_cli/config.py +15 -48
- package/agent/hermes_cli/distribution.py +230 -0
- package/agent/hermes_cli/main.py +73 -18
- package/agent/hermes_cli/runtime_provider.py +24 -0
- package/agent/hermes_cli/skin_engine.py +16 -84
- package/agent/optional-mcps/clawpump/manifest.yaml +33 -6
- package/agent/optional-mcps/clawpump-stdio/manifest.yaml +24 -3
- package/agent/plugins/model-providers/usepod/__init__.py +100 -0
- package/agent/plugins/model-providers/usepod/plugin.yaml +5 -0
- package/agent/scripts/release.py +1 -0
- package/agent/skills/clawpump/SKILL.md +32 -16
- package/agent/skills/pay-sh/SKILL.md +66 -0
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
claw-agent (@clawpump/claw-agent) is a distribution of the Hermes Agent.
|
|
2
|
+
It bundles the Hermes Agent by Nous Research together with ClawPump's
|
|
3
|
+
modifications and branding. Both the original work and the modifications are
|
|
4
|
+
provided under the MIT License below. The Hermes Agent copyright notice is
|
|
5
|
+
retained as required.
|
|
6
|
+
|
|
7
|
+
Upstream: https://github.com/NousResearch/hermes-agent
|
|
8
|
+
|
|
9
|
+
----------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2025 Nous Research (Hermes Agent)
|
|
14
|
+
Copyright (c) 2026 ClawPump (claw-agent distribution and modifications)
|
|
15
|
+
|
|
16
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
17
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
18
|
+
in the Software without restriction, including without limitation the rights
|
|
19
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
20
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
21
|
+
furnished to do so, subject to the following conditions:
|
|
22
|
+
|
|
23
|
+
The above copyright notice and this permission notice shall be included in all
|
|
24
|
+
copies or substantial portions of the Software.
|
|
25
|
+
|
|
26
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
27
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
28
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
29
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
30
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
31
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
32
|
+
SOFTWARE.
|
package/agent/README.md
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
<a href="https://github.com/NousResearch/hermes-agent">Upstream: Hermes</a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
ClawPump's full feature set — **
|
|
18
|
+
ClawPump's full feature set — **131 MCP tools** spanning agents, trading, Phoenix perps, DCA, Jupiter lending, token launch, marketplace, predictions, gift cards (Laso), agent mail, wallet transfers, pay.sh x402 paid APIs, and market intelligence — is wired in natively. One command:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
hermes clawpump setup # pick remote OAuth (browser) or stdio (cpk_ key)
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
That pairs the agent with the ClawPump MCP — remote `https://mcp.clawpump.tech/mcp`, or the local `npx @clawpump/agents` stdio path — and the ClawPump green theme is on by default. See the [ClawPump skill](skills/clawpump/SKILL.md) and the catalog entries under [`optional-mcps/`](optional-mcps/) (`clawpump`, `clawpump-stdio`).
|
|
24
|
+
That pairs the agent with the ClawPump MCP — remote `https://mcp.clawpump.tech/mcp`, or the local `npx @clawpump/agents` stdio path — and the ClawPump green theme is on by default. See the [ClawPump skill](skills/clawpump/SKILL.md) and the catalog entries under [`optional-mcps/`](optional-mcps/) (`clawpump`, `clawpump-stdio`). [pay.sh](https://pay.sh) x402 paid APIs are paid straight from the agent wallet via the `pay_sh_*` tools — no separate wallet.
|
|
25
25
|
|
|
26
26
|
> **Built on Hermes.** ClawPump is a downstream distribution of the **Hermes Agent** by **Nous Research**, used under the MIT License. The upstream agent — its runtime, docs, and features — is unchanged below; ClawPump adds the native ClawPump MCP integration plus init/theme branding on top. Full credit for the underlying agent goes to Nous Research. See [`LICENSE`](LICENSE).
|
|
27
27
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Keeping ClawPump in sync with upstream Hermes
|
|
2
|
+
|
|
3
|
+
ClawPump (`Clawpump/claw-agent`) is a **fork of [`NousResearch/hermes-agent`](https://github.com/NousResearch/hermes-agent)** that shares full git history with upstream. Upstream ships very frequently (CalVer, ~daily), so we pull its changes in continuously rather than letting the fork drift.
|
|
4
|
+
|
|
5
|
+
## How divergence is kept small
|
|
6
|
+
|
|
7
|
+
All ClawPump-specific behavior lives in a single downstream-owned module, **`hermes_cli/distribution.py`** (skin, default skin, default MCP server, `CLAWPUMP_*` env vars, the `clawpump` subcommand, the npm self-update, the update-check repo URL). The upstream-owned files (`skin_engine.py`, `config.py`, `main.py`, `banner.py`) carry only a small, self-degrading hook each and otherwise match vanilla Hermes byte-for-byte.
|
|
8
|
+
|
|
9
|
+
**Rule of thumb:** never edit an upstream-owned file to add ClawPump behavior. Add it to `distribution.py` and wire a one-line hook. The smaller the divergence in upstream files, the cleaner every sync.
|
|
10
|
+
|
|
11
|
+
## Automated sync (`.github/workflows/upstream-sync.yml`)
|
|
12
|
+
|
|
13
|
+
Runs daily (and via **Actions → Upstream Sync → Run workflow**). Each run:
|
|
14
|
+
|
|
15
|
+
1. Fetches `upstream/main` and checks how far `main` is behind.
|
|
16
|
+
2. If behind **and** no `upstream-sync` PR is already open, creates a `sync/upstream-<timestamp>` branch and **merges** `upstream/main` into it (a real merge commit, to preserve history).
|
|
17
|
+
3. Opens a PR into `main`, labelled `upstream-sync` (and `has-conflicts` if the merge had conflicts — the markers are committed so you can resolve them in the branch).
|
|
18
|
+
|
|
19
|
+
It is self-throttling: only one open sync PR at a time, and it no-ops when already up to date.
|
|
20
|
+
|
|
21
|
+
### Reviewing / merging a sync PR
|
|
22
|
+
|
|
23
|
+
- **Clean merge:** review the diff + CI, then **merge with a merge commit** (not squash — squashing discards the upstream parent and breaks future merge-bases).
|
|
24
|
+
- **Conflicts:** they're almost always in docs (`README.md`, `.env.example`). Resolve in the branch:
|
|
25
|
+
```bash
|
|
26
|
+
git fetch origin && git switch sync/upstream-<timestamp>
|
|
27
|
+
# resolve conflicts; for docs you usually keep ours
|
|
28
|
+
git add -A && git commit && git push
|
|
29
|
+
```
|
|
30
|
+
If a conflict lands in an upstream-owned `.py` file, that's a signal a downstream edit leaked in — prefer moving that edit into `distribution.py` so it won't conflict again.
|
|
31
|
+
|
|
32
|
+
### One-time setup for full CI on sync PRs
|
|
33
|
+
|
|
34
|
+
PRs opened with the default `GITHUB_TOKEN` do **not** trigger other workflows, so the repo's CI (tests / lint / branding) won't auto-run on a sync PR. To get CI as the merge gate, add a repo secret **`UPSTREAM_SYNC_PAT`** (a fine-scoped PAT with `repo` + `workflow`); the workflow uses it automatically. Without it, re-run CI on the sync PR manually.
|
|
35
|
+
|
|
36
|
+
### Caveats
|
|
37
|
+
|
|
38
|
+
- **`contributor-check`** requires every new commit-author email to be in `AUTHOR_MAP` (`scripts/release.py`). A sync that brings in commits from a *new* upstream contributor will fail this check until you add their mapping — the check prints the exact lines to paste.
|
|
39
|
+
- **`history-check`** requires a common ancestor with `main`; a real merge from our shared-history upstream always satisfies it.
|
|
40
|
+
|
|
41
|
+
## Manual sync (by hand)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# one-time
|
|
45
|
+
git remote add upstream https://github.com/NousResearch/hermes-agent.git
|
|
46
|
+
|
|
47
|
+
git fetch --no-tags upstream main
|
|
48
|
+
git switch -c sync/upstream-manual main
|
|
49
|
+
git merge upstream/main
|
|
50
|
+
# resolve any conflicts (usually README.md / .env.example), then:
|
|
51
|
+
git commit
|
|
52
|
+
git push -u origin sync/upstream-manual
|
|
53
|
+
# open a PR into main
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Versioning
|
|
57
|
+
|
|
58
|
+
Tag ClawPump releases off the upstream CalVer base plus a suffix, e.g. `v2026.6.5-clawpump.1`, so it's always clear which upstream snapshot a release is built on.
|
package/agent/hermes_cli/auth.py
CHANGED
|
@@ -531,6 +531,33 @@ def _resolve_kimi_base_url(api_key: str, default_url: str, env_override: str) ->
|
|
|
531
531
|
return default_url
|
|
532
532
|
|
|
533
533
|
|
|
534
|
+
# =============================================================================
|
|
535
|
+
# UsePod Endpoint Derivation
|
|
536
|
+
# =============================================================================
|
|
537
|
+
|
|
538
|
+
# UsePod (usepod.ai) is a drop-in OpenAI-compatible proxy that authenticates by
|
|
539
|
+
# the token embedded in the request PATH — ``/proxy/<token>/v1/...`` — and
|
|
540
|
+
# ignores the Authorization header. The inference base URL is therefore derived
|
|
541
|
+
# from the API key (the token) rather than stored as a static endpoint, so the
|
|
542
|
+
# user only ever needs to paste their token.
|
|
543
|
+
USEPOD_API_BASE = "https://api.usepod.ai"
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def _resolve_usepod_base_url(api_key: str, env_override: str = "") -> str:
|
|
547
|
+
"""Return the UsePod proxy base URL for *api_key* (the token).
|
|
548
|
+
|
|
549
|
+
An explicit ``USEPOD_BASE_URL`` (``env_override``) always wins — e.g. for a
|
|
550
|
+
self-hosted UsePod gateway. With no token yet, return the proxy root so
|
|
551
|
+
callers degrade gracefully instead of producing a malformed URL.
|
|
552
|
+
"""
|
|
553
|
+
if env_override:
|
|
554
|
+
return env_override.rstrip("/")
|
|
555
|
+
token = (api_key or "").strip()
|
|
556
|
+
if not token:
|
|
557
|
+
return f"{USEPOD_API_BASE}/proxy"
|
|
558
|
+
return f"{USEPOD_API_BASE}/proxy/{token}/v1"
|
|
559
|
+
|
|
560
|
+
|
|
534
561
|
|
|
535
562
|
_PLACEHOLDER_SECRET_VALUES = {
|
|
536
563
|
"*",
|
|
@@ -5657,6 +5684,8 @@ def get_api_key_provider_status(provider_id: str) -> Dict[str, Any]:
|
|
|
5657
5684
|
|
|
5658
5685
|
if provider_id in {"kimi-coding", "kimi-coding-cn"}:
|
|
5659
5686
|
base_url = _resolve_kimi_base_url(api_key, pconfig.inference_base_url, env_url)
|
|
5687
|
+
elif provider_id == "usepod":
|
|
5688
|
+
base_url = _resolve_usepod_base_url(api_key, env_url)
|
|
5660
5689
|
elif env_url:
|
|
5661
5690
|
base_url = env_url
|
|
5662
5691
|
else:
|
|
@@ -5848,6 +5877,8 @@ def resolve_api_key_provider_credentials(provider_id: str) -> Dict[str, Any]:
|
|
|
5848
5877
|
base_url = _resolve_kimi_base_url(api_key, pconfig.inference_base_url, env_url)
|
|
5849
5878
|
elif provider_id == "zai":
|
|
5850
5879
|
base_url = _resolve_zai_base_url(api_key, pconfig.inference_base_url, env_url)
|
|
5880
|
+
elif provider_id == "usepod":
|
|
5881
|
+
base_url = _resolve_usepod_base_url(api_key, env_url)
|
|
5851
5882
|
elif env_url:
|
|
5852
5883
|
base_url = env_url.rstrip("/")
|
|
5853
5884
|
else:
|
|
@@ -129,7 +129,10 @@ _UPDATE_CHECK_CACHE_SECONDS = 6 * 3600
|
|
|
129
129
|
# (e.g. nix-built hermes — no local git history to count against).
|
|
130
130
|
UPDATE_AVAILABLE_NO_COUNT = -1
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
try:
|
|
133
|
+
from hermes_cli.distribution import UPDATE_REPO_URL as _UPSTREAM_REPO_URL
|
|
134
|
+
except Exception:
|
|
135
|
+
_UPSTREAM_REPO_URL = "https://github.com/NousResearch/hermes-agent.git"
|
|
133
136
|
|
|
134
137
|
|
|
135
138
|
def _check_via_rev(local_rev: str) -> Optional[int]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""``hermes clawpump`` — one-command install/auth for the ClawPump MCP.
|
|
2
2
|
|
|
3
|
-
ClawPump ships its full feature set (
|
|
3
|
+
ClawPump ships its full feature set (131 tools) as an MCP server, bundled in
|
|
4
4
|
the Hermes catalog as two entries:
|
|
5
5
|
|
|
6
6
|
- ``clawpump`` remote OAuth over Streamable HTTP (browser, paste cpk_*)
|
|
@@ -59,9 +59,10 @@ def _cmd_setup(args) -> int:
|
|
|
59
59
|
print()
|
|
60
60
|
print(color(" ClawPump setup", Colors.GREEN + Colors.BOLD))
|
|
61
61
|
print(color(" ──────────────", Colors.GREEN))
|
|
62
|
-
print(" ClawPump's
|
|
63
|
-
print(" token launch, marketplace, predictions,
|
|
64
|
-
print(" through an MCP server. Two ways
|
|
62
|
+
print(" ClawPump's 131 tools (agents, trading, perps, DCA, lending,")
|
|
63
|
+
print(" token launch, marketplace, predictions, gift cards, agent")
|
|
64
|
+
print(" mail, intelligence) come in through an MCP server. Two ways")
|
|
65
|
+
print(" to connect:")
|
|
65
66
|
print()
|
|
66
67
|
print(f" 1) {color('Remote', Colors.GREEN)} — browser login, paste your cpk_* key (recommended)")
|
|
67
68
|
print(f" 2) {color('Stdio', Colors.GREEN)} — local npx, store the cpk_* key in ~/.hermes/.env")
|
|
@@ -220,7 +221,7 @@ def add_parser(subparsers) -> None:
|
|
|
220
221
|
help="ClawPump (Solana token launch, trading, perps, DeFi) via MCP",
|
|
221
222
|
description=(
|
|
222
223
|
"Install and authenticate the ClawPump MCP server, then manage which "
|
|
223
|
-
"of its
|
|
224
|
+
"of its 131 tools are enabled. Subcommands: setup (default: status), "
|
|
224
225
|
"login, status, tools."
|
|
225
226
|
),
|
|
226
227
|
)
|
|
@@ -741,23 +741,7 @@ DEFAULT_CONFIG = {
|
|
|
741
741
|
"fallback_providers": [],
|
|
742
742
|
"credential_pool_strategies": {},
|
|
743
743
|
"toolsets": ["hermes-cli"],
|
|
744
|
-
|
|
745
|
-
# server (the full ClawPump tool surface) comes pre-wired. On first connect
|
|
746
|
-
# Hermes opens a browser to log in to ClawPump — that one step is per-user
|
|
747
|
-
# auth and cannot be skipped — after which the mcp_clawpump_* tools load
|
|
748
|
-
# automatically. The bundled `clawpump` skill requires explicit user
|
|
749
|
-
# confirmation before any financial/irreversible tool runs. Prune the tool
|
|
750
|
-
# set any time with `hermes mcp configure clawpump`.
|
|
751
|
-
"mcp_servers": {
|
|
752
|
-
"clawpump": {
|
|
753
|
-
# TODO: switch to https://mcp.clawpump.tech/mcp once the DNS CNAME
|
|
754
|
-
# is configured; the custom domain is currently NXDOMAIN, so point
|
|
755
|
-
# at the live Railway domain so a fresh install connects.
|
|
756
|
-
"url": "https://clawpump-mcp-production.up.railway.app/mcp",
|
|
757
|
-
"auth": "oauth",
|
|
758
|
-
"enabled": True,
|
|
759
|
-
},
|
|
760
|
-
},
|
|
744
|
+
"mcp_servers": {},
|
|
761
745
|
"agent": {
|
|
762
746
|
"max_turns": 90,
|
|
763
747
|
# Inactivity timeout for gateway agent execution (seconds).
|
|
@@ -1337,7 +1321,7 @@ DEFAULT_CONFIG = {
|
|
|
1337
1321
|
# failure isn't silent from the UI's perspective. Set false to suppress.
|
|
1338
1322
|
"turn_completion_explainer": True,
|
|
1339
1323
|
"show_cost": False, # Show $ cost in the status bar (off by default)
|
|
1340
|
-
"skin": "
|
|
1324
|
+
"skin": "default", # distribution default (clawpump) applied via distribution.apply_config_overlay
|
|
1341
1325
|
# UI language for static user-facing messages (approval prompts, a
|
|
1342
1326
|
# handful of gateway slash-command replies). Does NOT affect agent
|
|
1343
1327
|
# responses, log lines, tool outputs, or slash-command descriptions.
|
|
@@ -3395,38 +3379,21 @@ OPTIONAL_ENV_VARS = {
|
|
|
3395
3379
|
"password": False,
|
|
3396
3380
|
"category": "setting",
|
|
3397
3381
|
},
|
|
3398
|
-
|
|
3399
|
-
# ── ClawPump (Solana token launch, trading, perps, DeFi) ──
|
|
3400
|
-
# Used by the stdio ClawPump MCP path (`npx @clawpump/agents`, catalog
|
|
3401
|
-
# entry `clawpump-stdio`). The remote OAuth path (`clawpump`) stores
|
|
3402
|
-
# per-user tokens under ~/.hermes/mcp-tokens/ instead and needs no key
|
|
3403
|
-
# here. The ClawPump tools themselves come from the MCP server, not the
|
|
3404
|
-
# native registry, so there's no `tools` list.
|
|
3405
|
-
"CLAWPUMP_API_KEY": {
|
|
3406
|
-
"description": "ClawPump API key (cpk_*) for the ClawPump MCP stdio transport",
|
|
3407
|
-
"prompt": "ClawPump API key (cpk_…)",
|
|
3408
|
-
"url": "https://agents.clawpump.tech/dashboard/api",
|
|
3409
|
-
"password": True,
|
|
3410
|
-
"category": "tools",
|
|
3411
|
-
},
|
|
3412
|
-
"CLAWPUMP_API_URL": {
|
|
3413
|
-
"description": "ClawPump backend URL override (advanced — leave empty for the default)",
|
|
3414
|
-
"prompt": "ClawPump backend URL (leave empty for default)",
|
|
3415
|
-
"url": None,
|
|
3416
|
-
"password": False,
|
|
3417
|
-
"category": "tools",
|
|
3418
|
-
"advanced": True,
|
|
3419
|
-
},
|
|
3420
|
-
"CLAWPUMP_DEFAULT_AGENT": {
|
|
3421
|
-
"description": "Default ClawPump agent id (optional — skips agent-selection prompts)",
|
|
3422
|
-
"prompt": "Default ClawPump agent id (optional)",
|
|
3423
|
-
"url": None,
|
|
3424
|
-
"password": False,
|
|
3425
|
-
"category": "tools",
|
|
3426
|
-
"advanced": True,
|
|
3427
|
-
},
|
|
3428
3382
|
}
|
|
3429
3383
|
|
|
3384
|
+
# ── ClawPump distribution overlay (downstream) ───────────────────────────
|
|
3385
|
+
# Apply ClawPump's defaults (pre-wired MCP server + default skin) and env-var
|
|
3386
|
+
# registry from the downstream-owned overlay, keeping this upstream-owned file
|
|
3387
|
+
# mergeable. No-ops on vanilla Hermes (module/keys absent).
|
|
3388
|
+
try:
|
|
3389
|
+
from hermes_cli import distribution as _distribution
|
|
3390
|
+
|
|
3391
|
+
_distribution.apply_config_overlay(DEFAULT_CONFIG)
|
|
3392
|
+
_distribution.apply_env_var_overlay(OPTIONAL_ENV_VARS)
|
|
3393
|
+
except Exception:
|
|
3394
|
+
pass
|
|
3395
|
+
|
|
3396
|
+
|
|
3430
3397
|
# Tool Gateway env vars are always visible — they're useful for
|
|
3431
3398
|
# self-hosted / custom gateway setups regardless of subscription state.
|
|
3432
3399
|
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""ClawPump distribution overlay (downstream-owned).
|
|
2
|
+
|
|
3
|
+
This module is the single home for everything that makes this distribution
|
|
4
|
+
"ClawPump" rather than vanilla Hermes. Keeping it here -- instead of editing
|
|
5
|
+
upstream-owned files (skin_engine.py, config.py, ...) -- keeps those files
|
|
6
|
+
byte-for-byte mergeable with NousResearch/hermes-agent, so syncing upstream
|
|
7
|
+
stays (near) conflict-free.
|
|
8
|
+
|
|
9
|
+
Every upstream consumer imports this lazily and degrades to vanilla Hermes
|
|
10
|
+
when the module (or a given key) is absent. Keep imports light: config.py
|
|
11
|
+
imports this at startup.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Any, Dict
|
|
17
|
+
|
|
18
|
+
# Default skin for this distribution (vanilla Hermes uses "default").
|
|
19
|
+
DEFAULT_SKIN = "clawpump"
|
|
20
|
+
|
|
21
|
+
# Git remote the in-app update check compares against (vanilla Hermes uses
|
|
22
|
+
# NousResearch/hermes-agent).
|
|
23
|
+
UPDATE_REPO_URL = "https://github.com/Clawpump/claw-agent.git"
|
|
24
|
+
|
|
25
|
+
# Extra top-level CLI subcommands this distribution adds (kept in sync with
|
|
26
|
+
# main.py's _BUILTIN_SUBCOMMANDS validation set via a hook there).
|
|
27
|
+
EXTRA_SUBCOMMANDS = ("clawpump",)
|
|
28
|
+
|
|
29
|
+
# ── Skins shipped by this distribution ───────────────────────────────────
|
|
30
|
+
# Moved verbatim out of hermes_cli/skin_engine.py:_BUILTIN_SKINS and merged
|
|
31
|
+
# back into that dict by a small hook there, so every skin consumer
|
|
32
|
+
# (list_skins / load_skin / get_active_skin) sees it unchanged.
|
|
33
|
+
BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
|
|
34
|
+
"clawpump": {
|
|
35
|
+
"name": "clawpump",
|
|
36
|
+
"description": "ClawPump — Solana green, claw mark (built on Hermes)",
|
|
37
|
+
"colors": {
|
|
38
|
+
"banner_border": "#16A34A",
|
|
39
|
+
"banner_title": "#4ADE80",
|
|
40
|
+
"banner_accent": "#22C55E",
|
|
41
|
+
"banner_dim": "#15803D",
|
|
42
|
+
"banner_text": "#DCFCE7",
|
|
43
|
+
"ui_accent": "#22C55E",
|
|
44
|
+
"ui_label": "#4ADE80",
|
|
45
|
+
"ui_ok": "#22C55E",
|
|
46
|
+
"ui_error": "#ef5350",
|
|
47
|
+
"ui_warn": "#ffa726",
|
|
48
|
+
"prompt": "#DCFCE7",
|
|
49
|
+
"input_rule": "#16A34A",
|
|
50
|
+
"response_border": "#4ADE80",
|
|
51
|
+
"status_bar_bg": "#0B1F14",
|
|
52
|
+
"status_bar_text": "#DCFCE7",
|
|
53
|
+
"status_bar_strong": "#4ADE80",
|
|
54
|
+
"status_bar_dim": "#3F6B50",
|
|
55
|
+
"status_bar_good": "#22C55E",
|
|
56
|
+
"status_bar_warn": "#FACC15",
|
|
57
|
+
"status_bar_bad": "#F59E0B",
|
|
58
|
+
"status_bar_critical": "#EF5350",
|
|
59
|
+
"session_label": "#4ADE80",
|
|
60
|
+
"session_border": "#3F6B50",
|
|
61
|
+
"selection_bg": "#14532D",
|
|
62
|
+
"completion_menu_bg": "#06140C",
|
|
63
|
+
"completion_menu_current_bg": "#14532D",
|
|
64
|
+
"completion_menu_meta_bg": "#0B1F14",
|
|
65
|
+
"completion_menu_meta_current_bg": "#14532D",
|
|
66
|
+
},
|
|
67
|
+
"spinner": {
|
|
68
|
+
"waiting_faces": ["(◴)", "(◷)", "(◶)", "(◵)", "(<>)"],
|
|
69
|
+
"thinking_faces": ["(✦)", "(◇)", "(◈)", "(⌁)", "(<>)"],
|
|
70
|
+
"thinking_verbs": [
|
|
71
|
+
"pumping", "launching", "scanning the mints", "routing the swap",
|
|
72
|
+
"reading the chart", "minting", "snapping the claw", "checking liquidity",
|
|
73
|
+
],
|
|
74
|
+
"wings": [
|
|
75
|
+
["⟪◇", "◇⟫"],
|
|
76
|
+
["⟪✦", "✦⟫"],
|
|
77
|
+
["⟪>", "<⟫"],
|
|
78
|
+
["⟪◈", "◈⟫"],
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
"branding": {
|
|
82
|
+
"agent_name": "ClawPump",
|
|
83
|
+
"org": "ClawPump",
|
|
84
|
+
"credit": "built on Hermes ☤ by Nous Research",
|
|
85
|
+
"welcome": "Welcome to ClawPump 🦀 — Solana agents, trading & token launch. Type your message or /help for commands.",
|
|
86
|
+
"goodbye": "Claws out! 🦀",
|
|
87
|
+
"response_label": " ✦ ClawPump ",
|
|
88
|
+
"prompt_symbol": "❯",
|
|
89
|
+
"help_header": "(✦) Available Commands",
|
|
90
|
+
},
|
|
91
|
+
"tool_prefix": "┊",
|
|
92
|
+
"banner_logo": """[bold #86EFAC] ██████╗██╗ █████╗ ██╗ ██╗██████╗ ██╗ ██╗███╗ ███╗██████╗ [/]
|
|
93
|
+
[bold #4ADE80]██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██║ ██║████╗ ████║██╔══██╗[/]
|
|
94
|
+
[#22C55E]██║ ██║ ███████║██║ █╗ ██║██████╔╝██║ ██║██╔████╔██║██████╔╝[/]
|
|
95
|
+
[#16A34A]██║ ██║ ██╔══██║██║███╗██║██╔═══╝ ██║ ██║██║╚██╔╝██║██╔═══╝ [/]
|
|
96
|
+
[#15803D]╚██████╗███████╗██║ ██║╚███╔███╔╝██║ ╚██████╔╝██║ ╚═╝ ██║██║ [/]
|
|
97
|
+
[#166534] ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ [/]""",
|
|
98
|
+
"banner_hero": """[#86EFAC]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣀⣂⣤⣤⣤⣤⣤⣤⠄[/]
|
|
99
|
+
[#7EE5A4]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣢⣵⣾⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀[/]
|
|
100
|
+
[#77DA9B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣴⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀[/]
|
|
101
|
+
[#6FD093]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⠟⠁⢀⣼⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀[/]
|
|
102
|
+
[#68C58A]⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣜⡿⠁⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⠗⠀⠀⠀⠀⠀[/]
|
|
103
|
+
[#60BB82]⠀⠀⠀⠀⠀⠀⠀⠀⢀⣮⣿⣇⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀[/]
|
|
104
|
+
[#58B179]⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠃⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀[/]
|
|
105
|
+
[#51A671]⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀[/]
|
|
106
|
+
[#499C68]⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
|
|
107
|
+
[#429160]⠀⠀⠀⠀⠀⣀⣈⡙⠻⢿⣿⣿⣿⣿⣿⣿⡿⠋⣡⣤⣤⠀⠀⠀⠀⠀⠐⢀⣠⣴[/]
|
|
108
|
+
[#3A8757]⠀⠀⠀⢀⣞⣿⠟⠉⣷⣦⣌⠙⢿⣿⣿⣿⣠⣾⣿⣿⣿⣷⣷⣶⣶⣶⣿⣿⣿⠃[/]
|
|
109
|
+
[#327D4F]⠀⠀⣀⣉⡛⠳⢴⣾⣿⣿⣿⣷⣄⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀[/]
|
|
110
|
+
[#2B7246]⢠⣞⣿⡟⣩⣿⣶⣌⠻⢿⣿⣿⣿⣆⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀[/]
|
|
111
|
+
[#23683E]⠀⠉⠙⠻⢿⣿⣿⣿⣷⣄⠻⣿⣿⣿⡀⠹⢿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀[/]
|
|
112
|
+
[#1C5D35]⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣆⠹⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
|
|
113
|
+
[#14532D]⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]""",
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ── Default-config overlay ───────────────────────────────────────────────
|
|
119
|
+
# ClawPump ships its remote MCP server pre-wired and the clawpump skin as the
|
|
120
|
+
# default brand. Applied onto DEFAULT_CONFIG by a hook in config.py.
|
|
121
|
+
_CLAWPUMP_MCP_SERVER = {
|
|
122
|
+
# TODO: switch to https://mcp.clawpump.tech/mcp once the DNS CNAME is
|
|
123
|
+
# configured; the custom domain is currently NXDOMAIN, so point at the
|
|
124
|
+
# live Railway domain so a fresh install connects.
|
|
125
|
+
"url": "https://clawpump-mcp-production.up.railway.app/mcp",
|
|
126
|
+
"auth": "oauth",
|
|
127
|
+
"enabled": True,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def apply_config_overlay(default_config: Dict[str, Any]) -> None:
|
|
132
|
+
"""Apply ClawPump defaults onto a freshly-built DEFAULT_CONFIG.
|
|
133
|
+
|
|
134
|
+
Pre-wires the remote ClawPump MCP server (the full tool surface; first
|
|
135
|
+
connect opens a browser for per-user OAuth, after which the mcp_clawpump_*
|
|
136
|
+
tools load automatically -- prune with ``hermes mcp configure clawpump``)
|
|
137
|
+
and makes the clawpump skin the default brand. Idempotent.
|
|
138
|
+
"""
|
|
139
|
+
servers = default_config.setdefault("mcp_servers", {})
|
|
140
|
+
if isinstance(servers, dict):
|
|
141
|
+
servers.setdefault("clawpump", dict(_CLAWPUMP_MCP_SERVER))
|
|
142
|
+
display = default_config.get("display")
|
|
143
|
+
if isinstance(display, dict):
|
|
144
|
+
display["skin"] = DEFAULT_SKIN
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ── OPTIONAL_ENV_VARS overlay ────────────────────────────────────────────
|
|
148
|
+
# ClawPump (Solana token launch, trading, perps, DeFi). Used by the stdio
|
|
149
|
+
# ClawPump MCP path (``npx @clawpump/agents``, catalog entry
|
|
150
|
+
# ``clawpump-stdio``). The remote OAuth path (``clawpump``) stores per-user
|
|
151
|
+
# tokens under ~/.hermes/mcp-tokens/ instead and needs no key here.
|
|
152
|
+
_CLAWPUMP_ENV_VARS: Dict[str, Dict[str, Any]] = {
|
|
153
|
+
"CLAWPUMP_API_KEY": {
|
|
154
|
+
"description": "ClawPump API key (cpk_*) for the ClawPump MCP stdio transport",
|
|
155
|
+
"prompt": "ClawPump API key (cpk_…)",
|
|
156
|
+
"url": "https://agents.clawpump.tech/dashboard/api",
|
|
157
|
+
"password": True,
|
|
158
|
+
"category": "tools",
|
|
159
|
+
},
|
|
160
|
+
"CLAWPUMP_API_URL": {
|
|
161
|
+
"description": "ClawPump backend URL override (advanced — leave empty for the default)",
|
|
162
|
+
"prompt": "ClawPump backend URL (leave empty for default)",
|
|
163
|
+
"url": None,
|
|
164
|
+
"password": False,
|
|
165
|
+
"category": "tools",
|
|
166
|
+
"advanced": True,
|
|
167
|
+
},
|
|
168
|
+
"CLAWPUMP_DEFAULT_AGENT": {
|
|
169
|
+
"description": "Default ClawPump agent id (optional — skips agent-selection prompts)",
|
|
170
|
+
"prompt": "Default ClawPump agent id (optional)",
|
|
171
|
+
"url": None,
|
|
172
|
+
"password": False,
|
|
173
|
+
"category": "tools",
|
|
174
|
+
"advanced": True,
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def apply_env_var_overlay(optional_env_vars: Dict[str, Any]) -> None:
|
|
180
|
+
"""Register ClawPump's env vars into config.OPTIONAL_ENV_VARS. Idempotent."""
|
|
181
|
+
for name, spec in _CLAWPUMP_ENV_VARS.items():
|
|
182
|
+
optional_env_vars.setdefault(name, dict(spec))
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# ── CLI integration ──────────────────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def register_subparsers(subparsers) -> None:
|
|
189
|
+
"""Register distribution-specific CLI subcommands.
|
|
190
|
+
|
|
191
|
+
Wires the ``clawpump`` command (ClawPump MCP install / auth / tool
|
|
192
|
+
selection) onto the top-level argparse subparsers.
|
|
193
|
+
"""
|
|
194
|
+
from hermes_cli.clawpump_cli import add_parser as _add_clawpump_parser
|
|
195
|
+
|
|
196
|
+
_add_clawpump_parser(subparsers)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def try_self_update(project_root: Any) -> bool:
|
|
200
|
+
"""Handle distribution-specific self-update; return True if handled.
|
|
201
|
+
|
|
202
|
+
ClawPump agents installed via ``npx @clawpump/claw-agent`` have no git
|
|
203
|
+
checkout (the bundle ships inside the npm package), so the normal git-pull
|
|
204
|
+
update can't apply -- re-run the npm installer instead. Returns False when
|
|
205
|
+
this isn't an npm-bundle install, so the caller falls through to the
|
|
206
|
+
standard (git / pip / docker) update paths.
|
|
207
|
+
"""
|
|
208
|
+
from pathlib import Path
|
|
209
|
+
|
|
210
|
+
if not (Path(project_root) / ".claw-bundle").exists():
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
import shutil
|
|
214
|
+
import subprocess
|
|
215
|
+
import sys
|
|
216
|
+
|
|
217
|
+
print("→ Updating ClawPump agent via npm (npx @clawpump/claw-agent@latest)…")
|
|
218
|
+
npx = shutil.which("npx")
|
|
219
|
+
if not npx:
|
|
220
|
+
print("✗ npx (Node.js) not found. Install Node.js, then run:")
|
|
221
|
+
print(" npx @clawpump/claw-agent@latest")
|
|
222
|
+
sys.exit(1)
|
|
223
|
+
try:
|
|
224
|
+
subprocess.run([npx, "-y", "@clawpump/claw-agent@latest"], check=True)
|
|
225
|
+
except subprocess.CalledProcessError as exc:
|
|
226
|
+
print(f"✗ Update failed (exit {exc.returncode}). Try manually:")
|
|
227
|
+
print(" npx @clawpump/claw-agent@latest")
|
|
228
|
+
sys.exit(1)
|
|
229
|
+
print("✓ ClawPump agent updated. Restart your session with `claw`.")
|
|
230
|
+
return True
|
package/agent/hermes_cli/main.py
CHANGED
|
@@ -5806,19 +5806,31 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|
|
5806
5806
|
pass
|
|
5807
5807
|
effective_base = current_base or pconfig.inference_base_url
|
|
5808
5808
|
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
)
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5809
|
+
if provider_id == "usepod":
|
|
5810
|
+
# UsePod authenticates by the token embedded in the URL path, so there
|
|
5811
|
+
# is no base URL for the user to type — it is derived from the pasted
|
|
5812
|
+
# key. Skip the prompt; honour USEPOD_BASE_URL only for self-hosting.
|
|
5813
|
+
from hermes_cli.auth import _resolve_usepod_base_url
|
|
5814
|
+
|
|
5815
|
+
key_for_probe = existing_key or (get_env_value(key_env) if key_env else "")
|
|
5816
|
+
env_override = ""
|
|
5817
|
+
if base_url_env:
|
|
5818
|
+
env_override = get_env_value(base_url_env) or os.getenv(base_url_env, "")
|
|
5819
|
+
effective_base = _resolve_usepod_base_url(key_for_probe, env_override)
|
|
5820
|
+
else:
|
|
5821
|
+
try:
|
|
5822
|
+
override = input(f"Base URL [{effective_base}]: ").strip()
|
|
5823
|
+
except (KeyboardInterrupt, EOFError):
|
|
5824
|
+
print()
|
|
5825
|
+
override = ""
|
|
5826
|
+
if override and base_url_env:
|
|
5827
|
+
if not override.startswith(("http://", "https://")):
|
|
5828
|
+
print(
|
|
5829
|
+
" Invalid URL — must start with http:// or https://. Keeping current value."
|
|
5830
|
+
)
|
|
5831
|
+
else:
|
|
5832
|
+
save_env_value(base_url_env, override)
|
|
5833
|
+
effective_base = override
|
|
5822
5834
|
|
|
5823
5835
|
# Model selection — resolution order:
|
|
5824
5836
|
# 1. models.dev registry (cached, filtered for agentic/tool-capable models)
|
|
@@ -5857,6 +5869,22 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|
|
5857
5869
|
)
|
|
5858
5870
|
if model_list:
|
|
5859
5871
|
print(f" Found {len(model_list)} model(s) from Ollama Cloud")
|
|
5872
|
+
elif provider_id == "usepod":
|
|
5873
|
+
from hermes_cli.models import fetch_api_models
|
|
5874
|
+
from providers import get_provider_profile
|
|
5875
|
+
|
|
5876
|
+
api_key_for_probe = existing_key or (get_env_value(key_env) if key_env else "")
|
|
5877
|
+
live_models = fetch_api_models(api_key_for_probe, effective_base)
|
|
5878
|
+
if live_models:
|
|
5879
|
+
model_list = live_models
|
|
5880
|
+
print(f" Found {len(model_list)} model(s) from {pconfig.name} API")
|
|
5881
|
+
else:
|
|
5882
|
+
_pp = get_provider_profile("usepod")
|
|
5883
|
+
model_list = list(getattr(_pp, "fallback_models", ()) or [])
|
|
5884
|
+
if model_list:
|
|
5885
|
+
print(
|
|
5886
|
+
f' Showing {len(model_list)} curated models — use "Enter custom model name" for others.'
|
|
5887
|
+
)
|
|
5860
5888
|
elif provider_id == "novita":
|
|
5861
5889
|
from hermes_cli.models import fetch_api_models
|
|
5862
5890
|
|
|
@@ -5964,7 +5992,13 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
|
|
5964
5992
|
model = {"default": model} if model else {}
|
|
5965
5993
|
cfg["model"] = model
|
|
5966
5994
|
model["provider"] = provider_id
|
|
5967
|
-
|
|
5995
|
+
if provider_id == "usepod":
|
|
5996
|
+
# The effective base URL embeds the token; persisting it would bake
|
|
5997
|
+
# the secret into config.yaml and go stale on key rotation. Runtime
|
|
5998
|
+
# always re-derives it from the current USEPOD_API_KEY.
|
|
5999
|
+
model.pop("base_url", None)
|
|
6000
|
+
else:
|
|
6001
|
+
model["base_url"] = effective_base
|
|
5968
6002
|
if provider_id in {"opencode-zen", "opencode-go"}:
|
|
5969
6003
|
model["api_mode"] = opencode_model_api_mode(provider_id, selected)
|
|
5970
6004
|
else:
|
|
@@ -9197,6 +9231,15 @@ def cmd_update(args):
|
|
|
9197
9231
|
managed_error("update Hermes Agent")
|
|
9198
9232
|
return
|
|
9199
9233
|
|
|
9234
|
+
# Distribution-specific self-update (e.g. ClawPump's npm bundle, which has
|
|
9235
|
+
# no git checkout to pull). No-op on vanilla Hermes.
|
|
9236
|
+
try:
|
|
9237
|
+
from hermes_cli import distribution as _distribution
|
|
9238
|
+
except Exception:
|
|
9239
|
+
_distribution = None
|
|
9240
|
+
if _distribution is not None and _distribution.try_self_update(PROJECT_ROOT):
|
|
9241
|
+
return
|
|
9242
|
+
|
|
9200
9243
|
# Docker users can't ``git pull`` — the image excludes ``.git`` from
|
|
9201
9244
|
# the build context. Bail with a friendly explanation pointing at
|
|
9202
9245
|
# ``docker pull`` BEFORE any of the apply-path / check-path branches
|
|
@@ -11457,7 +11500,7 @@ def cmd_logs(args):
|
|
|
11457
11500
|
# to parse.
|
|
11458
11501
|
_BUILTIN_SUBCOMMANDS = frozenset(
|
|
11459
11502
|
{
|
|
11460
|
-
"acp", "auth", "backup", "bundles", "checkpoints", "claw", "
|
|
11503
|
+
"acp", "auth", "backup", "bundles", "checkpoints", "claw", "completion",
|
|
11461
11504
|
"computer-use",
|
|
11462
11505
|
"config", "cron", "curator", "dashboard", "debug", "doctor",
|
|
11463
11506
|
"dump", "fallback", "gateway", "hooks", "import", "insights",
|
|
@@ -11474,6 +11517,14 @@ _BUILTIN_SUBCOMMANDS = frozenset(
|
|
|
11474
11517
|
}
|
|
11475
11518
|
)
|
|
11476
11519
|
|
|
11520
|
+
# Distribution-specific subcommands (e.g. ClawPump). No-op on vanilla Hermes.
|
|
11521
|
+
try:
|
|
11522
|
+
from hermes_cli import distribution as _distribution
|
|
11523
|
+
|
|
11524
|
+
_BUILTIN_SUBCOMMANDS = _BUILTIN_SUBCOMMANDS | frozenset(_distribution.EXTRA_SUBCOMMANDS)
|
|
11525
|
+
except Exception:
|
|
11526
|
+
pass
|
|
11527
|
+
|
|
11477
11528
|
|
|
11478
11529
|
# Top-level flags that take a value. Needed by ``_first_positional_argv``
|
|
11479
11530
|
# so that in ``hermes -m gpt5 chat``, ``gpt5`` is correctly skipped as a
|
|
@@ -12754,10 +12805,14 @@ def main():
|
|
|
12754
12805
|
_add_portal_parser(subparsers)
|
|
12755
12806
|
|
|
12756
12807
|
# =========================================================================
|
|
12757
|
-
#
|
|
12808
|
+
# Distribution-specific subcommands (e.g. ClawPump). No-op on vanilla Hermes.
|
|
12758
12809
|
# =========================================================================
|
|
12759
|
-
|
|
12760
|
-
|
|
12810
|
+
try:
|
|
12811
|
+
from hermes_cli import distribution as _distribution
|
|
12812
|
+
except Exception:
|
|
12813
|
+
_distribution = None
|
|
12814
|
+
if _distribution is not None:
|
|
12815
|
+
_distribution.register_subparsers(subparsers)
|
|
12761
12816
|
|
|
12762
12817
|
# =========================================================================
|
|
12763
12818
|
# kanban command — multi-profile collaboration board
|
|
@@ -368,6 +368,19 @@ def _resolve_runtime_from_pool_entry(
|
|
|
368
368
|
# For Anthropic-style endpoints, strip /v1 suffix
|
|
369
369
|
if api_mode == "anthropic_messages":
|
|
370
370
|
base_url = re.sub(r"/v1/?$", "", base_url)
|
|
371
|
+
elif provider == "usepod":
|
|
372
|
+
# UsePod authenticates by the token in the URL path, so the pool
|
|
373
|
+
# entry's base_url is only the proxy root — derive the real per-token
|
|
374
|
+
# base URL from the resolved key. A config base_url or USEPOD_BASE_URL
|
|
375
|
+
# (self-hosted gateway) still wins.
|
|
376
|
+
from hermes_cli.auth import _resolve_usepod_base_url
|
|
377
|
+
cfg_provider = str(model_cfg.get("provider") or "").strip().lower()
|
|
378
|
+
cfg_base_url = ""
|
|
379
|
+
if cfg_provider == "usepod":
|
|
380
|
+
cfg_base_url = str(model_cfg.get("base_url") or "").strip().rstrip("/")
|
|
381
|
+
env_override = os.getenv("USEPOD_BASE_URL", "").strip()
|
|
382
|
+
base_url = cfg_base_url or _resolve_usepod_base_url(api_key, env_override).rstrip("/")
|
|
383
|
+
api_mode = "chat_completions"
|
|
371
384
|
else:
|
|
372
385
|
configured_provider = str(model_cfg.get("provider") or "").strip().lower()
|
|
373
386
|
# Honour model.base_url from config.yaml when the configured provider
|
|
@@ -1165,6 +1178,11 @@ def _resolve_explicit_runtime(
|
|
|
1165
1178
|
if provider in {"kimi-coding", "kimi-coding-cn"}:
|
|
1166
1179
|
creds = resolve_api_key_provider_credentials(provider)
|
|
1167
1180
|
base_url = creds.get("base_url", "").rstrip("/")
|
|
1181
|
+
elif provider == "usepod":
|
|
1182
|
+
# UsePod embeds the token in the URL path; defer base_url until
|
|
1183
|
+
# the token is resolved below so it always reflects the current
|
|
1184
|
+
# key (covers explicit --api-key overrides too).
|
|
1185
|
+
base_url = ""
|
|
1168
1186
|
else:
|
|
1169
1187
|
base_url = env_url or pconfig.inference_base_url
|
|
1170
1188
|
|
|
@@ -1175,6 +1193,12 @@ def _resolve_explicit_runtime(
|
|
|
1175
1193
|
if not base_url:
|
|
1176
1194
|
base_url = creds.get("base_url", "").rstrip("/")
|
|
1177
1195
|
|
|
1196
|
+
if provider == "usepod" and not explicit_base_url:
|
|
1197
|
+
# Derive the proxy base URL from the resolved token. An explicit
|
|
1198
|
+
# --base-url (or USEPOD_BASE_URL, carried via env_url) still wins.
|
|
1199
|
+
from hermes_cli.auth import _resolve_usepod_base_url
|
|
1200
|
+
base_url = _resolve_usepod_base_url(api_key, env_url).rstrip("/")
|
|
1201
|
+
|
|
1178
1202
|
api_mode = "chat_completions"
|
|
1179
1203
|
if provider == "copilot":
|
|
1180
1204
|
api_mode = _copilot_runtime_api_mode(model_cfg, api_key)
|
|
@@ -196,87 +196,6 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
|
|
|
196
196
|
},
|
|
197
197
|
"tool_prefix": "┊",
|
|
198
198
|
},
|
|
199
|
-
"clawpump": {
|
|
200
|
-
"name": "clawpump",
|
|
201
|
-
"description": "ClawPump — Solana green, claw mark (built on Hermes)",
|
|
202
|
-
"colors": {
|
|
203
|
-
"banner_border": "#16A34A",
|
|
204
|
-
"banner_title": "#4ADE80",
|
|
205
|
-
"banner_accent": "#22C55E",
|
|
206
|
-
"banner_dim": "#15803D",
|
|
207
|
-
"banner_text": "#DCFCE7",
|
|
208
|
-
"ui_accent": "#22C55E",
|
|
209
|
-
"ui_label": "#4ADE80",
|
|
210
|
-
"ui_ok": "#22C55E",
|
|
211
|
-
"ui_error": "#ef5350",
|
|
212
|
-
"ui_warn": "#ffa726",
|
|
213
|
-
"prompt": "#DCFCE7",
|
|
214
|
-
"input_rule": "#16A34A",
|
|
215
|
-
"response_border": "#4ADE80",
|
|
216
|
-
"status_bar_bg": "#0B1F14",
|
|
217
|
-
"status_bar_text": "#DCFCE7",
|
|
218
|
-
"status_bar_strong": "#4ADE80",
|
|
219
|
-
"status_bar_dim": "#3F6B50",
|
|
220
|
-
"status_bar_good": "#22C55E",
|
|
221
|
-
"status_bar_warn": "#FACC15",
|
|
222
|
-
"status_bar_bad": "#F59E0B",
|
|
223
|
-
"status_bar_critical": "#EF5350",
|
|
224
|
-
"session_label": "#4ADE80",
|
|
225
|
-
"session_border": "#3F6B50",
|
|
226
|
-
"selection_bg": "#14532D",
|
|
227
|
-
"completion_menu_bg": "#06140C",
|
|
228
|
-
"completion_menu_current_bg": "#14532D",
|
|
229
|
-
"completion_menu_meta_bg": "#0B1F14",
|
|
230
|
-
"completion_menu_meta_current_bg": "#14532D",
|
|
231
|
-
},
|
|
232
|
-
"spinner": {
|
|
233
|
-
"waiting_faces": ["(◴)", "(◷)", "(◶)", "(◵)", "(<>)"],
|
|
234
|
-
"thinking_faces": ["(✦)", "(◇)", "(◈)", "(⌁)", "(<>)"],
|
|
235
|
-
"thinking_verbs": [
|
|
236
|
-
"pumping", "launching", "scanning the mints", "routing the swap",
|
|
237
|
-
"reading the chart", "minting", "snapping the claw", "checking liquidity",
|
|
238
|
-
],
|
|
239
|
-
"wings": [
|
|
240
|
-
["⟪◇", "◇⟫"],
|
|
241
|
-
["⟪✦", "✦⟫"],
|
|
242
|
-
["⟪>", "<⟫"],
|
|
243
|
-
["⟪◈", "◈⟫"],
|
|
244
|
-
],
|
|
245
|
-
},
|
|
246
|
-
"branding": {
|
|
247
|
-
"agent_name": "ClawPump",
|
|
248
|
-
"org": "ClawPump",
|
|
249
|
-
"credit": "built on Hermes ☤ by Nous Research",
|
|
250
|
-
"welcome": "Welcome to ClawPump 🦀 — Solana agents, trading & token launch. Type your message or /help for commands.",
|
|
251
|
-
"goodbye": "Claws out! 🦀",
|
|
252
|
-
"response_label": " ✦ ClawPump ",
|
|
253
|
-
"prompt_symbol": "❯",
|
|
254
|
-
"help_header": "(✦) Available Commands",
|
|
255
|
-
},
|
|
256
|
-
"tool_prefix": "┊",
|
|
257
|
-
"banner_logo": """[bold #86EFAC] ██████╗██╗ █████╗ ██╗ ██╗██████╗ ██╗ ██╗███╗ ███╗██████╗ [/]
|
|
258
|
-
[bold #4ADE80]██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██║ ██║████╗ ████║██╔══██╗[/]
|
|
259
|
-
[#22C55E]██║ ██║ ███████║██║ █╗ ██║██████╔╝██║ ██║██╔████╔██║██████╔╝[/]
|
|
260
|
-
[#16A34A]██║ ██║ ██╔══██║██║███╗██║██╔═══╝ ██║ ██║██║╚██╔╝██║██╔═══╝ [/]
|
|
261
|
-
[#15803D]╚██████╗███████╗██║ ██║╚███╔███╔╝██║ ╚██████╔╝██║ ╚═╝ ██║██║ [/]
|
|
262
|
-
[#166534] ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ [/]""",
|
|
263
|
-
"banner_hero": """[#86EFAC]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣀⣂⣤⣤⣤⣤⣤⣤⠄[/]
|
|
264
|
-
[#7EE5A4]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣢⣵⣾⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀[/]
|
|
265
|
-
[#77DA9B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣴⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⠀[/]
|
|
266
|
-
[#6FD093]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⠟⠁⢀⣼⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀[/]
|
|
267
|
-
[#68C58A]⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣜⡿⠁⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⠗⠀⠀⠀⠀⠀[/]
|
|
268
|
-
[#60BB82]⠀⠀⠀⠀⠀⠀⠀⠀⢀⣮⣿⣇⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀[/]
|
|
269
|
-
[#58B179]⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠃⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀[/]
|
|
270
|
-
[#51A671]⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀[/]
|
|
271
|
-
[#499C68]⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
|
|
272
|
-
[#429160]⠀⠀⠀⠀⠀⣀⣈⡙⠻⢿⣿⣿⣿⣿⣿⣿⡿⠋⣡⣤⣤⠀⠀⠀⠀⠀⠐⢀⣠⣴[/]
|
|
273
|
-
[#3A8757]⠀⠀⠀⢀⣞⣿⠟⠉⣷⣦⣌⠙⢿⣿⣿⣿⣠⣾⣿⣿⣿⣷⣷⣶⣶⣶⣿⣿⣿⠃[/]
|
|
274
|
-
[#327D4F]⠀⠀⣀⣉⡛⠳⢴⣾⣿⣿⣿⣷⣄⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀[/]
|
|
275
|
-
[#2B7246]⢠⣞⣿⡟⣩⣿⣶⣌⠻⢿⣿⣿⣿⣆⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀[/]
|
|
276
|
-
[#23683E]⠀⠉⠙⠻⢿⣿⣿⣿⣷⣄⠻⣿⣿⣿⡀⠹⢿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀[/]
|
|
277
|
-
[#1C5D35]⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣆⠹⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
|
|
278
|
-
[#14532D]⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]""",
|
|
279
|
-
},
|
|
280
199
|
"ares": {
|
|
281
200
|
"name": "ares",
|
|
282
201
|
"description": "War-god theme — crimson and bronze",
|
|
@@ -730,8 +649,21 @@ _BUILTIN_SKINS: Dict[str, Dict[str, Any]] = {
|
|
|
730
649
|
# Skin loading and management
|
|
731
650
|
# =============================================================================
|
|
732
651
|
|
|
652
|
+
# -- ClawPump distribution overlay (downstream) ---------------------------
|
|
653
|
+
# Pull ClawPump's skins + default-skin name from the downstream-owned
|
|
654
|
+
# overlay so this upstream-owned file stays mergeable. Falls back to
|
|
655
|
+
# vanilla Hermes ("default") when the overlay module is absent.
|
|
656
|
+
try:
|
|
657
|
+
from hermes_cli.distribution import (
|
|
658
|
+
BUILTIN_SKINS as _DIST_SKINS,
|
|
659
|
+
DEFAULT_SKIN as _DISTRIBUTION_DEFAULT_SKIN,
|
|
660
|
+
)
|
|
661
|
+
_BUILTIN_SKINS.update(_DIST_SKINS)
|
|
662
|
+
except Exception:
|
|
663
|
+
_DISTRIBUTION_DEFAULT_SKIN = "default"
|
|
664
|
+
|
|
733
665
|
_active_skin: Optional[SkinConfig] = None
|
|
734
|
-
_active_skin_name: str =
|
|
666
|
+
_active_skin_name: str = _DISTRIBUTION_DEFAULT_SKIN
|
|
735
667
|
|
|
736
668
|
|
|
737
669
|
def _skins_dir() -> Path:
|
|
@@ -876,11 +808,11 @@ def init_skin_from_config(config: dict) -> None:
|
|
|
876
808
|
display = config.get("display") or {}
|
|
877
809
|
if not isinstance(display, dict):
|
|
878
810
|
display = {}
|
|
879
|
-
skin_name = display.get("skin",
|
|
811
|
+
skin_name = display.get("skin", _DISTRIBUTION_DEFAULT_SKIN)
|
|
880
812
|
if isinstance(skin_name, str) and skin_name.strip():
|
|
881
813
|
set_active_skin(skin_name.strip())
|
|
882
814
|
else:
|
|
883
|
-
set_active_skin(
|
|
815
|
+
set_active_skin(_DISTRIBUTION_DEFAULT_SKIN)
|
|
884
816
|
|
|
885
817
|
|
|
886
818
|
# =============================================================================
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
manifest_version: 1
|
|
4
4
|
|
|
5
5
|
name: clawpump
|
|
6
|
-
description: ClawPump — Solana AI agents, trading, perps, DCA, token launch, marketplace, lending, predictions, market intelligence (
|
|
6
|
+
description: ClawPump — Solana AI agents, trading, perps, DCA, token launch, marketplace, lending, predictions, gift cards, agent mail, x402 paid APIs, market intelligence (131 tools).
|
|
7
7
|
source: https://mcp.clawpump.tech
|
|
8
8
|
|
|
9
9
|
# ClawPump ships a remote MCP server: Streamable HTTP + native OAuth 2.1 +
|
|
@@ -29,11 +29,13 @@ auth:
|
|
|
29
29
|
# first probe / first connect.
|
|
30
30
|
|
|
31
31
|
# Tool selection at install time.
|
|
32
|
-
# ClawPump exposes
|
|
32
|
+
# ClawPump exposes 131 tools; 37 of them move real funds or are irreversible
|
|
33
33
|
# (perps orders, swaps, DCA/limit orders, lending deposit/withdraw, prediction
|
|
34
|
-
# positions, marketplace bids, external-wallet changes,
|
|
34
|
+
# positions, marketplace bids, external-wallet changes, wallet transfers,
|
|
35
|
+
# token launches, gift-card purchases/withdrawals, agent-mail
|
|
36
|
+
# provisioning/sending, x402 paid-API execution).
|
|
35
37
|
# Hermes does NOT auto-gate MCP tools by their destructiveHint, so we ship a
|
|
36
|
-
# read-mostly default: the
|
|
38
|
+
# read-mostly default: the 94 safe tools below are pre-checked in the install
|
|
37
39
|
# checklist (and applied directly if the server can't be probed before auth).
|
|
38
40
|
# Users opt into the financial tools per their threat model in the checklist,
|
|
39
41
|
# or later with `hermes mcp configure clawpump`.
|
|
@@ -54,6 +56,23 @@ tools:
|
|
|
54
56
|
- upload_agent_avatar
|
|
55
57
|
- get_agent_asset_url
|
|
56
58
|
- list_available_skills
|
|
59
|
+
# agent cards (Laso — reads / linking / quotes; purchase & withdraw are opt-in)
|
|
60
|
+
- agent_card_list
|
|
61
|
+
- agent_card_get
|
|
62
|
+
- agent_card_status
|
|
63
|
+
- agent_card_balance
|
|
64
|
+
- agent_card_data
|
|
65
|
+
- agent_card_withdrawals
|
|
66
|
+
- agent_card_quote
|
|
67
|
+
- agent_card_refresh
|
|
68
|
+
- agent_card_search_gift_cards
|
|
69
|
+
- agent_card_search_merchants
|
|
70
|
+
- agent_card_connect
|
|
71
|
+
- agent_card_connect_link
|
|
72
|
+
# agent mail (reads; inbox provisioning & sending are opt-in)
|
|
73
|
+
- agent_mail_get_address
|
|
74
|
+
- agent_mail_list
|
|
75
|
+
- agent_mail_read
|
|
57
76
|
# automations
|
|
58
77
|
- list_automations
|
|
59
78
|
- get_automation
|
|
@@ -95,6 +114,10 @@ tools:
|
|
|
95
114
|
- get_my_bids
|
|
96
115
|
- get_received_bids
|
|
97
116
|
- get_marketplace_history
|
|
117
|
+
# pay.sh x402 (catalog / pricing / approval prep — paid execution is opt-in)
|
|
118
|
+
- pay_sh_search
|
|
119
|
+
- pay_sh_provider_details
|
|
120
|
+
- pay_sh_prepare_call
|
|
98
121
|
# perps (read / preview only)
|
|
99
122
|
- perps_markets
|
|
100
123
|
- perps_market_data
|
|
@@ -143,8 +166,12 @@ post_install: |
|
|
|
143
166
|
|
|
144
167
|
FINANCIAL / IRREVERSIBLE TOOLS are OFF by default (perps_*, swap_execute,
|
|
145
168
|
dca_create, limit_order_create, jup_lend_deposit/withdraw, predictions_open/
|
|
146
|
-
close, place_bid / accept_marketplace_bid, set_external_wallet,
|
|
147
|
-
|
|
169
|
+
close, place_bid / accept_marketplace_bid, set_external_wallet,
|
|
170
|
+
wallet_transfer, agent_card_create/cancel/reveal/withdraw,
|
|
171
|
+
agent_mail_create/send, pay_sh_execute_approved, and the token-launch
|
|
172
|
+
tools). Several require explicit confirm flags (confirmRisk,
|
|
173
|
+
confirm_launch, confirm_spend, confirm_send, confirm_transfer,
|
|
174
|
+
confirm_payment, …).
|
|
148
175
|
Enable the ones you want and review every call:
|
|
149
176
|
hermes mcp configure clawpump
|
|
150
177
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
manifest_version: 1
|
|
4
4
|
|
|
5
5
|
name: clawpump-stdio
|
|
6
|
-
description: ClawPump (stdio) — the same
|
|
6
|
+
description: ClawPump (stdio) — the same 131 tools via the npm package, authed with a cpk_* API key (no browser).
|
|
7
7
|
source: https://www.npmjs.com/package/@clawpump/agents
|
|
8
8
|
|
|
9
9
|
# Same tool surface as the `clawpump` remote entry, but run locally over stdio
|
|
@@ -31,8 +31,8 @@ auth:
|
|
|
31
31
|
secret: false
|
|
32
32
|
default: ""
|
|
33
33
|
|
|
34
|
-
# Same read-mostly default as the remote `clawpump` entry:
|
|
35
|
-
# pre-checked; the
|
|
34
|
+
# Same read-mostly default as the remote `clawpump` entry: 94 safe tools
|
|
35
|
+
# pre-checked; the 37 financial/irreversible tools are opt-in. See the
|
|
36
36
|
# `clawpump` manifest for the rationale (Hermes does not auto-gate MCP tools
|
|
37
37
|
# by destructiveHint).
|
|
38
38
|
tools:
|
|
@@ -52,6 +52,23 @@ tools:
|
|
|
52
52
|
- upload_agent_avatar
|
|
53
53
|
- get_agent_asset_url
|
|
54
54
|
- list_available_skills
|
|
55
|
+
# agent cards (Laso — reads / linking / quotes; purchase & withdraw are opt-in)
|
|
56
|
+
- agent_card_list
|
|
57
|
+
- agent_card_get
|
|
58
|
+
- agent_card_status
|
|
59
|
+
- agent_card_balance
|
|
60
|
+
- agent_card_data
|
|
61
|
+
- agent_card_withdrawals
|
|
62
|
+
- agent_card_quote
|
|
63
|
+
- agent_card_refresh
|
|
64
|
+
- agent_card_search_gift_cards
|
|
65
|
+
- agent_card_search_merchants
|
|
66
|
+
- agent_card_connect
|
|
67
|
+
- agent_card_connect_link
|
|
68
|
+
# agent mail (reads; inbox provisioning & sending are opt-in)
|
|
69
|
+
- agent_mail_get_address
|
|
70
|
+
- agent_mail_list
|
|
71
|
+
- agent_mail_read
|
|
55
72
|
# automations
|
|
56
73
|
- list_automations
|
|
57
74
|
- get_automation
|
|
@@ -93,6 +110,10 @@ tools:
|
|
|
93
110
|
- get_my_bids
|
|
94
111
|
- get_received_bids
|
|
95
112
|
- get_marketplace_history
|
|
113
|
+
# pay.sh x402 (catalog / pricing / approval prep — paid execution is opt-in)
|
|
114
|
+
- pay_sh_search
|
|
115
|
+
- pay_sh_provider_details
|
|
116
|
+
- pay_sh_prepare_call
|
|
96
117
|
# perps (read / preview only)
|
|
97
118
|
- perps_markets
|
|
98
119
|
- perps_market_data
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""UsePod provider profile.
|
|
2
|
+
|
|
3
|
+
UsePod (usepod.ai) is a drop-in OpenAI- and Anthropic-compatible inference
|
|
4
|
+
marketplace. Independent operators serve open-weight models (or relay their
|
|
5
|
+
own upstream keys) and centralized providers stay available as a fallback;
|
|
6
|
+
billing is pay-per-request, settled in USDC from a per-token balance.
|
|
7
|
+
|
|
8
|
+
Unlike a normal API-key provider, UsePod authenticates by the token embedded
|
|
9
|
+
in the request *path* (``/proxy/<token>/v1/...``) and ignores the
|
|
10
|
+
Authorization header. The base URL is therefore DERIVED from the API key
|
|
11
|
+
rather than being static — see ``hermes_cli.auth._resolve_usepod_base_url`` and
|
|
12
|
+
the ``usepod`` branches in ``resolve_api_key_provider_credentials`` /
|
|
13
|
+
``get_api_key_provider_status`` (auth.py) and ``_resolve_explicit_runtime``
|
|
14
|
+
(runtime_provider.py).
|
|
15
|
+
|
|
16
|
+
The net effect for the user: they only paste the token they obtained from
|
|
17
|
+
``POST https://api.usepod.ai/v1/register`` (and funded on https://usepod.ai/fund)
|
|
18
|
+
— the proxy URL is built for them. An explicit ``USEPOD_BASE_URL`` env var
|
|
19
|
+
still wins, e.g. for a self-hosted UsePod gateway.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import logging
|
|
26
|
+
import urllib.request
|
|
27
|
+
|
|
28
|
+
from providers import register_provider
|
|
29
|
+
from providers.base import ProviderProfile, _profile_user_agent
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
# Production gateway host. The token-bearing inference base URL is
|
|
34
|
+
# ``{USEPOD_API_BASE}/proxy/<token>/v1``; the catalog is
|
|
35
|
+
# ``{USEPOD_API_BASE}/proxy/<token>/v1/models``.
|
|
36
|
+
USEPOD_API_BASE = "https://api.usepod.ai"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class UsePodProfile(ProviderProfile):
|
|
40
|
+
"""UsePod — OpenAI-compatible proxy with the auth token in the URL path."""
|
|
41
|
+
|
|
42
|
+
def fetch_models(self, *, api_key: str | None = None, timeout: float = 8.0):
|
|
43
|
+
"""List models from the per-token catalog endpoint.
|
|
44
|
+
|
|
45
|
+
UsePod exposes ``/proxy/<token>/v1/models``; the token lives in the
|
|
46
|
+
path, so the base-class implementation (which builds the URL from the
|
|
47
|
+
static ``base_url``) cannot reach it. Returns None when no token is
|
|
48
|
+
available so callers fall back to ``fallback_models``.
|
|
49
|
+
"""
|
|
50
|
+
token = (api_key or "").strip()
|
|
51
|
+
if not token:
|
|
52
|
+
return None
|
|
53
|
+
url = f"{USEPOD_API_BASE}/proxy/{token}/v1/models"
|
|
54
|
+
req = urllib.request.Request(url)
|
|
55
|
+
# Harmless — UsePod ignores it (auth is the path token) — but send it
|
|
56
|
+
# for parity with standard OpenAI clients / intermediaries.
|
|
57
|
+
req.add_header("Authorization", f"Bearer {token}")
|
|
58
|
+
req.add_header("Accept", "application/json")
|
|
59
|
+
req.add_header("User-Agent", _profile_user_agent())
|
|
60
|
+
try:
|
|
61
|
+
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
62
|
+
data = json.loads(resp.read().decode())
|
|
63
|
+
items = data if isinstance(data, list) else data.get("data", [])
|
|
64
|
+
return [m["id"] for m in items if isinstance(m, dict) and "id" in m]
|
|
65
|
+
except Exception as exc:
|
|
66
|
+
logger.debug("fetch_models(usepod): %s", exc)
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
usepod = UsePodProfile(
|
|
71
|
+
name="usepod",
|
|
72
|
+
# USEPOD_API_KEY = the token (paste-in). USEPOD_BASE_URL = optional override
|
|
73
|
+
# for self-hosted gateways; the registry auto-maps the *_BASE_URL var to the
|
|
74
|
+
# base_url override env var.
|
|
75
|
+
env_vars=("USEPOD_API_KEY", "USEPOD_BASE_URL"),
|
|
76
|
+
display_name="UsePod",
|
|
77
|
+
description="UsePod (drop-in OpenAI-compatible inference marketplace, pay-per-use in USDC)",
|
|
78
|
+
signup_url="https://usepod.ai",
|
|
79
|
+
# Non-empty so the picker + live-fetch plumbing engages; the *effective*
|
|
80
|
+
# inference URL is derived per-token (see module docstring). hostname pins
|
|
81
|
+
# the URL→provider reverse mapping to api.usepod.ai.
|
|
82
|
+
base_url=f"{USEPOD_API_BASE}/proxy",
|
|
83
|
+
hostname="api.usepod.ai",
|
|
84
|
+
# The token is in the URL path, so doctor's static /models probe (built from
|
|
85
|
+
# base_url) can't reach the per-token catalog. Skip it — key presence is the
|
|
86
|
+
# meaningful "configured" signal for this provider.
|
|
87
|
+
supports_health_check=False,
|
|
88
|
+
# Best-effort offline picker list — UsePod's real catalog is dynamic and is
|
|
89
|
+
# fetched live from /proxy/<token>/v1/models whenever a key is present.
|
|
90
|
+
fallback_models=(
|
|
91
|
+
"claude-opus-4-8",
|
|
92
|
+
"claude-sonnet-4-6",
|
|
93
|
+
"gpt-5.5",
|
|
94
|
+
"deepseek-v4",
|
|
95
|
+
"glm-4-7",
|
|
96
|
+
"kimi-k2.5",
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
register_provider(usepod)
|
package/agent/scripts/release.py
CHANGED
|
@@ -45,6 +45,7 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|
|
45
45
|
|
|
46
46
|
# Auto-extracted from noreply emails + manual overrides
|
|
47
47
|
AUTHOR_MAP = {
|
|
48
|
+
"chris@100x.dev": "chris-gilbert",
|
|
48
49
|
"ben.bartholomew@vectorize.io": "benfrank241",
|
|
49
50
|
"74339271+SaguaroDev@users.noreply.github.com": "SaguaroDev",
|
|
50
51
|
"subw3@mail2.sysu.edu.cn": "Subway2023",
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clawpump
|
|
3
|
-
description: "ClawPump on Solana — create/chat with agents, trade, perps, DCA, lend, launch tokens, marketplace, predictions, intelligence via mcp_clawpump_* tools. Use when the user mentions ClawPump, launching a token, an agent's wallet/balance, swaps, perps, or DeFi on Solana."
|
|
4
|
-
version: 1.
|
|
3
|
+
description: "ClawPump on Solana — create/chat with agents, trade, perps, DCA, lend, launch tokens, marketplace, predictions, gift cards, agent email, intelligence via mcp_clawpump_* tools. Use when the user mentions ClawPump, launching a token, an agent's wallet/balance, swaps, perps, gift cards, agent email, or DeFi on Solana."
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platforms: [linux, macos, windows]
|
|
6
6
|
metadata:
|
|
7
7
|
hermes:
|
|
8
|
-
tags: [clawpump, solana, defi, trading, perps, dca, lending, token-launch, marketplace, predictions, agents, mcp]
|
|
9
|
-
related_skills: [mcp]
|
|
8
|
+
tags: [clawpump, solana, defi, trading, perps, dca, lending, token-launch, marketplace, predictions, gift-cards, agent-mail, agents, mcp]
|
|
9
|
+
related_skills: [mcp, pay-sh]
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# ClawPump
|
|
13
13
|
|
|
14
14
|
ClawPump is a Solana platform for AI agents: each agent has a wallet and can
|
|
15
|
-
trade, run perps, DCA, lend, launch tokens,
|
|
16
|
-
marketplace. Its full feature set
|
|
17
|
-
server** (
|
|
15
|
+
trade, run perps, DCA, lend, launch tokens, buy gift cards, send email from
|
|
16
|
+
its own inbox, and be bought/sold on a marketplace. Its full feature set
|
|
17
|
+
reaches Hermes through the **ClawPump MCP server** (131 tools, 10 resources,
|
|
18
|
+
10 prompts).
|
|
18
19
|
|
|
19
20
|
## Enabling ClawPump
|
|
20
21
|
|
|
@@ -43,7 +44,7 @@ Most tools act on a specific agent. Resolve it once with `list_agents`, then
|
|
|
43
44
|
pass `agent_id`. If the user set `CLAWPUMP_DEFAULT_AGENT` (or has exactly one
|
|
44
45
|
agent), `agent_id` can usually be omitted. When unsure which agent, ask.
|
|
45
46
|
|
|
46
|
-
## What's available (
|
|
47
|
+
## What's available (131 tools, 20 groups)
|
|
47
48
|
|
|
48
49
|
| Group | Representative tools |
|
|
49
50
|
|-------|----------------------|
|
|
@@ -53,19 +54,22 @@ agent), `agent_id` can usually be omitted. When unsure which agent, ask.
|
|
|
53
54
|
| Custom skills | `list_custom_skills`, `get_custom_skill`, `create_custom_skill`, `update_custom_skill`, `delete_custom_skill` |
|
|
54
55
|
| Trading | `swap_quote`, `swap_execute`, `token_search`, `get_portfolio`, `get_price`, `get_market_signals`, `get_indicators`, `arbitrage_quote`/`arbitrage_prices` |
|
|
55
56
|
| DCA / limits | `dca_create`, `dca_list`, `dca_cancel`, `limit_order_create`, `limit_order_cancel`, `limit_order_history` |
|
|
56
|
-
| Phoenix perps | `perps_markets`, `perps_market_data`, `perps_account`, `perps_account_prepare`, `perps_trader_register`, `perps_collateral_deposit`, `perps_order_preview`, `perps_order_execute`, `perps_order_cancel` |
|
|
57
|
+
| Phoenix perps | `perps_markets`, `perps_market_data`, `perps_account`, `perps_account_prepare`, `perps_trader_register`, `perps_collateral_deposit`, `perps_collateral_withdraw`, `perps_order_preview`, `perps_order_execute`, `perps_order_cancel` |
|
|
57
58
|
| Lending (Jupiter) | `jup_lend_tokens`, `jup_lend_positions`, `jup_lend_deposit`, `jup_lend_withdraw` |
|
|
58
59
|
| Predictions | `predictions_events`, `predictions_positions`, `predictions_open`, `predictions_close` |
|
|
59
60
|
| Token launch | `get_launch_status`, `launch_token_gasless`, `launch_metaplex_genesis_token` |
|
|
60
61
|
| Marketplace | `browse_marketplace`, `create_marketplace_listing`, `delist_marketplace_listing`, `browse_public_agents`, `place_bid`, `get_my_bids`, `get_received_bids`, `accept_marketplace_bid`, `reject_marketplace_bid`, `withdraw_marketplace_bid`, `get_marketplace_history` |
|
|
61
|
-
|
|
|
62
|
+
| Agent cards (Laso) | `agent_card_search_merchants`, `agent_card_search_gift_cards`, `agent_card_quote`, `agent_card_create`, `agent_card_list`, `agent_card_get`, `agent_card_status`, `agent_card_data`, `agent_card_balance`, `agent_card_reveal`, `agent_card_cancel`, `agent_card_refresh`, `agent_card_withdraw`, `agent_card_withdrawals`, `agent_card_connect`, `agent_card_connect_link` |
|
|
63
|
+
| Agent mail | `agent_mail_create`, `agent_mail_get_address`, `agent_mail_send`, `agent_mail_list`, `agent_mail_read` |
|
|
64
|
+
| Pay.sh x402 (agent-wallet paid APIs) | `pay_sh_search`, `pay_sh_provider_details`, `pay_sh_prepare_call`, `pay_sh_execute_approved` |
|
|
65
|
+
| Wallet & billing | `get_balance`, `get_budget`, `get_usage`, `get_transactions`, `get_wallet_summaries`, `get_wallet_history`, `get_private_wallet_balance`, `get_balance_history`, `sync_billing`, `wallet_transfer` |
|
|
62
66
|
| Market intelligence | `intelligence_capabilities`, `intelligence_market`, `intelligence_signals`, `intelligence_macro`, `intelligence_perps` |
|
|
63
67
|
| Integrations | `list_integrations`, `save_integration`, `remove_integration`, `get_linked_accounts` |
|
|
64
68
|
| Account | `get_account_status`, `connect_twitter`, `configure_twitter_posting`, `set_external_wallet`, `generate_link_code`, `link_google_account`, `get_dashboard_urls` |
|
|
65
69
|
| Whitelist | `get_whitelist`, `add_to_whitelist`, `remove_from_whitelist` |
|
|
66
70
|
| Utility | `get_model_catalog`, `get_news_feed` |
|
|
67
71
|
|
|
68
|
-
By default only the **
|
|
72
|
+
By default only the **94 read-mostly** tools are enabled. The financial ones
|
|
69
73
|
below are opt-in via `hermes mcp configure clawpump`.
|
|
70
74
|
|
|
71
75
|
## ⚠️ FINANCIAL & IRREVERSIBLE TOOLS — confirmation is mandatory
|
|
@@ -73,20 +77,27 @@ below are opt-in via `hermes mcp configure clawpump`.
|
|
|
73
77
|
These move real funds on-chain or are irreversible. **Never call them without
|
|
74
78
|
the user's explicit, specific go-ahead in this conversation.** Quote the exact
|
|
75
79
|
action (amounts, token, agent) and wait for a clear yes. Several require an
|
|
76
|
-
explicit confirm flag (e.g. `confirmRisk: true`, `confirm_launch: true
|
|
77
|
-
|
|
80
|
+
explicit confirm flag (e.g. `confirmRisk: true`, `confirm_launch: true`,
|
|
81
|
+
`confirm_spend: true`, `confirm_send: true`, `confirm_transfer: true`,
|
|
82
|
+
`confirm_payment: true`) — only set it after the user agrees.
|
|
78
83
|
|
|
79
84
|
- Trading: `swap_execute`, `dca_create`, `dca_cancel`, `limit_order_create`, `limit_order_cancel`
|
|
80
|
-
- Perps: `perps_account_prepare`, `perps_trader_register`, `perps_collateral_deposit`, `perps_order_execute`, `perps_order_cancel`
|
|
85
|
+
- Perps: `perps_account_prepare`, `perps_trader_register`, `perps_collateral_deposit`, `perps_collateral_withdraw`, `perps_order_execute`, `perps_order_cancel`
|
|
81
86
|
- Lending: `jup_lend_deposit`, `jup_lend_withdraw`
|
|
82
87
|
- Predictions: `predictions_open`, `predictions_close`
|
|
83
88
|
- Marketplace (funds/ownership): `place_bid`, `accept_marketplace_bid`, `reject_marketplace_bid`, `withdraw_marketplace_bid`, `delist_marketplace_listing`
|
|
84
89
|
- Token launch: `launch_token_gasless`, `launch_metaplex_genesis_token`
|
|
85
90
|
- Account / lifecycle: `set_external_wallet`, `delete_agent`, `delete_automation`, `delete_custom_skill`, `cancel_agent_run`, `remove_integration`, `remove_from_whitelist`
|
|
91
|
+
- Agent cards (Laso): `agent_card_create` (pays USDC from the agent wallet — quote first), `agent_card_withdraw`, `agent_card_cancel`, `agent_card_reveal` (exposes the card number / redemption secret)
|
|
92
|
+
- Agent mail: `agent_mail_create` (one-time ~$2 USDC from the agent wallet), `agent_mail_send` (outward-facing email; paid per send via x402 from the agent wallet)
|
|
93
|
+
- Wallet: `wallet_transfer` (irreversible on-chain send; destination must be on the agent's whitelist via `add_to_whitelist`; quote the exact amount, token, and address, then `confirm_transfer: true`)
|
|
94
|
+
- Pay.sh x402: `pay_sh_execute_approved` (pays USDC from the agent wallet via x402 — always `pay_sh_prepare_call` first; quote the exact endpoint + price; approval codes expire in 10 minutes; requires the `x402` skill on the agent)
|
|
86
95
|
|
|
87
96
|
**Always get a quote/preview first** (`swap_quote` before `swap_execute`,
|
|
88
|
-
`perps_order_preview` before `perps_order_execute`
|
|
89
|
-
|
|
97
|
+
`perps_order_preview` before `perps_order_execute`, `agent_card_quote` before
|
|
98
|
+
`agent_card_create`, `pay_sh_prepare_call` before `pay_sh_execute_approved`)
|
|
99
|
+
and show it to the user before executing. Report tx signatures back when a
|
|
100
|
+
call succeeds.
|
|
90
101
|
|
|
91
102
|
## Resources (read with the MCP resource reader)
|
|
92
103
|
|
|
@@ -120,3 +131,8 @@ Common patterns:
|
|
|
120
131
|
- **Launch a token:** `get_launch_status` → confirm details → `launch_token_gasless` (gasless) or `launch_metaplex_genesis_token`.
|
|
121
132
|
- **Check portfolio:** `get_balance` + `get_portfolio` + `get_wallet_summaries`.
|
|
122
133
|
- **Perps:** `perps_markets`/`perps_market_data` → `perps_order_preview` → (confirm) → `perps_order_execute`.
|
|
134
|
+
- **Gift card:** `agent_card_search_merchants`/`agent_card_search_gift_cards` → `agent_card_quote` → (confirm) → `agent_card_create` → `agent_card_status`; `agent_card_reveal` only when the user asks for the card details.
|
|
135
|
+
- **Agent email:** `agent_mail_get_address`; no inbox → (confirm ~$2 USDC) `agent_mail_create`; then `agent_mail_send` (confirm) or `agent_mail_list` → `agent_mail_read`.
|
|
136
|
+
- **Deliverability (avoid spam):** write genuine, complete messages — a specific subject, a greeting, 2–4 sentences of real purpose, and a sign-off. Never send one-word/empty bodies or test-like "hello": low-content mail from a fresh sender domain is the #1 spam trigger. Do **not** use fake-urgent or deceptive subjects ("IMPORTANT!!", "URGENT") to game filters — that backfires and is deceptive. Tell first-time recipients to mark "Not spam" + add the address to contacts; that trains their inbox fastest.
|
|
137
|
+
- **Fund an external wallet (e.g. a pay.sh allowance):** `get_balance` → `add_to_whitelist` (user-approved address) → (confirm) `wallet_transfer`. See the `pay-sh` skill.
|
|
138
|
+
- **Paid x402 API call (agent wallet pays):** `pay_sh_search` → `pay_sh_provider_details` (price) → `pay_sh_prepare_call` → (confirm price with user) → `pay_sh_execute_approved`. The agent needs the `x402` skill (`update_agent` with `enabled_skills`).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pay-sh
|
|
3
|
+
description: "Pay.sh / x402 paid APIs paid with the ClawPump agent wallet — search a catalog of pay-per-call services (images, data, email, voice…) and pay per call in USDC straight from the agent's custodial wallet via the ClawPump MCP. Use when the user mentions pay.sh, x402, 402 payments, or paying for an API/service with the agent's funds."
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
platforms: [linux, macos, windows]
|
|
6
|
+
metadata:
|
|
7
|
+
hermes:
|
|
8
|
+
tags: [pay-sh, x402, solana, payments, usdc, apis, mcp, clawpump]
|
|
9
|
+
related_skills: [clawpump, mcp]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Pay.sh (x402 paid APIs) — paid by the ClawPump wallet
|
|
13
|
+
|
|
14
|
+
Pay.sh is a catalog of APIs gated by stablecoin payments instead of accounts
|
|
15
|
+
and keys: call an endpoint, get HTTP 402 with a price, pay in USDC, get the
|
|
16
|
+
response. ClawPump pays these **from the agent's own custodial wallet** — there
|
|
17
|
+
is no separate wallet to create or fund.
|
|
18
|
+
|
|
19
|
+
## Use the ClawPump MCP tools — nothing else
|
|
20
|
+
|
|
21
|
+
These come from the ClawPump MCP (`mcp_clawpump_*` / `mcp_clawpump-stdio_*`):
|
|
22
|
+
|
|
23
|
+
- `pay_sh_search` — find providers (free)
|
|
24
|
+
- `pay_sh_provider_details` — endpoints + per-call price for one provider (free)
|
|
25
|
+
- `pay_sh_prepare_call` — balance preflight + payment preview + a 10-minute
|
|
26
|
+
approval code; **pays nothing**
|
|
27
|
+
- `pay_sh_execute_approved` — pays from the agent wallet via x402 and returns
|
|
28
|
+
the response; needs the approval code + `confirm_payment: true`
|
|
29
|
+
|
|
30
|
+
## ⛔ Never do this
|
|
31
|
+
|
|
32
|
+
- **Do NOT run the `pay` CLI** (`npx @solana/pay …`) — `pay setup`,
|
|
33
|
+
`pay account new`, `pay topup`, `pay curl`, etc. That creates a *separate
|
|
34
|
+
local wallet*, which is exactly what we are avoiding. The user wants the
|
|
35
|
+
**ClawPump agent wallet** to pay.
|
|
36
|
+
- **Do NOT** create, fund, or transfer to any local/external pay wallet for
|
|
37
|
+
this. No `wallet_transfer` "allowance" hop either.
|
|
38
|
+
- If the ClawPump pay_sh tools are missing, tell the user to enable them
|
|
39
|
+
(`hermes mcp configure clawpump`, opt in `pay_sh_execute_approved`) and that
|
|
40
|
+
the agent needs the `x402` skill — do **not** fall back to the CLI.
|
|
41
|
+
|
|
42
|
+
## Requirement: the `x402` skill
|
|
43
|
+
|
|
44
|
+
`pay_sh_prepare_call` / `pay_sh_execute_approved` require the ClawPump agent to
|
|
45
|
+
have the **`x402`** skill enabled. If a call is rejected for capability, enable
|
|
46
|
+
it with `update_agent` (`enabled_skills` += `x402`), then retry — never reach
|
|
47
|
+
for the CLI.
|
|
48
|
+
|
|
49
|
+
## ⚠️ Spending rules
|
|
50
|
+
|
|
51
|
+
`pay_sh_execute_approved` spends real USDC. Before it:
|
|
52
|
+
|
|
53
|
+
1. Get the price first — `pay_sh_provider_details` / the `pay_sh_prepare_call`
|
|
54
|
+
preview include per-call pricing.
|
|
55
|
+
2. Tell the user the exact endpoint and price; wait for a clear yes.
|
|
56
|
+
3. Only then call `pay_sh_execute_approved` with the approval code and
|
|
57
|
+
`confirm_payment: true`. Never loop paid calls without telling the user the
|
|
58
|
+
total.
|
|
59
|
+
4. Report what was spent and the result.
|
|
60
|
+
|
|
61
|
+
## Pattern
|
|
62
|
+
|
|
63
|
+
`pay_sh_search` → `pay_sh_provider_details` (price) → quote it to the user →
|
|
64
|
+
`pay_sh_prepare_call` → (user approves) → `pay_sh_execute_approved`. All paid
|
|
65
|
+
from the agent's ClawPump wallet. See the `clawpump` skill for the full tool
|
|
66
|
+
reference.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawpump/claw-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"bin/",
|
|
14
14
|
"agent/",
|
|
15
|
-
"README.md"
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
19
|
"build": "node scripts/build-bundle.mjs",
|