aweshare 0.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.
- package/LICENSE +21 -0
- package/README.md +246 -0
- package/apps/agent/dist/adapters.d.ts +15 -0
- package/apps/agent/dist/adapters.js +25 -0
- package/apps/agent/dist/adapters.js.map +1 -0
- package/apps/agent/dist/cli.d.ts +2 -0
- package/apps/agent/dist/cli.js +175 -0
- package/apps/agent/dist/cli.js.map +1 -0
- package/apps/agent/dist/config.d.ts +38 -0
- package/apps/agent/dist/config.js +150 -0
- package/apps/agent/dist/config.js.map +1 -0
- package/apps/agent/dist/connection.d.ts +40 -0
- package/apps/agent/dist/connection.js +359 -0
- package/apps/agent/dist/connection.js.map +1 -0
- package/apps/agent/dist/doctor.d.ts +14 -0
- package/apps/agent/dist/doctor.js +125 -0
- package/apps/agent/dist/doctor.js.map +1 -0
- package/apps/agent/dist/health.d.ts +15 -0
- package/apps/agent/dist/health.js +45 -0
- package/apps/agent/dist/health.js.map +1 -0
- package/apps/agent/dist/index.d.ts +5 -0
- package/apps/agent/dist/index.js +6 -0
- package/apps/agent/dist/index.js.map +1 -0
- package/apps/agent/package.json +20 -0
- package/apps/hub/dist/admin.d.ts +10 -0
- package/apps/hub/dist/admin.js +208 -0
- package/apps/hub/dist/admin.js.map +1 -0
- package/apps/hub/dist/auth.d.ts +17 -0
- package/apps/hub/dist/auth.js +28 -0
- package/apps/hub/dist/auth.js.map +1 -0
- package/apps/hub/dist/cli.d.ts +2 -0
- package/apps/hub/dist/cli.js +243 -0
- package/apps/hub/dist/cli.js.map +1 -0
- package/apps/hub/dist/config.d.ts +25 -0
- package/apps/hub/dist/config.js +53 -0
- package/apps/hub/dist/config.js.map +1 -0
- package/apps/hub/dist/consumer.d.ts +18 -0
- package/apps/hub/dist/consumer.js +157 -0
- package/apps/hub/dist/consumer.js.map +1 -0
- package/apps/hub/dist/db.d.ts +91 -0
- package/apps/hub/dist/db.js +236 -0
- package/apps/hub/dist/db.js.map +1 -0
- package/apps/hub/dist/http.d.ts +31 -0
- package/apps/hub/dist/http.js +118 -0
- package/apps/hub/dist/http.js.map +1 -0
- package/apps/hub/dist/limiter.d.ts +35 -0
- package/apps/hub/dist/limiter.js +78 -0
- package/apps/hub/dist/limiter.js.map +1 -0
- package/apps/hub/dist/limits.d.ts +30 -0
- package/apps/hub/dist/limits.js +52 -0
- package/apps/hub/dist/limits.js.map +1 -0
- package/apps/hub/dist/meter.d.ts +25 -0
- package/apps/hub/dist/meter.js +135 -0
- package/apps/hub/dist/meter.js.map +1 -0
- package/apps/hub/dist/sanitize.d.ts +3 -0
- package/apps/hub/dist/sanitize.js +56 -0
- package/apps/hub/dist/sanitize.js.map +1 -0
- package/apps/hub/dist/server.d.ts +25 -0
- package/apps/hub/dist/server.js +77 -0
- package/apps/hub/dist/server.js.map +1 -0
- package/apps/hub/dist/tokens.d.ts +9 -0
- package/apps/hub/dist/tokens.js +35 -0
- package/apps/hub/dist/tokens.js.map +1 -0
- package/apps/hub/dist/tunnel.d.ts +108 -0
- package/apps/hub/dist/tunnel.js +424 -0
- package/apps/hub/dist/tunnel.js.map +1 -0
- package/apps/hub/package.json +21 -0
- package/bin/aweshare.mjs +43 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aweshare contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="logo/logo.webp" alt="aweshare" width="860">
|
|
4
|
+
|
|
5
|
+
# aweshare
|
|
6
|
+
|
|
7
|
+
**Open-source, local-first AI capability relay**
|
|
8
|
+
|
|
9
|
+
**English** · [简体中文](./README_cn.md)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
Producers run a lightweight agent on their own machine and share local Ollama/vLLM or **authorized** OpenAI/Anthropic backends. Upstream API keys live only on the producer's device and are injected by the local agent at forwarding time. Consumers point a standard OpenAI/Anthropic SDK at the hub and call models by `namespace/alias` — exactly like using any other model vendor.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Consumer (standard SDK, zero changes) Producer side
|
|
17
|
+
┌───────────────────────┐ ┌────────────────────────────┐
|
|
18
|
+
│ Claude Code │ │ aweshare agent (Node CLI) │
|
|
19
|
+
│ ANTHROPIC_BASE_URL ──┼──► HTTPS ──┤ ~/.aweshare/config.toml │
|
|
20
|
+
│ OpenAI SDK / Codex │ │ ~/.aweshare/secrets.json │
|
|
21
|
+
└───────────────────────┘ │ │ upstream key injection │
|
|
22
|
+
│ /v1/messages │ ▼ (the only place it happens)
|
|
23
|
+
│ /v1/chat/completions │ Ollama / vLLM / OpenAI / Anthropic
|
|
24
|
+
▼ │
|
|
25
|
+
┌─────────────────────────────┐ │
|
|
26
|
+
│ aweshare hub (public, 1 node)│◄───── WSS reverse tunnel (agent dials out)
|
|
27
|
+
│ auth / grants / route / meter│ no public IP, no port forwarding needed
|
|
28
|
+
└─────────────────────────────┘
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Grant-based trust**: consumers can only use aliases explicitly granted to them. No payments, no marketplace.
|
|
32
|
+
- **Namespaced aliases**: `peng/gpt-4o` is globally unique with one owner — routing is a deterministic lookup.
|
|
33
|
+
- v1 relays **native transparent SSE** for OpenAI↔OpenAI (chat completions and Responses), Anthropic↔Anthropic. No cross-protocol conversion, no smart routing, no web console.
|
|
34
|
+
|
|
35
|
+
## Trust boundary (read this first)
|
|
36
|
+
|
|
37
|
+
- To route and meter, **consumer prompts and model responses transit the hub in plaintext — this is not end-to-end encryption**. The hub persists no request/response content, but the hub operator can technically see it. Only use a hub instance you trust — which is why the hub is open source and self-hostable.
|
|
38
|
+
- Upstream API keys never leave the producer's device and are never sent to consumers; the hub database stores only SHA-256 hashes of tokens.
|
|
39
|
+
|
|
40
|
+
### Compliance and disclaimer
|
|
41
|
+
|
|
42
|
+
- aweshare is relay software: it cannot and does not judge whether you are allowed to share a given upstream key or subscription — that question is between you and the upstream provider. Being able to call an API yourself does not mean you may resell or re-provide it to third parties.
|
|
43
|
+
- Before sharing anything, read the upstream's terms (account rules, subscription and seat limits, forwarding, commercial-use clauses). Sharing a personal-subscription key — coding plans included — with third parties likely violates those terms; self-hosted open models have no such issue. **When in doubt, don't share.**
|
|
44
|
+
- The producer bears the consequences of sharing (key revocation, account suspension or termination by the upstream). The hub operator is responsible for operating the hub lawfully and for informing consumers of the plaintext-transit boundary above.
|
|
45
|
+
- The software is provided "as is" under the [MIT license](./LICENSE), without warranty of any kind. The authors and contributors are not liable for how aweshare is used or for any damage arising from sharing access through it.
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
Published as [`aweshare`](https://www.npmjs.com/package/aweshare) on npm (requires Node ≥ 22) and as a Docker image (`ghcr.io/mugpeng/aweshare`). No clone needed.
|
|
50
|
+
|
|
51
|
+
### 1. Start the hub (operator, one VPS)
|
|
52
|
+
|
|
53
|
+
**npm** (simplest):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g aweshare
|
|
57
|
+
aweshare hub init # data in ~/.aweshare-hub; prints the admin token — save it
|
|
58
|
+
aweshare hub serve # listens on :8787 (put Caddy/nginx TLS in front)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**docker**:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
docker run -d --name aweshare-hub --restart unless-stopped \
|
|
65
|
+
-p 127.0.0.1:8787:8787 -v "$PWD/data:/data" ghcr.io/mugpeng/aweshare:latest
|
|
66
|
+
docker exec aweshare-hub node apps/hub/dist/cli.js init # first run: prints the admin token, save it
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then issue tokens (admin token in hand):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
aweshare hub token issue --role producer --name peng # → asp_..., give to the producer
|
|
73
|
+
aweshare hub token issue --role consumer --name alice # → asc_..., give to the consumer
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The producer's `name` becomes their alias namespace (the `peng/` in `peng/gpt-4o`).
|
|
77
|
+
|
|
78
|
+
### 2. Producer first run (in this order)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install -g aweshare # ⓪ once, on the producer machine (Node ≥ 22)
|
|
82
|
+
|
|
83
|
+
# ① init: writes ~/.aweshare/config.toml + secrets.json (0600)
|
|
84
|
+
aweshare agent init --hub https://hub.example.com --token asp_...
|
|
85
|
+
|
|
86
|
+
# ② Edit the config (see below); put upstream keys in secrets.json — they never leave this machine
|
|
87
|
+
|
|
88
|
+
# ③ doctor: pre-flight checks, ordered to find the first failing link
|
|
89
|
+
aweshare agent doctor
|
|
90
|
+
|
|
91
|
+
# ④ Grant a consumer
|
|
92
|
+
aweshare agent grant --alias peng/qwen2.5.7b --consumer alice
|
|
93
|
+
# time-limited trial: add --expires-in 7d (re-granting refreshes the expiry)
|
|
94
|
+
|
|
95
|
+
# ⑤ Start (long-running; when it stops, aliases go offline and consumers get 503)
|
|
96
|
+
aweshare agent start
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Consumer first run (in this order)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# ① one small curl to prove the path
|
|
103
|
+
curl https://hub.example.com/v1/chat/completions \
|
|
104
|
+
-H "Authorization: Bearer asc_..." -H "content-type: application/json" \
|
|
105
|
+
-d '{"model":"peng/qwen2.5.7b","messages":[{"role":"user","content":"ping"}]}'
|
|
106
|
+
|
|
107
|
+
# ② configure your tool (below) → run one minimal task
|
|
108
|
+
# ③ check usage: aweshare hub usage --alias peng/qwen2.5.7b
|
|
109
|
+
# ④ only then move to real workloads
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Consumer tool configuration
|
|
113
|
+
|
|
114
|
+
**OpenAI SDK / any OpenAI-compatible tool**
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const client = new OpenAI({ baseURL: 'https://hub.example.com/v1', apiKey: 'asc_...' })
|
|
118
|
+
await client.chat.completions.create({ model: 'peng/gpt-4o', messages: [...] })
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Claude Code** (the key is the `asc_` consumer key — **not** any upstream x-api-key)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
export ANTHROPIC_BASE_URL=https://hub.example.com
|
|
125
|
+
export ANTHROPIC_API_KEY=asc_...
|
|
126
|
+
claude --model peng/sonnet
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If Claude Code has a stale OAuth login it overrides env config — switch with `/login` or clean stored credentials.
|
|
130
|
+
|
|
131
|
+
**Codex** (the default Responses wire protocol works — the alias must be backed by a `responses`-protocol offering; `wire_api = "chat"` against an `openai`-protocol offering also works)
|
|
132
|
+
|
|
133
|
+
```toml
|
|
134
|
+
[model_providers.aweshare]
|
|
135
|
+
base_url = "https://hub.example.com/v1"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Discovering models**: `GET /v1/models` (OpenAI SDK `client.models.list()`) returns every alias granted to the key, with online status.
|
|
139
|
+
|
|
140
|
+
## Producer config reference (~/.aweshare/config.toml)
|
|
141
|
+
|
|
142
|
+
```toml
|
|
143
|
+
hubUrl = "https://hub.example.com"
|
|
144
|
+
token = "asp_..."
|
|
145
|
+
|
|
146
|
+
[[backends]]
|
|
147
|
+
id = "ollama"
|
|
148
|
+
protocol = "openai" # openai-style baseUrl includes /v1 (SDK convention)
|
|
149
|
+
baseUrl = "http://127.0.0.1:11434/v1"
|
|
150
|
+
|
|
151
|
+
[[backends]]
|
|
152
|
+
id = "anthropic-main"
|
|
153
|
+
protocol = "anthropic" # anthropic-style baseUrl excludes /v1 (agent adds it)
|
|
154
|
+
baseUrl = "https://api.anthropic.com"
|
|
155
|
+
keyRef = "anthropic-key" # key lives in secrets.json under this name
|
|
156
|
+
|
|
157
|
+
[[backends]]
|
|
158
|
+
id = "glm-responses"
|
|
159
|
+
protocol = "responses" # responses-style baseUrl includes the version path
|
|
160
|
+
baseUrl = "https://open.bigmodel.cn/api/v1"
|
|
161
|
+
keyRef = "glm-key" # e.g. a GLM coding-plan key (Codex-ready)
|
|
162
|
+
|
|
163
|
+
[[offerings]]
|
|
164
|
+
alias = "peng/qwen2.5.7b" # namespace must be your producer name
|
|
165
|
+
backend = "ollama"
|
|
166
|
+
upstreamModel = "qwen2.5:7b" # the real backend id (full tag from `ollama list`)
|
|
167
|
+
maxConcurrency = 1 # start at 1 for local models; raise for cloud APIs
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Key hygiene: use dedicated, least-privilege, revocable keys with budget alerts; keep `secrets.json` at 0600 and out of git/screenshots; rotate on suspected leaks. Before sharing, check the upstream's terms: account rules, subscription limits, forwarding and commercial-use constraints.
|
|
171
|
+
|
|
172
|
+
## Consumer limits (hub-wide defaults + per-consumer overrides)
|
|
173
|
+
|
|
174
|
+
Every consumer gets the hub-wide defaults (`AWESHARE_CONSUMER_RPS` / `BURST` / `CONCURRENCY`, see Operations). On top of that, the hub admin can set **sparse per-consumer overrides** — only the keys you set take effect, everything else keeps the defaults:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
aweshare hub consumer limits --name alice # show current overrides
|
|
178
|
+
aweshare hub consumer limits --name alice --tpm 60000 --max-total-tokens 5000000
|
|
179
|
+
aweshare hub consumer limits --name alice --rps 2 # later calls merge, not replace
|
|
180
|
+
aweshare hub consumer limits --name alice --clear # back to hub-wide defaults
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Key | Meaning | Enforcement |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `rps` / `burst` / `maxConcurrent` | override the hub-wide rate/inflight defaults for this consumer | 429 `RATE_LIMITED` |
|
|
186
|
+
| `tpm` | max tokens (prompt + completion) in any sliding 60s window | 429 `RATE_LIMITED` (in-memory window, like the RPS bucket) |
|
|
187
|
+
| `maxTotalTokens` | lifetime token budget for this consumer | 429 `QUOTA_EXCEEDED` (sums `usage_events`) |
|
|
188
|
+
|
|
189
|
+
Grants can also carry an expiry: `aweshare hub grant add --alias peng/gpt-4o --consumer alice --expires-in 7d` (or `aweshare agent grant … --expires-in 7d` on the producer side). An expired grant returns `403 GRANT_EXPIRED`; re-granting refreshes the expiry.
|
|
190
|
+
|
|
191
|
+
Honest limits: token-based caps count what upstreams report — Ollama streams report no usage, so they contribute 0. TPM is best-effort (concurrent requests that all pass before any finishes can overshoot); the lifetime budget is exact because it sums persisted rows.
|
|
192
|
+
|
|
193
|
+
## Endpoints and errors
|
|
194
|
+
|
|
195
|
+
| Endpoint | Purpose |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `POST /v1/chat/completions` · `POST /v1/messages` · `POST /v1/responses` | inference (Bearer or `x-api-key`) |
|
|
198
|
+
| `GET /v1/models` | aliases visible to this key, with status |
|
|
199
|
+
| `GET /healthz` | liveness |
|
|
200
|
+
| `/admin/v1/*` | token/grant/usage management (admin or producer token) · consumer limit overrides: `GET`/`PUT`/`DELETE /admin/v1/consumers/{name}/limits` (admin only) |
|
|
201
|
+
|
|
202
|
+
Error semantics: `401` invalid key · `403` not granted or `GRANT_EXPIRED` · `404` unknown alias · `400 PROTOCOL_MISMATCH` protocol/alias mismatch · `429` rate limit, TPM or producer concurrency cap (`QUOTA_EXCEEDED` = lifetime token budget hit) · `502` upstream/tunnel failure (upstream 4xx/5xx passes through verbatim) · `503` producer offline / backend degraded · `504` timeout. Errors carry `{error:{code,message,requestId}}`; the requestId spans both sides' logs.
|
|
203
|
+
|
|
204
|
+
Usage metering: one row per request (alias, real model, status, duration, byte counts, best-effort token counts), **zero content stored**. Producers list grants with `aweshare agent list`; query usage with `aweshare hub usage`.
|
|
205
|
+
|
|
206
|
+
## Operations
|
|
207
|
+
|
|
208
|
+
| Env var | Default | Purpose |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `AWESHARE_HUB_DATA_DIR` | `~/.aweshare-hub` | data dir (SQLite/pepper/admin token; volume-mount = backup) |
|
|
211
|
+
| `AWESHARE_HUB_PORT` / `HOST` | 8787 / 0.0.0.0 | listen address |
|
|
212
|
+
| `AWESHARE_CONSUMER_RPS` / `BURST` / `CONCURRENCY` | 10 / 20 / 8 | per-consumer limits |
|
|
213
|
+
| `AWESHARE_HEAD_TIMEOUT_MS` / `IDLE_TIMEOUT_MS` | 120000 / 300000 | response-head timeout / stream idle timeout |
|
|
214
|
+
| `AWESHARE_MAX_BODY_BYTES` | 32MB | request body cap |
|
|
215
|
+
|
|
216
|
+
Health: agent heartbeats every 15s, silent 45s = dead; backends with 2 consecutive AUTH/QUOTA failures auto-degrade (alias shows `degraded`, dispatch stops), 30s probes recover. A new connection with the same producer token replaces the old one (latest-wins).
|
|
217
|
+
|
|
218
|
+
## Development
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
pnpm install
|
|
222
|
+
pnpm test # 98 tests: protocol / hub contract (fake agent vs real hub) / agent unit / e2e (real SDKs)
|
|
223
|
+
pnpm build # tsc -b, whole monorepo
|
|
224
|
+
pnpm check # biome
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
To run the CLIs from a source checkout without `node apps/.../dist/cli.js`, link them once after building:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npm link # or: pnpm link --global — exposes the single `aweshare` bin
|
|
231
|
+
aweshare hub serve
|
|
232
|
+
aweshare agent doctor
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Releasing: push a `v*` tag with a matching `## [x.y.z]` section in `docs/CHANGELOG.md`; CI publishes `aweshare-protocol` + `aweshare` to npm (needs the `NPM_TOKEN` secret) and the Docker image to `ghcr.io/mugpeng/aweshare`.
|
|
236
|
+
|
|
237
|
+
Layout: `packages/protocol` (shared wire protocol) · `apps/hub` (HTTP+WS+SQLite+CLI) · `apps/agent` (CLI). Design docs live in `docs/specs/`; the changelog in `docs/CHANGELOG.md`; contribution scope in [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
238
|
+
|
|
239
|
+
## Known limitations (v1)
|
|
240
|
+
|
|
241
|
+
- No cross-protocol conversion: an alias speaks exactly one wire (openai chat, anthropic messages, or openai responses).
|
|
242
|
+
- Ollama streams carry no usage → token counts recorded as NULL (best effort by design).
|
|
243
|
+
- Single hub instance + SQLite; no horizontal scaling.
|
|
244
|
+
- Corporate proxies may block the WebSocket tunnel (environmental limit).
|
|
245
|
+
|
|
246
|
+
MIT License.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RequestStartMessage } from 'aweshare-protocol';
|
|
2
|
+
import type { Backend } from './config.js';
|
|
3
|
+
export interface ResolvedBackend extends Backend {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface UpstreamRequest {
|
|
7
|
+
url: string;
|
|
8
|
+
headers: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Rebuild the upstream request from the tunnel message.
|
|
12
|
+
* The hub already stripped consumer credentials; the upstream key is
|
|
13
|
+
* injected here and nowhere else.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildUpstreamRequest(backend: ResolvedBackend, msg: RequestStartMessage): UpstreamRequest;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuild the upstream request from the tunnel message.
|
|
3
|
+
* The hub already stripped consumer credentials; the upstream key is
|
|
4
|
+
* injected here and nowhere else.
|
|
5
|
+
*/
|
|
6
|
+
export function buildUpstreamRequest(backend, msg) {
|
|
7
|
+
const base = backend.baseUrl.replace(/\/+$/, '');
|
|
8
|
+
// anthropic baseUrl excludes /v1 (SDK convention); openai/responses baseUrl already has it
|
|
9
|
+
const prefix = backend.protocol === 'anthropic' ? '/v1' : '';
|
|
10
|
+
const url = new URL(base + prefix + msg.path);
|
|
11
|
+
for (const [key, value] of Object.entries(msg.query ?? {})) {
|
|
12
|
+
url.searchParams.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
const headers = { ...msg.headers };
|
|
15
|
+
if (backend.protocol === 'anthropic') {
|
|
16
|
+
if (backend.apiKey)
|
|
17
|
+
headers['x-api-key'] = backend.apiKey;
|
|
18
|
+
headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';
|
|
19
|
+
}
|
|
20
|
+
else if (backend.apiKey) {
|
|
21
|
+
headers.authorization = `Bearer ${backend.apiKey}`;
|
|
22
|
+
}
|
|
23
|
+
return { url: url.toString(), headers };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAwB,EACxB,GAAwB;IAExB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAChD,2FAA2F;IAC3F,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1D,IAAI,OAAO,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAA;QACzD,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,YAAY,CAAA;IAC7E,CAAC;SAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,aAAa,GAAG,UAAU,OAAO,CAAC,MAAM,EAAE,CAAA;IACpD,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAA;AACzC,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import pino from 'pino';
|
|
5
|
+
import { agentDir, CONFIG_TEMPLATE, loadAgentConfig, SECRETS_TEMPLATE, writeFileAtomic, } from './config.js';
|
|
6
|
+
import { AgentConnection } from './connection.js';
|
|
7
|
+
import { runDoctor } from './doctor.js';
|
|
8
|
+
const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
9
|
+
const USAGE = `aweshare agent — share local/authorized AI capacity through an aweshare hub
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
aweshare agent init [--hub URL] [--token asp_...] write config template + empty secrets
|
|
13
|
+
aweshare agent start connect, register offerings, relay
|
|
14
|
+
aweshare agent doctor pre-flight checks (direct replay first, hub last)
|
|
15
|
+
aweshare agent grant --alias ALIAS --consumer NAME [--expires-in 7d|12h|30m|90s]
|
|
16
|
+
aweshare agent revoke --alias ALIAS --consumer NAME
|
|
17
|
+
aweshare agent list list grants for your namespace
|
|
18
|
+
|
|
19
|
+
Environment:
|
|
20
|
+
AWESHARE_AGENT_DIR config directory (default ~/.aweshare)`;
|
|
21
|
+
function parseFlags(argv) {
|
|
22
|
+
const positional = [];
|
|
23
|
+
const flags = new Map();
|
|
24
|
+
for (let i = 0; i < argv.length; i++) {
|
|
25
|
+
const a = argv[i];
|
|
26
|
+
if (a.startsWith('--')) {
|
|
27
|
+
const eq = a.indexOf('=');
|
|
28
|
+
if (eq >= 0) {
|
|
29
|
+
flags.set(a.slice(2, eq), a.slice(eq + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
|
|
32
|
+
flags.set(a.slice(2), argv[++i]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
flags.set(a.slice(2), 'true');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
positional.push(a);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { positional, flags };
|
|
43
|
+
}
|
|
44
|
+
function fail(message) {
|
|
45
|
+
console.error(`error: ${message}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
/** Node fetch reports "fetch failed" without the reason; surface the cause. */
|
|
49
|
+
function errorMessage(err) {
|
|
50
|
+
if (err instanceof Error) {
|
|
51
|
+
const cause = err.cause;
|
|
52
|
+
return cause ? `${err.message} (${cause.code ?? cause.message})` : err.message;
|
|
53
|
+
}
|
|
54
|
+
return String(err);
|
|
55
|
+
}
|
|
56
|
+
/** Parse a human duration like 90s, 30m, 12h, 7d into milliseconds. */
|
|
57
|
+
function parseDuration(raw) {
|
|
58
|
+
const m = /^(\d+)([smhd])$/.exec(raw);
|
|
59
|
+
if (!m)
|
|
60
|
+
fail(`--expires-in must look like 90s, 30m, 12h or 7d, got '${raw}'`);
|
|
61
|
+
const unit = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2]];
|
|
62
|
+
return Number(m[1]) * unit;
|
|
63
|
+
}
|
|
64
|
+
async function main() {
|
|
65
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
66
|
+
const { flags } = parseFlags(rest);
|
|
67
|
+
if (cmd === '-v' || cmd === '--version') {
|
|
68
|
+
console.log(`aweshare agent ${VERSION}`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h' || flags.get('help') === 'true') {
|
|
72
|
+
console.log(USAGE);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const dir = agentDir();
|
|
76
|
+
switch (cmd) {
|
|
77
|
+
case 'init': {
|
|
78
|
+
const configPath = join(dir, 'config.toml');
|
|
79
|
+
const secretsPath = join(dir, 'secrets.json');
|
|
80
|
+
if (!existsSync(configPath)) {
|
|
81
|
+
let template = CONFIG_TEMPLATE;
|
|
82
|
+
if (flags.get('hub')) {
|
|
83
|
+
template = template.replace('hubUrl = "http://127.0.0.1:8787"', `hubUrl = "${flags.get('hub')}"`);
|
|
84
|
+
}
|
|
85
|
+
if (flags.get('token')) {
|
|
86
|
+
template = template.replace('token = "asp_PASTE_PRODUCER_TOKEN"', `token = "${flags.get('token')}"`);
|
|
87
|
+
}
|
|
88
|
+
writeFileAtomic(configPath, template, 0o600);
|
|
89
|
+
console.log(`wrote ${configPath}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(`exists, kept: ${configPath}`);
|
|
93
|
+
}
|
|
94
|
+
if (!existsSync(secretsPath)) {
|
|
95
|
+
writeFileAtomic(secretsPath, SECRETS_TEMPLATE, 0o600);
|
|
96
|
+
console.log(`wrote ${secretsPath}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(`exists, kept: ${secretsPath}`);
|
|
100
|
+
}
|
|
101
|
+
console.log('\nnext steps:');
|
|
102
|
+
console.log(' 1. edit config.toml: backends + offerings (namespace must be your producer name)');
|
|
103
|
+
console.log(' 2. put upstream keys in secrets.json (they never leave this machine)');
|
|
104
|
+
console.log(' 3. aweshare agent doctor # find the first failing link');
|
|
105
|
+
console.log(' 4. aweshare agent grant --alias YOU/model --consumer NAME');
|
|
106
|
+
console.log(' 5. aweshare agent start');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
case 'doctor': {
|
|
110
|
+
const report = await runDoctor(dir);
|
|
111
|
+
for (const check of report.checks) {
|
|
112
|
+
console.log(`${check.ok ? ' ok ' : 'FAIL '} ${check.name}: ${check.detail}`);
|
|
113
|
+
}
|
|
114
|
+
console.log(report.ok ? '\ndoctor: all green' : '\ndoctor: fix the first FAIL above, then re-run');
|
|
115
|
+
process.exitCode = report.ok ? 0 : 1;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
case 'start': {
|
|
119
|
+
const { config, secrets } = loadAgentConfig(dir);
|
|
120
|
+
const connection = new AgentConnection({
|
|
121
|
+
config,
|
|
122
|
+
secrets,
|
|
123
|
+
log: pino({ level: process.env.AWESHARE_LOG ?? 'info' }),
|
|
124
|
+
});
|
|
125
|
+
const shutdown = () => {
|
|
126
|
+
console.error('\nshutting down…');
|
|
127
|
+
void connection.stop().then(() => process.exit(0));
|
|
128
|
+
};
|
|
129
|
+
process.on('SIGINT', shutdown);
|
|
130
|
+
process.on('SIGTERM', shutdown);
|
|
131
|
+
await connection.start();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
case 'grant':
|
|
135
|
+
case 'revoke':
|
|
136
|
+
case 'list': {
|
|
137
|
+
const { config } = loadAgentConfig(dir);
|
|
138
|
+
const base = config.hubUrl;
|
|
139
|
+
const auth = { authorization: `Bearer ${config.token}`, 'content-type': 'application/json' };
|
|
140
|
+
if (cmd === 'grant' || cmd === 'revoke') {
|
|
141
|
+
const alias = flags.get('alias');
|
|
142
|
+
const consumer = flags.get('consumer');
|
|
143
|
+
if (!alias || !consumer)
|
|
144
|
+
fail('--alias and --consumer are required');
|
|
145
|
+
const body = { alias, consumer };
|
|
146
|
+
const expiresIn = flags.get('expires-in');
|
|
147
|
+
if (cmd === 'grant' && expiresIn) {
|
|
148
|
+
body.expiresAt = new Date(Date.now() + parseDuration(expiresIn)).toISOString();
|
|
149
|
+
}
|
|
150
|
+
const res = cmd === 'grant'
|
|
151
|
+
? await fetch(`${base}/admin/v1/grants`, {
|
|
152
|
+
method: 'PUT',
|
|
153
|
+
headers: auth,
|
|
154
|
+
body: JSON.stringify(body),
|
|
155
|
+
})
|
|
156
|
+
: await fetch(`${base}/admin/v1/grants?alias=${encodeURIComponent(alias)}&consumer=${encodeURIComponent(consumer)}`, { method: 'DELETE', headers: auth });
|
|
157
|
+
const data = (await res.json().catch(() => ({})));
|
|
158
|
+
if (!res.ok)
|
|
159
|
+
fail(`${res.status} ${data.error?.message ?? res.statusText}`);
|
|
160
|
+
console.log(JSON.stringify(data));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const res = await fetch(`${base}/admin/v1/grants`, { headers: auth });
|
|
164
|
+
const data = (await res.json().catch(() => ({})));
|
|
165
|
+
if (!res.ok)
|
|
166
|
+
fail(`${res.status} ${data.error?.message ?? res.statusText}`);
|
|
167
|
+
console.log(JSON.stringify(data, null, 2));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
fail(`unknown command: ${cmd}\n\n${USAGE}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
main().catch((err) => fail(errorMessage(err)));
|
|
175
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Protocol } from 'aweshare-protocol';
|
|
2
|
+
export interface Backend {
|
|
3
|
+
id: string;
|
|
4
|
+
protocol: Protocol;
|
|
5
|
+
/**
|
|
6
|
+
* Follows the SDK convention of the protocol:
|
|
7
|
+
* openai-style includes /v1 (e.g. http://127.0.0.1:11434/v1); anthropic-style
|
|
8
|
+
* excludes it (the agent appends /v1 itself); responses follows the openai
|
|
9
|
+
* convention (e.g. https://open.bigmodel.cn/api/v1).
|
|
10
|
+
*/
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
keyRef?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AgentOffering {
|
|
15
|
+
alias: string;
|
|
16
|
+
backend: string;
|
|
17
|
+
upstreamModel: string;
|
|
18
|
+
maxConcurrency: number;
|
|
19
|
+
}
|
|
20
|
+
export interface AgentConfig {
|
|
21
|
+
hubUrl: string;
|
|
22
|
+
token: string;
|
|
23
|
+
backends: Backend[];
|
|
24
|
+
offerings: AgentOffering[];
|
|
25
|
+
}
|
|
26
|
+
export declare function agentDir(env?: NodeJS.ProcessEnv): string;
|
|
27
|
+
export declare class ConfigError extends Error {
|
|
28
|
+
readonly problems: string[];
|
|
29
|
+
constructor(message: string, problems: string[]);
|
|
30
|
+
}
|
|
31
|
+
export declare function loadAgentConfig(dir: string): {
|
|
32
|
+
config: AgentConfig;
|
|
33
|
+
secrets: Record<string, string>;
|
|
34
|
+
};
|
|
35
|
+
/** tmp+rename atomic write with owner-only permissions. */
|
|
36
|
+
export declare function writeFileAtomic(path: string, content: string, mode?: number): void;
|
|
37
|
+
export declare const CONFIG_TEMPLATE = "# aweshare agent configuration (~/.aweshare/config.toml)\n# Secrets live in ~/.aweshare/secrets.json and never leave this machine.\n\nhubUrl = \"http://127.0.0.1:8787\"\ntoken = \"asp_PASTE_PRODUCER_TOKEN\"\n\n# Backends hold the upstream API. baseUrl follows the SDK convention:\n# openai-style (OpenAI/Ollama/vLLM/LM Studio) includes /v1, e.g. http://127.0.0.1:11434/v1\n# anthropic-style excludes /v1, e.g. https://api.anthropic.com\n# responses-style includes the version path, e.g. https://open.bigmodel.cn/api/v1\n[[backends]]\nid = \"ollama\"\nprotocol = \"openai\"\nbaseUrl = \"http://127.0.0.1:11434/v1\"\n# keyRef = \"ollama-key\" # optional; keys live in secrets.json\n\n[[backends]]\nid = \"openai\"\nprotocol = \"openai\"\nbaseUrl = \"https://api.openai.com/v1\"\nkeyRef = \"openai-key\"\n\n# Offerings map a public alias (namespace/name) to a backend model.\n# The namespace must match your producer name on the hub.\n[[offerings]]\nalias = \"YOUR_NAME/qwen2.5.7b\"\nbackend = \"ollama\"\nupstreamModel = \"qwen2.5:7b\" # must match 'ollama list' exactly, including the tag\nmaxConcurrency = 1 # start at 1 for local models\n\n[[offerings]]\nalias = \"YOUR_NAME/gpt-4o\"\nbackend = \"openai\"\nupstreamModel = \"gpt-4o-2024-11-20\"\nmaxConcurrency = 4\n";
|
|
38
|
+
export declare const SECRETS_TEMPLATE = "{\n \"openai-key\": \"sk-PASTE_YOUR_KEY\"\n}\n";
|