@route_33/opencode 0.4.6 → 0.4.7-rc.11
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/README.md +74 -88
- package/dist/cli/production-smoke/production-smoke.js +1665 -0
- package/dist/index.js +3886 -1232
- package/dist/tui-entry/index.js +7935 -0
- package/dist/v2-entry/index.js +4304 -0
- package/package.json +38 -42
- package/LICENSE +0 -21
- package/dist/index.d.ts +0 -23
- package/dist/tui/index.d.ts +0 -5
- package/dist/tui/index.js +0 -542
- package/docs/gateway-limits-variants-broadcast.md +0 -146
- package/docs/gateway-pricing-proposal.md +0 -96
- package/docs/getting-started.html +0 -570
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# Gateway model metadata broadcast
|
|
2
|
-
|
|
3
|
-
**To:** R33 gateway team
|
|
4
|
-
**From:** opencode-route33 plugin maintainers
|
|
5
|
-
**Date:** 2026-08-10
|
|
6
|
-
**Subject:** Shipped per-model metadata in `GET /v1/models`
|
|
7
|
-
|
|
8
|
-
## Problem
|
|
9
|
-
|
|
10
|
-
This document is the limits and variants sibling of the [gateway pricing broadcast proposal](./gateway-pricing-proposal.md) from 2026-07-07. That contract shipped and proved that extra JSON fields on the standard OpenAI-compatible `/v1/models` response do not break clients.
|
|
11
|
-
|
|
12
|
-
The opencode-route33 plugin previously kept a static seed catalog with hardcoded `context_window`, `max_output_tokens`, capability flags, and variant definitions. That file has been deleted. The gateway already persists `context_window` and `max_output_tokens` on `canonical_models`, and the catalog now needs to treat variants as platform-curated data (for example, `kimi-k3`'s `max` variant that sets `reasoningEffort: "max"`). Without a broadcast contract, plugin consumers fall back to stale seed data or fabricated defaults, which violates the never-accept-loss principle for model metadata.
|
|
13
|
-
|
|
14
|
-
This creates three gaps:
|
|
15
|
-
|
|
16
|
-
1. **Stale or fabricated limits.** The plugin has no source of truth for token ceilings once the seed catalog is gone.
|
|
17
|
-
2. **Variants out of sync.** Model-specific parameter variants (max reasoning effort, output style presets, and so on) must live with the curated catalog, not in a plugin-side JSON file.
|
|
18
|
-
3. **New-model lag.** A model that appears in the gateway catalog without published limit/variant metadata is treated as a lossy fallback.
|
|
19
|
-
|
|
20
|
-
## Recommendation
|
|
21
|
-
|
|
22
|
-
**Status: shipped.** Each entry of the existing `GET /v1/models` response supports these optional metadata fields:
|
|
23
|
-
|
|
24
|
-
- `limits`: `{ "context": number, "output": number }`, present only when both values are positive integers.
|
|
25
|
-
- `variants`: `Record<string, Record<string, unknown>>`, passed through verbatim from the platform's curated catalog.
|
|
26
|
-
- `modalities`: `{ "input": ["text"|"audio"|"image"|"video"|"pdf"], "output": ["text"|"audio"|"image"|"video"|"pdf"] }`.
|
|
27
|
-
- `attachment`: boolean, derived by the gateway as true when `modalities.input` contains `image` or `pdf`.
|
|
28
|
-
|
|
29
|
-
Existing unchanged fields (`id`, `object`, `created`, `owned_by`, plus optional `display_name`, `pricing`, `capabilities`, and `endpoints`) remain unchanged. Extra JSON fields still do not break OpenAI-compatible clients, so the catalog stays one round trip and atomically consistent.
|
|
30
|
-
|
|
31
|
-
### Concrete JSON example
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"object": "list",
|
|
36
|
-
"data": [
|
|
37
|
-
{
|
|
38
|
-
"id": "anthropic/claude-opus-4-8",
|
|
39
|
-
"object": "model",
|
|
40
|
-
"created": 1767225600,
|
|
41
|
-
"owned_by": "anthropic",
|
|
42
|
-
"display_name": "Claude Opus 4.8",
|
|
43
|
-
"pricing": {
|
|
44
|
-
"input": 5,
|
|
45
|
-
"output": 25,
|
|
46
|
-
"cache_read": 0.5,
|
|
47
|
-
"cache_write": 6.25
|
|
48
|
-
},
|
|
49
|
-
"capabilities": {
|
|
50
|
-
"modality": "text",
|
|
51
|
-
"context_tier": "large",
|
|
52
|
-
"tool_support": true,
|
|
53
|
-
"structured_output": true,
|
|
54
|
-
"generation_class": "chat",
|
|
55
|
-
"reasoning": true
|
|
56
|
-
},
|
|
57
|
-
"endpoints": ["chat", "messages"],
|
|
58
|
-
"limits": {
|
|
59
|
-
"context": 1000000,
|
|
60
|
-
"output": 128000
|
|
61
|
-
},
|
|
62
|
-
"variants": {
|
|
63
|
-
"max": {
|
|
64
|
-
"reasoningEffort": "max"
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
"modalities": { "input": ["text", "image"], "output": ["text"] },
|
|
68
|
-
"attachment": true
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Field semantics
|
|
75
|
-
|
|
76
|
-
| Field | Type | Meaning |
|
|
77
|
-
| --- | --- | --- |
|
|
78
|
-
| `id` | string | Canonical model identifier in `vendor/slug` form |
|
|
79
|
-
| `object` | string | Always `"model"` |
|
|
80
|
-
| `created` | integer | Unix epoch timestamp when the model was added to the catalog |
|
|
81
|
-
| `owned_by` | string | Model vendor, matching the `vendor` portion of `id` |
|
|
82
|
-
| `display_name` | string or omitted | Human-readable model label |
|
|
83
|
-
| `pricing` | object or omitted | Pricing object as defined in the 2026-07-07 pricing broadcast |
|
|
84
|
-
| `capabilities` | object or omitted | Structured capability flags |
|
|
85
|
-
| `capabilities.modality` | string | Input/output modality, for example `"text"` |
|
|
86
|
-
| `capabilities.context_tier` | string | Qualitative size class, for example `"large"` |
|
|
87
|
-
| `capabilities.tool_support` | boolean | Native tool calling; mapped to opencode `tool_call` when `true` |
|
|
88
|
-
| `capabilities.structured_output` | boolean | Native structured / JSON mode support |
|
|
89
|
-
| `capabilities.generation_class` | string | Interaction style, for example `"chat"` |
|
|
90
|
-
| `capabilities.reasoning` | boolean | Exposes reasoning or extended thinking; mapped to opencode `reasoning` when `true` |
|
|
91
|
-
| `endpoints` | array of strings or omitted | Supported gateway endpoints, for example `["chat", "messages"]` |
|
|
92
|
-
| `limits` | object or omitted | Per-model token limits |
|
|
93
|
-
| `limits.context` | positive integer | Maximum context-window tokens |
|
|
94
|
-
| `limits.output` | positive integer | Maximum completion tokens |
|
|
95
|
-
| `variants` | object or omitted | Per-model parameter variants, a record of records |
|
|
96
|
-
| `modalities` | object or omitted | Exact supported input and output media types |
|
|
97
|
-
| `modalities.input` | array | Zero or more of `text`, `audio`, `image`, `video`, `pdf` |
|
|
98
|
-
| `modalities.output` | array | Zero or more of `text`, `audio`, `image`, `video`, `pdf` |
|
|
99
|
-
| `attachment` | boolean or omitted | Gateway-derived file/image support (`input` includes `image` or `pdf`) |
|
|
100
|
-
|
|
101
|
-
### Consumer parse rules
|
|
102
|
-
|
|
103
|
-
The opencode-route33 plugin consumes this shape with the following rules:
|
|
104
|
-
|
|
105
|
-
- `limits` is accepted only when both `context` and `output` are present and are positive integers. Partial or invalid `limits` objects are ignored. This mirrors the models.dev `normalizeLimit` rule.
|
|
106
|
-
- `capabilities.reasoning` with the boolean value `true` maps to opencode's `reasoning` flag. Any non-boolean value is skipped.
|
|
107
|
-
- `capabilities.tool_support` with the boolean value `true` maps to opencode's `tool_call` flag. Any non-boolean value is skipped.
|
|
108
|
-
- `variants` is accepted only when it is a `Record<string, Record<string, unknown>>` and is passed through verbatim. Malformed variants are skipped.
|
|
109
|
-
- `modalities` is accepted only as an object with array `input` and `output` fields. Consumers drop unrecognized modality values; malformed modality shapes are omitted for that one model.
|
|
110
|
-
- `attachment` is accepted only when boolean; a non-boolean value is omitted for that one model.
|
|
111
|
-
- `capabilities.modality` is legacy qualitative metadata. `modalities` is the authoritative exact media contract.
|
|
112
|
-
- Unknown or malformed fields are ignored. Parsing is never fatal.
|
|
113
|
-
|
|
114
|
-
### Why embed limits and variants on `/v1/models`
|
|
115
|
-
|
|
116
|
-
- **Single round trip.** The plugin fetches the catalog anyway, so embedding removes a second request for limit and variant metadata.
|
|
117
|
-
- **No client breakage.** OpenAI-compatible consumers ignore unknown keys, so existing integrations keep working exactly as before.
|
|
118
|
-
- **Curator is the source of truth.** The platform owns `canonical_models.context_window`, `canonical_models.max_output_tokens`, and the JSONB variants column, so the broadcast comes from the same place the gateway already trusts.
|
|
119
|
-
- **No unit conversion or schema drift.** `limits.context` and `limits.output` are plain token counts, identical to opencode's internal limit schema, and `variants` is a passthrough of the platform JSONB value.
|
|
120
|
-
|
|
121
|
-
## Curated-limits audit reference (models.dev parity, verified 2026-08-10)
|
|
122
|
-
|
|
123
|
-
These entries were cross-checked against models.dev on 2026-08-10 and should be the values broadcast by the gateway:
|
|
124
|
-
|
|
125
|
-
- Anthropic `claude-opus-4-8`, `claude-sonnet-5`, `claude-fable-5`: `1,000,000` context / `128,000` output
|
|
126
|
-
- Anthropic `claude-haiku-4-5`: `200,000` context / `64,000` output
|
|
127
|
-
- `moonshotai/kimi-k3`: `1,048,576` context / `131,072` output, with the `max` variant (`reasoningEffort: "max"`)
|
|
128
|
-
- `minimax/minimax-m3`, `nvidia/nemotron-3-ultra`, and `mistralai/mistral-medium-3.5` keep their curated values (none of these appear in models.dev, so platform values stand).
|
|
129
|
-
|
|
130
|
-
## Alternative: separate metadata endpoint
|
|
131
|
-
|
|
132
|
-
If the gateway team prefers not to extend the standard `/v1/models` shape, a separate endpoint is acceptable:
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
GET /v1/models/metadata
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
It should return the same per-model fields and types documented above (`id`, `object`, `created`, `owned_by`, optional `display_name`, `pricing`, `capabilities`, `endpoints`, `limits`, and `variants`). The plugin would fetch this endpoint and merge the additional metadata with the catalog. The parse rules remain identical, only the HTTP envelope changes.
|
|
139
|
-
|
|
140
|
-
## Secondary option (later)
|
|
141
|
-
|
|
142
|
-
Publish route33 limit and variant metadata on models.dev via a community TOML PR. This is useful for non-gateway consumers, but it does not solve the key-scoped freshness problem or the single-round-trip goal. Recommended as a follow-up, not a substitute.
|
|
143
|
-
|
|
144
|
-
## Future direction
|
|
145
|
-
|
|
146
|
-
Broadcasting `reasoning_options` is deferred. The current shipped contract intentionally limits itself to limits, variants, modalities, attachment, pricing, and capabilities.
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Gateway pricing broadcast proposal
|
|
2
|
-
|
|
3
|
-
**To:** R33 gateway team
|
|
4
|
-
**From:** opencode-route33 plugin maintainers
|
|
5
|
-
**Date:** 2026-07-07 (rev 2 — switched to the `input`/`output` per-1M vocabulary)
|
|
6
|
-
**Subject:** Embedding per-model pricing in `GET /v1/models`
|
|
7
|
-
|
|
8
|
-
## Problem
|
|
9
|
-
|
|
10
|
-
The route33.ai gateway exposes `GET /v1/models` for key-scoped catalog discovery, but the response carries no pricing metadata today. Downstream consumers (the opencode-route33 plugin, bench cost aggregation, and user-facing cost estimates) must source prices from an external registry (models.dev) and a hard-coded seed catalog. This creates three gaps:
|
|
11
|
-
|
|
12
|
-
1. **Stale prices** — models.dev is community-maintained and can lag behind gateway rate changes.
|
|
13
|
-
2. **Key-scoped pricing mismatch** — the gateway may offer tiered or negotiated rates per key; a global registry cannot express that.
|
|
14
|
-
3. **New-model lag** — a model that appears in the gateway catalog but not in models.dev reports $0 cost until someone manually adds it to the seed.
|
|
15
|
-
|
|
16
|
-
## Recommendation
|
|
17
|
-
|
|
18
|
-
Embed a `pricing` object inside each entry of the existing `GET /v1/models` response, using the models.dev vocabulary: `input`, `output`, `cache_read`, `cache_write` as **numeric USD per 1M tokens**. Extra JSON fields do not break OpenAI-compatible clients, and key-scoped pricing rides the same key-scoped catalog response (one round trip, atomic catalog-plus-pricing consistency).
|
|
19
|
-
|
|
20
|
-
### Concrete JSON example
|
|
21
|
-
|
|
22
|
-
```json
|
|
23
|
-
{
|
|
24
|
-
"object": "list",
|
|
25
|
-
"data": [
|
|
26
|
-
{
|
|
27
|
-
"id": "openai/gpt-5.5",
|
|
28
|
-
"object": "model",
|
|
29
|
-
"created": 1751234567,
|
|
30
|
-
"owned_by": "openai",
|
|
31
|
-
"pricing": {
|
|
32
|
-
"input": 5.0,
|
|
33
|
-
"output": 30.0,
|
|
34
|
-
"cache_read": 0.5,
|
|
35
|
-
"cache_write": 1.0
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"id": "anthropic/claude-opus-4-8",
|
|
40
|
-
"object": "model",
|
|
41
|
-
"created": 1751234568,
|
|
42
|
-
"owned_by": "anthropic",
|
|
43
|
-
"pricing": {
|
|
44
|
-
"input": 5.0,
|
|
45
|
-
"output": 25.0,
|
|
46
|
-
"cache_read": 0.5,
|
|
47
|
-
"cache_write": 6.25
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
]
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Field semantics** (numeric USD **per 1M tokens**):
|
|
55
|
-
|
|
56
|
-
| Field | Meaning |
|
|
57
|
-
| ------------- | ----------------- |
|
|
58
|
-
| `input` | Input token rate |
|
|
59
|
-
| `output` | Output token rate |
|
|
60
|
-
| `cache_read` | Cache read rate |
|
|
61
|
-
| `cache_write` | Cache write rate |
|
|
62
|
-
|
|
63
|
-
All values are JSON numbers representing the cost of **one million tokens** in USD. `input` and `output` are required for a pricing entry to be consumed; the cache fields are optional.
|
|
64
|
-
|
|
65
|
-
### Why `input`/`output` per-1M numbers
|
|
66
|
-
|
|
67
|
-
- **Terminology match** — `input`/`output` is route33's own token vocabulary, and the modern industry direction (OpenAI's Responses API and Anthropic's Messages API both report `input_tokens`/`output_tokens`).
|
|
68
|
-
- **Consumer match** — this is byte-identical to opencode's native cost schema and the models.dev registry vocabulary, so the opencode-route33 plugin passes values through with **zero unit conversion**.
|
|
69
|
-
- **Human-scale numbers** — `5.0` per 1M reads and reviews better than `"0.000005"` per token, and sidesteps the ecosystem trap of conflating per-token with per-1M values, which has caused real underpricing bugs in other provider plugins.
|
|
70
|
-
|
|
71
|
-
### One vocabulary only (do not mix)
|
|
72
|
-
|
|
73
|
-
The plugin also recognizes the OpenRouter vocabulary (`prompt`, `completion`, `input_cache_read`, `input_cache_write` as string USD **per token**) as an accepted alternative shape. **Pick exactly one vocabulary.** A payload mixing keys from both sets is ambiguous about units and is deliberately ignored by the plugin.
|
|
74
|
-
|
|
75
|
-
### Alternative: byte-pure OpenAI surface
|
|
76
|
-
|
|
77
|
-
If the gateway team prefers not to extend the standard `/v1/models` shape, a separate endpoint is acceptable:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
GET /v1/models/pricing
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
With the **same vocabulary** (`input`, `output`, `cache_read`, `cache_write` as numeric USD-per-1M fields) and the same key-scoped semantics. The plugin would fetch this endpoint alongside the catalog and merge the pricing layer.
|
|
84
|
-
|
|
85
|
-
## Zero plugin changes needed
|
|
86
|
-
|
|
87
|
-
The opencode-route33 plugin already ships a **dual-shape pricing extractor** (decision D14) that is dormant today and will activate automatically the moment recognizable pricing fields appear:
|
|
88
|
-
|
|
89
|
-
- **models.dev vocabulary** (numeric USD per 1M) → passed through unchanged. **(recommended)**
|
|
90
|
-
- **OpenRouter vocabulary** (string USD per token) → converted `×1,000,000` to opencode's per-1M numbers.
|
|
91
|
-
|
|
92
|
-
Adopting either the embedded or the separate-endpoint contract above requires **zero changes** to the plugin — the dormant path becomes active without a version bump.
|
|
93
|
-
|
|
94
|
-
## Secondary option (later)
|
|
95
|
-
|
|
96
|
-
Register route33 in models.dev via a community TOML PR. This is useful for non-gateway consumers, but it does not solve the key-scoped-pricing or stale-data problems. Recommended as a follow-up, not a substitute.
|