monoize 1.6.0 → 1.6.1-darwin-arm64
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/bin/monoize +0 -0
- package/package.json +8 -15
- package/README.md +0 -331
- package/bin/monoize.js +0 -2
package/bin/monoize
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monoize",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "A protocol-normalizing AI gateway with provider routing, fail-forward, transforms, and billing.",
|
|
3
|
+
"version": "1.6.1-darwin-arm64",
|
|
4
|
+
"description": "A protocol-normalizing AI gateway with provider routing, fail-forward, transforms, and billing. Native binary for darwin arm64.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"os": [
|
|
7
|
+
"darwin"
|
|
8
|
+
],
|
|
9
|
+
"cpu": [
|
|
10
|
+
"arm64"
|
|
11
|
+
],
|
|
10
12
|
"engines": {
|
|
11
13
|
"node": ">=18"
|
|
12
14
|
},
|
|
@@ -18,15 +20,6 @@
|
|
|
18
20
|
"url": "git+https://github.com/Ikaleio/monoize.git"
|
|
19
21
|
},
|
|
20
22
|
"homepage": "https://github.com/Ikaleio/monoize#readme",
|
|
21
|
-
"bugs": "https://github.com/Ikaleio/monoize/issues",
|
|
22
|
-
"optionalDependencies": {
|
|
23
|
-
"monoize-linux-x64": "npm:monoize@1.6.0-linux-x64",
|
|
24
|
-
"monoize-linux-arm64": "npm:monoize@1.6.0-linux-arm64",
|
|
25
|
-
"monoize-darwin-x64": "npm:monoize@1.6.0-darwin-x64",
|
|
26
|
-
"monoize-darwin-arm64": "npm:monoize@1.6.0-darwin-arm64",
|
|
27
|
-
"monoize-win32-x64": "npm:monoize@1.6.0-win32-x64",
|
|
28
|
-
"monoize-win32-arm64": "npm:monoize@1.6.0-win32-arm64"
|
|
29
|
-
},
|
|
30
23
|
"publishConfig": {
|
|
31
24
|
"access": "public"
|
|
32
25
|
}
|
package/README.md
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
<img src="frontend/public/monoize.svg" width="96" alt="Monoize logo">
|
|
4
|
-
|
|
5
|
-
# Monoize
|
|
6
|
-
|
|
7
|
-
**AI APIs look alike. Their contracts differ.**
|
|
8
|
-
|
|
9
|
-
Monoize is a Rust gateway for OpenAI Responses, Chat Completions, Anthropic Messages, Gemini, embeddings, and image APIs. It converts protocol semantics. It routes one logical model across multiple upstream channels. It handles the failure modes that appear between real clients and real gateways.
|
|
10
|
-
|
|
11
|
-
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
12
|
-
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
## The problem
|
|
16
|
-
|
|
17
|
-
An AI API gateway does more than rename JSON fields.
|
|
18
|
-
|
|
19
|
-
Responses, Chat Completions, and Messages use different data models for conversation history, reasoning, tools, usage, errors, and streaming. A converter can return HTTP 200 and still corrupt the conversation. It can drop encrypted reasoning, attach a delta to the wrong content block, duplicate a stream event, or turn a tool result into assistant text.
|
|
20
|
-
|
|
21
|
-
Routing adds another state machine. A gateway must retry a failed channel. It must move to the next provider. It must stop retrying after it commits response bytes to the client. If a gateway switches upstreams after that point, it splices two different generations into one stream.
|
|
22
|
-
|
|
23
|
-
Clients and upstream gateways also differ in their boundary behavior. Claude Code, OpenRouter-compatible clients, Codex WebSocket clients, DeepSeek tool loops, image providers, and provider-specific SSE implementations each expose different assumptions.
|
|
24
|
-
|
|
25
|
-
Large inline images add a separate cost. Upload time and upstream image preprocessing can dominate time to first token. When every retry carries the same oversized base64 payload, this cost grows.
|
|
26
|
-
|
|
27
|
-
## Where common converters fail
|
|
28
|
-
|
|
29
|
-
Format support is not protocol correctness. These public examples were checked on 2026-08-10:
|
|
30
|
-
|
|
31
|
-
- OpenAI defines `encrypted_content` as the state needed to preserve reasoning in stateless multi-turn flows. At New API commit [`823e263`](https://github.com/QuantumNous/new-api/commit/823e26304a396854ace30b52b98ec497c2dd9c36), the Responses output DTO [cannot represent that field](https://github.com/QuantumNous/new-api/blob/823e26304a396854ace30b52b98ec497c2dd9c36/relaykit/dto/openai_response.go#L327-L339). The Responses-to-Chat converter [reads only reasoning text](https://github.com/QuantumNous/new-api/blob/823e26304a396854ace30b52b98ec497c2dd9c36/relaykit/relayconvert/internal/oai_responses/to_oai_chat_resp.go#L212-L229). Format conversion therefore still drops encrypted reasoning. See the [OpenAI reasoning guide](https://developers.openai.com/api/docs/guides/reasoning#preserve-reasoning-without-stored-responses) for why that state must be replayed.
|
|
32
|
-
- LiteLLM issue [#32357](https://github.com/BerriAI/litellm/issues/32357) reports an Anthropic adapter that emits `message_start` twice and sends `thinking_delta` inside a text block. Anthropic SDKs discard that reasoning because the event violates the block lifecycle.
|
|
33
|
-
- New API issue [#5480](https://github.com/QuantumNous/new-api/issues/5480) documents streaming relay paths that retain the complete generated text only to estimate tokens. Memory then grows with output length and concurrency.
|
|
34
|
-
|
|
35
|
-
These are design failures, not missing aliases. Monoize addresses them in the protocol model, stream state machines, routing rules, and resource bounds.
|
|
36
|
-
|
|
37
|
-
## What Monoize does
|
|
38
|
-
|
|
39
|
-
### It converts semantics, not field names
|
|
40
|
-
|
|
41
|
-
Monoize decodes each supported protocol into URP v2. URP v2 is a flat and typed canonical representation. It keeps text, reasoning summary, raw reasoning, encrypted reasoning, tool calls, tool results, images, files, refusals, usage, and control boundaries as distinct nodes.
|
|
42
|
-
|
|
43
|
-
The selected upstream adapter then encodes those nodes into the target protocol. The response follows the same path in reverse.
|
|
44
|
-
|
|
45
|
-
This design gives these guarantees:
|
|
46
|
-
|
|
47
|
-
- The full Responses, Chat Completions, and Messages request/response matrix is tested in streaming and non-streaming modes.
|
|
48
|
-
- Encrypted reasoning remains separate from visible reasoning. Optional `mz2` envelopes preserve opaque reasoning across otherwise incompatible replay formats.
|
|
49
|
-
- Tool-call IDs, parallel calls, multipart tool results, and assistant history keep their roles.
|
|
50
|
-
- Responses output-item lifecycles and Messages content-block lifecycles remain ordered and balanced.
|
|
51
|
-
- Unknown same-family fields can pass through. Monoize strips unsafe nested fields at cross-family boundaries, so they do not enter an invalid request.
|
|
52
|
-
|
|
53
|
-
The [protocol test matrix](spec/urp-v2-flat-protocol-test-matrix.spec.md) defines the normative cases and their tests.
|
|
54
|
-
|
|
55
|
-
### It retries before it commits a stream
|
|
56
|
-
|
|
57
|
-
A logical model can match several ordered Providers. Each Provider can contain several weighted Channels.
|
|
58
|
-
|
|
59
|
-
Monoize tries these routes as a bounded waterfall:
|
|
60
|
-
|
|
61
|
-
1. Select the first matching Provider.
|
|
62
|
-
2. Select an eligible Channel by weight and affinity.
|
|
63
|
-
3. Retry retryable failures within the configured budgets.
|
|
64
|
-
4. When the current route is exhausted, move forward to the next eligible route.
|
|
65
|
-
5. Stop fallback after the first downstream response byte.
|
|
66
|
-
|
|
67
|
-
Network failures, timeouts, `429`, and selected `5xx` responses let the waterfall move forward. Client errors such as `400`, `401`, `403`, and `422` stop the waterfall. Circuit breakers, passive health state, active probes, cooldowns, and model affinity keep known-bad channels out of the hot path.
|
|
68
|
-
|
|
69
|
-
Monoize never switches providers in the middle of a visible stream. The exact transition rules are defined in the [routing specification](spec/monoize-upstream-routing.spec.md).
|
|
70
|
-
|
|
71
|
-
### It handles client and gateway quirks at the boundary
|
|
72
|
-
|
|
73
|
-
The core adapters cover normal protocol conversion. Ordered transforms handle behavior that belongs to one client, provider, model, or API key.
|
|
74
|
-
|
|
75
|
-
Examples include:
|
|
76
|
-
|
|
77
|
-
- OpenRouter-compatible structured reasoning and final usage chunks.
|
|
78
|
-
- DeepSeek reasoning replay during tool loops.
|
|
79
|
-
- Anthropic thinking blocks and signatures.
|
|
80
|
-
- Codex Responses WebSocket sessions and `/v1/responses/compact`.
|
|
81
|
-
- Data-URL images converted to provider-native image sources.
|
|
82
|
-
- SSE frame splitting for clients with small line buffers.
|
|
83
|
-
- Orphaned tool-call cleanup and consecutive-role repair.
|
|
84
|
-
- Role mapping for `system` and `developer`.
|
|
85
|
-
- Prompt-cache breakpoints for system prompts, tool use, and OpenAI tools.
|
|
86
|
-
- Provider-specific header removal, model suffixes, and token-budget mapping.
|
|
87
|
-
|
|
88
|
-
Transforms can run at Provider, global, or API-key scope. Model globs select where each rule applies. See the [transform specification](spec/urp-transform-system.spec.md).
|
|
89
|
-
|
|
90
|
-
### It reduces large-image overhead before the upstream call
|
|
91
|
-
|
|
92
|
-
`compress_user_message_images` is an opt-in request transform. It can resize and recompress inline user images before routing them upstream. Supported output modes include JPEG, PNG, WebP, and JPEG XL.
|
|
93
|
-
|
|
94
|
-
The transform preserves the image node and its provider-specific detail hints. It skips unsupported or remote URL sources. Input bytes, decoded pixels, concurrent encodes, cache entries, and cache bytes have explicit limits.
|
|
95
|
-
|
|
96
|
-
The transform reduces request size and the avoidable part of image-heavy TTFT. Cached results also remove duplicate encode work across retries and repeated requests.
|
|
97
|
-
|
|
98
|
-
### It runs with significantly less forwarding overhead
|
|
99
|
-
|
|
100
|
-
Monoize is significantly more efficient on the forwarding hot path than common API forwarding gateways.
|
|
101
|
-
|
|
102
|
-
- Rust and Tokio handle concurrent I/O without a language runtime or per-request interpreter work.
|
|
103
|
-
- The normal stream path decodes and re-encodes incrementally through bounded channels.
|
|
104
|
-
- Usage estimation updates counters as deltas arrive. It does not retain the complete generated text merely to count it.
|
|
105
|
-
- Rate-limit keys, routing health, affinity, API-key caches, request capture, WebSocket history, discovery bodies, and image transforms all have explicit bounds.
|
|
106
|
-
- A release build embeds the React dashboard. One process serves the API, the dashboard, and metrics.
|
|
107
|
-
|
|
108
|
-
Some response transforms intentionally select buffered synthetic streaming. Replicate also uses that path. The default protocol bridge remains incremental.
|
|
109
|
-
|
|
110
|
-
This comparison concerns proxy-side CPU, memory, and latency. It does not claim to make an upstream model generate tokens faster. See [stream usage accounting](src/handlers/usage.rs) and the [runtime resource bounds](spec/runtime-resource-bounds.spec.md).
|
|
111
|
-
|
|
112
|
-
## Supported surface
|
|
113
|
-
|
|
114
|
-
### Downstream endpoints
|
|
115
|
-
|
|
116
|
-
| Method | Endpoint | Contract |
|
|
117
|
-
| --- | --- | --- |
|
|
118
|
-
| `GET` | `/v1/models` | OpenAI-compatible model list |
|
|
119
|
-
| `POST` | `/v1/responses` | OpenAI Responses, streaming or non-streaming |
|
|
120
|
-
| `GET` | `/v1/responses` | OpenAI Responses WebSocket transport |
|
|
121
|
-
| `POST` | `/v1/responses/compact` | Responses compaction |
|
|
122
|
-
| `POST` | `/v1/chat/completions` | OpenAI Chat Completions |
|
|
123
|
-
| `POST` | `/v1/messages` | Anthropic Messages |
|
|
124
|
-
| `POST` | `/v1/embeddings` | Embeddings |
|
|
125
|
-
| `POST` | `/v1/images/generations` | Image generation |
|
|
126
|
-
| `POST` | `/v1/images/edits` | Multipart image edits |
|
|
127
|
-
|
|
128
|
-
Every forwarding endpoint also has an `/api/v1/...` alias.
|
|
129
|
-
|
|
130
|
-
### Upstream channel types
|
|
131
|
-
|
|
132
|
-
| Type | Native upstream contract |
|
|
133
|
-
| --- | --- |
|
|
134
|
-
| `responses` | OpenAI Responses-compatible |
|
|
135
|
-
| `chat_completion` | OpenAI Chat Completions-compatible |
|
|
136
|
-
| `messages` | Anthropic Messages-compatible |
|
|
137
|
-
| `gemini` | Google Gemini native |
|
|
138
|
-
| `openai_image` | OpenAI-compatible image API |
|
|
139
|
-
| `replicate` | Replicate predictions |
|
|
140
|
-
|
|
141
|
-
Providers define routing order, retry budgets, and health policy. Channels hold the actual upstream type, base URL, credential, model mapping, weight, and timeout.
|
|
142
|
-
|
|
143
|
-
## Request path
|
|
144
|
-
|
|
145
|
-
```text
|
|
146
|
-
Client protocol
|
|
147
|
-
│
|
|
148
|
-
▼
|
|
149
|
-
Decode to typed URP v2
|
|
150
|
-
│
|
|
151
|
-
▼
|
|
152
|
-
Provider waterfall ──► weighted Channel ──► circuit breaker / affinity
|
|
153
|
-
│ │
|
|
154
|
-
│ retry or fail forward
|
|
155
|
-
│ before the first byte
|
|
156
|
-
▼
|
|
157
|
-
Provider, global, and API-key transforms
|
|
158
|
-
│
|
|
159
|
-
▼
|
|
160
|
-
Upstream protocol encoding
|
|
161
|
-
│
|
|
162
|
-
▼
|
|
163
|
-
Upstream stream ──► URP v2 events ──► downstream protocol events
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Quick start
|
|
167
|
-
|
|
168
|
-
Run Monoize once with Bun:
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
bunx monoize
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Or install it globally:
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
bun add --global monoize
|
|
178
|
-
monoize
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
The same package works with npm and pnpm:
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
npx monoize
|
|
185
|
-
# or: pnpm dlx monoize
|
|
186
|
-
# global: npm install --global monoize
|
|
187
|
-
# global: pnpm add --global monoize
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
The package manager installs only the native binary for the current operating system and CPU. The npm package supports GNU libc Linux, macOS, and Windows on x86-64 and ARM64.
|
|
191
|
-
|
|
192
|
-
To build from source, install a stable Rust toolchain and [Bun](https://bun.sh/). A release build compiles the frontend and embeds it in the executable.
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
cargo build --release
|
|
196
|
-
./target/release/monoize
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
Open `http://localhost:8080`. The first registered account becomes `super_admin`, even when public registration is disabled. Then:
|
|
200
|
-
|
|
201
|
-
1. Create a Provider.
|
|
202
|
-
2. Add at least one Channel with its upstream URL and credential.
|
|
203
|
-
3. Map a logical model to the Channel.
|
|
204
|
-
4. Create an API key.
|
|
205
|
-
|
|
206
|
-
### Docker
|
|
207
|
-
|
|
208
|
-
The published image supports Linux x86-64 and ARM64. Run it with a persistent SQLite volume:
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
docker run -d \
|
|
212
|
-
--name monoize \
|
|
213
|
-
--restart unless-stopped \
|
|
214
|
-
-p 8080:8080 \
|
|
215
|
-
-v monoize-data:/app/data \
|
|
216
|
-
ghcr.io/ikaleio/monoize:latest
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
To use PostgreSQL or a non-default SQLite location, set `MONOIZE_DATABASE_DSN` with `-e`.
|
|
220
|
-
|
|
221
|
-
Call the logical model through any supported downstream protocol:
|
|
222
|
-
|
|
223
|
-
```bash
|
|
224
|
-
curl http://localhost:8080/v1/responses \
|
|
225
|
-
-H 'Authorization: Bearer sk-your-monoize-key' \
|
|
226
|
-
-H 'Content-Type: application/json' \
|
|
227
|
-
-d '{
|
|
228
|
-
"model": "your-logical-model",
|
|
229
|
-
"input": "Explain why stream fallback must stop after the first byte.",
|
|
230
|
-
"stream": true
|
|
231
|
-
}'
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## Configuration
|
|
235
|
-
|
|
236
|
-
Runtime bootstrap uses environment variables. The database stores Providers, Channels, models, routing policy, transforms, users, and API keys. The dashboard manages them.
|
|
237
|
-
|
|
238
|
-
| Variable | Default | Purpose |
|
|
239
|
-
| --- | --- | --- |
|
|
240
|
-
| `MONOIZE_LISTEN` | `0.0.0.0:8080` | HTTP listen address |
|
|
241
|
-
| `MONOIZE_DATABASE_DSN` | `sqlite://./data/monoize.db` | SQLite or PostgreSQL DSN |
|
|
242
|
-
| `DATABASE_URL` | unset | Fallback DSN when `MONOIZE_DATABASE_DSN` is unset |
|
|
243
|
-
| `MONOIZE_METRICS_PATH` | `/metrics` | Prometheus metrics path |
|
|
244
|
-
| `MONOIZE_HTTP_BODY_MAX_BYTES` | `52428800` | Forwarding request-body limit |
|
|
245
|
-
| `MONOIZE_TRUSTED_PROXY_CIDRS` | `127.0.0.0/8,::1/128` | Trusted reverse-proxy networks; an explicitly empty value disables trust |
|
|
246
|
-
| `MONOIZE_UPSTREAM_PROXY_URL` | unset | Node-local outbound HTTP(S) proxy for upstream calls; channels may override per channel via `proxy_url` |
|
|
247
|
-
| `MONOIZE_CAP_API_ENDPOINT` | unset | Optional external Cap site endpoint including the site-key path; unset uses Monoize's built-in Cap service |
|
|
248
|
-
| `MONOIZE_CAP_SECRET_KEY` | unset | Secret for the external Cap site; configure it together with `MONOIZE_CAP_API_ENDPOINT` |
|
|
249
|
-
|
|
250
|
-
Dashboard login and registration use Monoize's built-in Cap proof-of-work service by default and require no extra configuration. Administrators can disable human verification under system settings, which removes bot and credential-stuffing protection from these endpoints. To use [Cap Standalone](https://capjs.js.org/guide/) instead, create one site key, set both variables above, and allow the dashboard origin in Cap's CORS configuration. Monoize then verifies each token through the site's `/siteverify` endpoint.
|
|
251
|
-
|
|
252
|
-
Monoize supports SQLite and PostgreSQL. One Monoize application process is the supported writer for its business tables.
|
|
253
|
-
|
|
254
|
-
### Primary/replica deployment
|
|
255
|
-
|
|
256
|
-
Monoize can run as one writable primary plus read-only replicas. All nodes share one PostgreSQL database (`spec/primary-replica-deployment.spec.md`). Replicas serve `/v1/**` traffic only. They do not serve the dashboard. Replicas ship request logs and billing deltas to the primary over an authenticated internal API. Balance checks subtract locally unshipped charges to keep overspend bounded. Failover is manual: to promote a replica, switch its role and restart it.
|
|
257
|
-
|
|
258
|
-
| Variable | Default | Purpose |
|
|
259
|
-
| --- | --- | --- |
|
|
260
|
-
| `MONOIZE_NODE_ROLE` | `primary` | `primary` or `replica` |
|
|
261
|
-
| `MONOIZE_PRIMARY_INTERNAL_URL` | required on replicas | Base URL of the primary for metering shipment |
|
|
262
|
-
| `MONOIZE_REPLICA_TOKEN` | unset | Shared secret: required on replicas; on a primary it enables the ingest endpoint |
|
|
263
|
-
| `MONOIZE_REPLICA_ID` | auto-generated and persisted | Fixed replica identity (UUID v4). When unset, an identity is generated once and persisted as `replica-identity` inside the metering spool directory, so the ID survives restarts |
|
|
264
|
-
| `MONOIZE_CONFIG_POLL_INTERVAL_SECONDS` | `5` | Replica config-epoch poll interval |
|
|
265
|
-
| `MONOIZE_METERING_SHIP_INTERVAL_SECONDS` | `10` | Replica metering shipment interval |
|
|
266
|
-
| `MONOIZE_METERING_SHIP_BATCH_MAX_ENTRIES` | `500` | Per-batch entry cap (hard cap 2000) |
|
|
267
|
-
| `MONOIZE_REPLICA_METERING_SPOOL_DIR` | `./data/replica-metering-spool` | Durable delta spool directory |
|
|
268
|
-
|
|
269
|
-
## Operations
|
|
270
|
-
|
|
271
|
-
The embedded dashboard manages:
|
|
272
|
-
|
|
273
|
-
- Providers, Channels, health, priority, model mapping, and pricing multipliers.
|
|
274
|
-
- API keys, quotas, model restrictions, IP allowlists, transforms, and sub-accounts.
|
|
275
|
-
- Users, balances, nano-dollar billing, and an append-only ledger.
|
|
276
|
-
- Request logs with TTFB, duration, token usage, cost, errors, and tried routes.
|
|
277
|
-
- Model metadata and pricing imported from [Models.dev](https://models.dev).
|
|
278
|
-
- Prometheus metrics and live operational views.
|
|
279
|
-
|
|
280
|
-
Request capture is opt-in and bounded. Credentials and prompt bodies are not part of normal observability logs.
|
|
281
|
-
|
|
282
|
-
## Limits and non-goals
|
|
283
|
-
|
|
284
|
-
- Monoize forwards tool definitions and tool calls. It does not execute tools locally.
|
|
285
|
-
- Monoize does not provide OpenAI Files, vector stores, or local retrieval.
|
|
286
|
-
- Responses object storage and later object retrieval are not implemented.
|
|
287
|
-
- Fallback ends after downstream bytes begin. Mid-stream provider switching is intentionally forbidden.
|
|
288
|
-
- Cross-family conversion preserves representable semantics. Provider-specific nested fields that have no safe target representation are intentionally removed.
|
|
289
|
-
- Image compression is opt-in. It does not fetch arbitrary remote image URLs unless the separate URL-resolution transform is configured.
|
|
290
|
-
|
|
291
|
-
## Release artifacts
|
|
292
|
-
|
|
293
|
-
A GitHub Release whose tag equals `v` plus the Cargo package version triggers the [release workflow](.github/workflows/release.yml). The workflow builds native x86-64 and ARM64 binaries for Linux, macOS, and Windows.
|
|
294
|
-
|
|
295
|
-
Linux and macOS assets use `tar.gz`. Windows assets use `zip`. Every archive includes both READMEs and the license. Every archive has a separate SHA-256 file. The workflow uploads nothing until all six builds and all checksum checks succeed.
|
|
296
|
-
|
|
297
|
-
A manual workflow run executes the same six-platform preflight. It does not change a GitHub Release. The exact asset contract is defined in the [release artifact specification](spec/release-artifacts.spec.md).
|
|
298
|
-
|
|
299
|
-
The workflow also builds seven npm tarballs: one TypeScript-derived launcher and six platform packages. A normal Bun, npm, or pnpm installation selects one platform package through `os` and `cpu` metadata. Publishing the package set requires the `NPM_TOKEN` Actions secret. The exact npm contract is defined in the [npm CLI distribution specification](spec/npm-cli-distribution.spec.md).
|
|
300
|
-
|
|
301
|
-
## Development and verification
|
|
302
|
-
|
|
303
|
-
Run the backend tests:
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
cargo test
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
Run the frontend checks:
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
cd frontend
|
|
313
|
-
bun install
|
|
314
|
-
bun run lint
|
|
315
|
-
bun run build
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
Run the live three-protocol suite against a configured instance:
|
|
319
|
-
|
|
320
|
-
```bash
|
|
321
|
-
cd sdk-tests
|
|
322
|
-
bun run live-protocol-suite.ts <baseURL> <apiKey> <model>
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
The suite checks non-streaming text, streaming text, tool loops, and streaming tool loops through Chat Completions, Responses, and Messages.
|
|
326
|
-
|
|
327
|
-
Observable behavior is specified under [`spec/`](spec/). Code and specifications change together.
|
|
328
|
-
|
|
329
|
-
## License
|
|
330
|
-
|
|
331
|
-
Monoize is licensed under the [MIT License](LICENSE).
|
package/bin/monoize.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{spawn as w}from"node:child_process";import{existsSync as v,realpathSync as b}from"node:fs";import{createRequire as y}from"node:module";import s from"node:path";import{fileURLToPath as S}from"node:url";var h=[{rustTarget:"x86_64-unknown-linux-gnu",packageAlias:"monoize-linux-x64",versionSuffix:"linux-x64",platform:"linux",architecture:"x64",executable:"monoize"},{rustTarget:"aarch64-unknown-linux-gnu",packageAlias:"monoize-linux-arm64",versionSuffix:"linux-arm64",platform:"linux",architecture:"arm64",executable:"monoize"},{rustTarget:"x86_64-apple-darwin",packageAlias:"monoize-darwin-x64",versionSuffix:"darwin-x64",platform:"darwin",architecture:"x64",executable:"monoize"},{rustTarget:"aarch64-apple-darwin",packageAlias:"monoize-darwin-arm64",versionSuffix:"darwin-arm64",platform:"darwin",architecture:"arm64",executable:"monoize"},{rustTarget:"x86_64-pc-windows-msvc",packageAlias:"monoize-win32-x64",versionSuffix:"win32-x64",platform:"win32",architecture:"x64",executable:"monoize.exe"},{rustTarget:"aarch64-pc-windows-msvc",packageAlias:"monoize-win32-arm64",versionSuffix:"win32-arm64",platform:"win32",architecture:"arm64",executable:"monoize.exe"}];function u(e,n){return h.find((r)=>r.platform===e&&r.architecture===n)}var m=b(S(import.meta.url)),T=y(m).resolve;function k(e=process.env,n=process.argv[1]??"",r=m){let o=e.npm_config_user_agent??"",t=e.npm_execpath??"";if(/\bpnpm\//.test(o)||t.includes("pnpm")||r.includes(`${s.sep}.pnpm${s.sep}`))return"pnpm";if(/\bbun\//.test(o)||t.includes("bun")||n.includes(".bun/install/global")||n.includes(".bun\\install\\global"))return"bun";return"npm"}function N(e){switch(e){case"bun":return"bun install -g monoize@latest";case"pnpm":return"pnpm add -g monoize@latest";default:return"npm install -g monoize@latest"}}function g(e=process.platform,n=process.arch){let r=u(e,n);if(!r)throw Error(`unsupported platform: ${e} (${n})`);return r}function d(e,n=T,r=v){let o;try{o=n(`${e.packageAlias}/package.json`)}catch{throw Error(`missing optional dependency ${e.packageAlias}`)}let t=s.join(s.dirname(o),"bin",e.executable);if(!r(t))throw Error(`missing optional dependency ${e.packageAlias}: expected ${e.executable}`);return t}async function x(e,n){let r=w(e,[...n],{cwd:process.cwd(),env:process.env,stdio:"inherit"}),o=["SIGINT","SIGTERM","SIGHUP"],t=new Map;for(let a of o){let i=()=>{if(!r.killed)try{r.kill(a)}catch{}};t.set(a,i),process.on(a,i)}let l=()=>{for(let[a,i]of t)process.off(a,i)};return await new Promise((a,i)=>{r.once("error",(c)=>{l(),i(c)}),r.once("exit",(c,p)=>{if(l(),p)a({type:"signal",signal:p});else a({type:"code",exitCode:c??1})})})}function f(e){let n=e instanceof Error?e.message:String(e);if(!n.startsWith("missing optional dependency"))return`monoize: ${n}`;let r=N(k());return`monoize: ${n}. Reinstall with: ${r}`}try{let e=g(),n=d(e),r=await x(n,process.argv.slice(2));if(r.type==="signal")process.kill(process.pid,r.signal);else process.exit(r.exitCode)}catch(e){console.error(f(e)),process.exit(1)}
|