@mmmbuto/anthmorph 0.1.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/Cargo.lock +1935 -0
- package/Cargo.toml +61 -0
- package/LICENSE +21 -0
- package/README.md +184 -0
- package/bin/anthmorph +22 -0
- package/package.json +52 -0
- package/scripts/anthmorphctl +456 -0
- package/scripts/postinstall.js +23 -0
- package/scripts/smoke_test.sh +72 -0
- package/src/config.rs +39 -0
- package/src/error.rs +54 -0
- package/src/main.rs +120 -0
- package/src/models/anthropic.rs +274 -0
- package/src/models/mod.rs +2 -0
- package/src/models/openai.rs +230 -0
- package/src/proxy.rs +829 -0
- package/src/transform.rs +460 -0
- package/tests/real_backends.rs +213 -0
package/Cargo.toml
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "AnthMorph"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Anthropic to OpenAI-compatible proxy"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
repository = "https://github.com/DioNanos/AnthMorph"
|
|
8
|
+
homepage = "https://github.com/DioNanos/AnthMorph"
|
|
9
|
+
authors = ["DioNanos <noreply@github.com>"]
|
|
10
|
+
|
|
11
|
+
[[bin]]
|
|
12
|
+
name = "anthmorph"
|
|
13
|
+
path = "src/main.rs"
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
# Async runtime
|
|
17
|
+
tokio = { version = "1.42", features = ["rt-multi-thread", "macros"] }
|
|
18
|
+
|
|
19
|
+
# Web framework
|
|
20
|
+
axum = { version = "0.7", features = ["http2"] }
|
|
21
|
+
|
|
22
|
+
# HTTP client
|
|
23
|
+
reqwest = { version = "0.12", features = ["json", "stream", "rustls-tls"], default-features = false }
|
|
24
|
+
|
|
25
|
+
# Serialization
|
|
26
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
27
|
+
serde_json = "1.0"
|
|
28
|
+
|
|
29
|
+
# Async utilities
|
|
30
|
+
futures = "0.3"
|
|
31
|
+
tokio-stream = "0.1"
|
|
32
|
+
|
|
33
|
+
# Observability
|
|
34
|
+
tracing = "0.1"
|
|
35
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
36
|
+
|
|
37
|
+
# Error handling
|
|
38
|
+
anyhow = "1.0"
|
|
39
|
+
thiserror = "2.0"
|
|
40
|
+
|
|
41
|
+
# Environment variables
|
|
42
|
+
dotenvy = "0.15"
|
|
43
|
+
|
|
44
|
+
# CLI argument parsing
|
|
45
|
+
clap = { version = "4.5", features = ["derive"] }
|
|
46
|
+
|
|
47
|
+
# Server utilities
|
|
48
|
+
tower = { version = "0.5", features = ["util"] }
|
|
49
|
+
tower-http = { version = "0.6", features = ["trace", "cors"] }
|
|
50
|
+
|
|
51
|
+
# Async streams
|
|
52
|
+
async-stream = "0.3"
|
|
53
|
+
bytes = "1.9"
|
|
54
|
+
pin-project = "1.1"
|
|
55
|
+
|
|
56
|
+
[profile.release]
|
|
57
|
+
opt-level = "z"
|
|
58
|
+
lto = true
|
|
59
|
+
codegen-units = 1
|
|
60
|
+
strip = true
|
|
61
|
+
panic = "abort"
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DioNanos
|
|
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,184 @@
|
|
|
1
|
+
# AnthMorph
|
|
2
|
+
|
|
3
|
+
[](#project-status)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.rust-lang.org)
|
|
6
|
+
[](https://termux.dev)
|
|
7
|
+
[](https://www.npmjs.com/package/@mmmbuto/anthmorph)
|
|
8
|
+
|
|
9
|
+
AnthMorph is a Chutes-first Anthropic `/v1/messages` proxy written in Rust.
|
|
10
|
+
It lets Claude-style clients talk to Chutes or other OpenAI-compatible backends through a safer, profile-aware translation layer.
|
|
11
|
+
|
|
12
|
+
Core capabilities:
|
|
13
|
+
- Anthropic `/v1/messages` ingress with OpenAI-compatible upstream translation
|
|
14
|
+
- `chutes` profile optimized for Chutes-specific compatibility, including `top_k` and reasoning handling
|
|
15
|
+
- `openai_generic` profile for conservative compatibility with generic OpenAI-style providers
|
|
16
|
+
- Streaming SSE translation with fragmented tool-call handling
|
|
17
|
+
- Local control CLI for init, start, stop, restart, status, and logs
|
|
18
|
+
- Termux-friendly workflow with optional npm distribution
|
|
19
|
+
|
|
20
|
+
## Project Status
|
|
21
|
+
|
|
22
|
+
- Current line: `0.1.0`
|
|
23
|
+
- Primary target: `chutes.ai`
|
|
24
|
+
- Secondary target: generic OpenAI-compatible endpoints
|
|
25
|
+
- Tested locally against Chutes, MiniMax, and Alibaba Coding Plan rejection handling
|
|
26
|
+
- Distribution paths: source build and npm package under `@mmmbuto/anthmorph`
|
|
27
|
+
- Repository metadata is aligned for GitHub and npm publication
|
|
28
|
+
|
|
29
|
+
## Quickstart
|
|
30
|
+
|
|
31
|
+
1. Install
|
|
32
|
+
|
|
33
|
+
Source build:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cargo build --release
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Global npm install:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @mmmbuto/anthmorph
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
2. Initialize Chutes profile
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export CHUTES_API_KEY=your_key_here
|
|
49
|
+
anthmorphctl init chutes --port 3107
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
3. Start proxy
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
anthmorphctl start
|
|
56
|
+
anthmorphctl status
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
4. Stop proxy
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
anthmorphctl stop
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## CLI Control
|
|
66
|
+
|
|
67
|
+
`anthmorphctl` is the operator entrypoint.
|
|
68
|
+
It stores runtime state under `.anthmorph/` in the project root.
|
|
69
|
+
|
|
70
|
+
Common commands:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
anthmorphctl init chutes
|
|
74
|
+
anthmorphctl init minimax
|
|
75
|
+
anthmorphctl init openai --backend-url https://api.example.com/v1 --model my-model --key-env EXAMPLE_API_KEY
|
|
76
|
+
anthmorphctl start
|
|
77
|
+
anthmorphctl status
|
|
78
|
+
anthmorphctl logs
|
|
79
|
+
anthmorphctl stop
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Direct binary usage is also available:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
anthmorph --port 3107 --backend-profile chutes --backend-url https://llm.chutes.ai/v1 --model Qwen/Qwen3-Coder-Next-TEE --api-key "$CHUTES_API_KEY"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
- `Ingress`: accepts Anthropic `/v1/messages` requests and validates profile-safe behavior.
|
|
91
|
+
- `Transform`: converts Anthropic messages, tools, and stop reasons into OpenAI-compatible payloads.
|
|
92
|
+
- `Streaming`: translates upstream SSE chunks back into Anthropic-style streaming events.
|
|
93
|
+
- `Profiles`: selects `chutes` or `openai_generic` behavior for request and response handling.
|
|
94
|
+
- `Control CLI`: manages local config, runtime state, start/stop/status, and operator logs.
|
|
95
|
+
|
|
96
|
+
## API Key Policy
|
|
97
|
+
|
|
98
|
+
Preferred mode:
|
|
99
|
+
- Store only the environment variable name with `anthmorphctl set key-env ENV_NAME`
|
|
100
|
+
- Keep the secret in your shell environment
|
|
101
|
+
|
|
102
|
+
Optional mode:
|
|
103
|
+
- Persist the key locally with `anthmorphctl set key VALUE --save`
|
|
104
|
+
|
|
105
|
+
Recommendation:
|
|
106
|
+
- Do not save API keys in the repo by default
|
|
107
|
+
- Use env vars for daily operation and CI
|
|
108
|
+
|
|
109
|
+
## Backend Profiles
|
|
110
|
+
|
|
111
|
+
- `chutes`: optimized path for Chutes, including `top_k` pass-through and reasoning support
|
|
112
|
+
- `openai_generic`: strips nonstandard fields and fails conservatively when the backend cannot represent Anthropic semantics safely
|
|
113
|
+
|
|
114
|
+
## Safety Rules
|
|
115
|
+
|
|
116
|
+
- Assistant thinking blocks in request history are rejected instead of being downgraded to plain text
|
|
117
|
+
- Generic mode rejects backend reasoning content that cannot be represented safely
|
|
118
|
+
- Streaming tool-call deltas support contiguous fragments and fail closed on unsafe interleaving
|
|
119
|
+
- Optional ingress auth supports `Authorization: Bearer ...` or `x-api-key`
|
|
120
|
+
- CORS is disabled unless explicitly configured
|
|
121
|
+
|
|
122
|
+
## Real Backend Coverage
|
|
123
|
+
|
|
124
|
+
Current integration coverage:
|
|
125
|
+
- `chutes.ai`: positive end-to-end smoke test
|
|
126
|
+
- `MiniMax`: positive end-to-end smoke test in generic mode
|
|
127
|
+
- `Alibaba Coding Plan`: negative expected test documenting upstream rejection for generic chat-completions flow
|
|
128
|
+
|
|
129
|
+
## npm Packaging
|
|
130
|
+
|
|
131
|
+
This repository already includes npm packaging files:
|
|
132
|
+
- `package.json`
|
|
133
|
+
- `bin/anthmorph`
|
|
134
|
+
- `scripts/postinstall.js`
|
|
135
|
+
|
|
136
|
+
Packaging behavior:
|
|
137
|
+
- `npm install -g @mmmbuto/anthmorph` exposes `anthmorph` and `anthmorphctl`
|
|
138
|
+
- `postinstall` tries to build the Rust binary with `cargo build --release`
|
|
139
|
+
- if the binary is missing later, the `anthmorph` shim will try to build it on demand
|
|
140
|
+
|
|
141
|
+
## Build And Test
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cargo test
|
|
145
|
+
npm pack --dry-run
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Real backend smoke tests:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
./scripts/smoke_test.sh chutes
|
|
152
|
+
./scripts/smoke_test.sh minimax
|
|
153
|
+
./scripts/smoke_test.sh alibaba
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Repository Layout
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
src/ Rust proxy implementation
|
|
160
|
+
bin/ npm-exposed executable shims
|
|
161
|
+
scripts/ control CLI, smoke tests, npm postinstall
|
|
162
|
+
tests/ protocol and real-backend integration tests
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Documentation
|
|
166
|
+
|
|
167
|
+
- Repository: https://github.com/DioNanos/AnthMorph
|
|
168
|
+
- npm package: https://www.npmjs.com/package/@mmmbuto/anthmorph
|
|
169
|
+
- Issue tracker: https://github.com/DioNanos/AnthMorph/issues
|
|
170
|
+
|
|
171
|
+
## Roadmap
|
|
172
|
+
|
|
173
|
+
1. Broader compatibility validation across more OpenAI-compatible providers
|
|
174
|
+
2. End-to-end validation against real Claude-style clients
|
|
175
|
+
3. Public-deployment hardening with rate limits and clearer auth policy
|
|
176
|
+
4. Better streaming coverage for complex multi-tool interleaving
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT License
|
|
181
|
+
<p>
|
|
182
|
+
Copyright (c) 2026 DioNanos<br>
|
|
183
|
+
Made in Italy
|
|
184
|
+
</p>
|
package/bin/anthmorph
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
|
5
|
+
RELEASE_BIN=$ROOT_DIR/target/release/anthmorph
|
|
6
|
+
DEBUG_BIN=$ROOT_DIR/target/debug/anthmorph
|
|
7
|
+
|
|
8
|
+
if [ -x "$RELEASE_BIN" ]; then
|
|
9
|
+
exec "$RELEASE_BIN" "$@"
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
if [ -x "$DEBUG_BIN" ]; then
|
|
13
|
+
exec "$DEBUG_BIN" "$@"
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
if command -v cargo >/dev/null 2>&1; then
|
|
17
|
+
(cd "$ROOT_DIR" && cargo build --release --quiet)
|
|
18
|
+
exec "$RELEASE_BIN" "$@"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "anthmorph binary not found and cargo is unavailable" >&2
|
|
22
|
+
exit 1
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mmmbuto/anthmorph",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Chutes-first Anthropic /v1/messages proxy for Chutes and OpenAI-compatible backends",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "DioNanos <noreply@github.com>",
|
|
7
|
+
"bin": {
|
|
8
|
+
"anthmorph": "bin/anthmorph",
|
|
9
|
+
"anthmorphctl": "scripts/anthmorphctl"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin/",
|
|
13
|
+
"scripts/anthmorphctl",
|
|
14
|
+
"scripts/postinstall.js",
|
|
15
|
+
"scripts/smoke_test.sh",
|
|
16
|
+
"src/",
|
|
17
|
+
"tests/",
|
|
18
|
+
"Cargo.toml",
|
|
19
|
+
"Cargo.lock",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"postinstall": "node scripts/postinstall.js",
|
|
25
|
+
"build:rust": "cargo build --release",
|
|
26
|
+
"test": "cargo test",
|
|
27
|
+
"pack:dry-run": "npm pack --dry-run"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"anthropic",
|
|
31
|
+
"claude",
|
|
32
|
+
"proxy",
|
|
33
|
+
"chutes",
|
|
34
|
+
"openai-compatible",
|
|
35
|
+
"termux",
|
|
36
|
+
"rust"
|
|
37
|
+
],
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/DioNanos/AnthMorph.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/DioNanos/AnthMorph#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/DioNanos/AnthMorph/issues"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
}
|
|
52
|
+
}
|