Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ subscription and makes its requests. The packages work in OpenCode and in
| [minimax](packages/minimax) | MiniMax Code (China): account credits and M Plan, with MiniMax Code's device sign-in | `minimax-code` |
| [minimax](packages/minimax) | MiniMax Code (international): account credits and M Plan, with MiniMax Code's device sign-in | `minimax-code-global` |
| [mimo](packages/mimo) | Xiaomi MiMo, with a Xiaomi account | `mimo-app` |
| [mistral-vibe](packages/mistral-vibe) | Mistral Vibe (Vibe Code, unofficial): the CLI's model catalog plus DeepSeek, each model on both wallets — the plan's Vibe budget, and the API budget as `<id>--api` — with both budgets as quota windows | `mistral-vibe` |
| [nous](packages/nous) | Nous Portal models, with Nous Portal's device sign-in | `nous-portal` |
| [opendesign](packages/opendesign) | Open Design Cloud (open-design.ai), with the Open Design CLI's device sign-in | `opendesign` |
| [qoder](packages/qoder) | Qoder subscription (qoder.com), with Qoder's device sign-in | `qoder` |
Expand Down
21 changes: 21 additions & 0 deletions packages/mistral-vibe/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 magpie-community contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
175 changes: 175 additions & 0 deletions packages/mistral-vibe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Mistral Vibe

[简体中文](README.zh-CN.md) | English

Mistral Vibe's coding plan in [magpie](https://usemagpie.ai) and
[OpenCode](https://opencode.ai). **Unofficial:** not affiliated with,
endorsed by, or supported by Mistral AI.

One provider, one model group, two wallets. The Vibe key signs in and the
model list is the Vibe plan's own catalog plus DeepSeek; every model is
offered on the Vibe budget and, if a Studio key is given too, on the API
budget as `<id>--api`. The plan's monthly Vibe Code and API budgets are read
into magpie's usage card, `magpie quota`, the quota alert and
`GET /v1/magpie/quotas`.

**Provider id:** `mistral-vibe`

| | |
|---|---|
| API | `https://api.mistral.ai/v1` (`@ai-sdk/openai-compatible`) |
| Sign-in | one credential holding both keys: `vibe=…;api=…` (the Vibe key alone works) |
| Models | the Vibe Code catalog (4 models on 2026-11-08) plus DeepSeek |
| Quota | `GET /v1/billing/budget` → `vibe_budget`, `api_budget`, `reset_at` |

## Sign-in

```sh
magpie plugin login mistral-vibe
```

Paste one line:

```
vibe=<Vibe key>;api=<Studio key>
```

- **Vibe key** — the key the official CLI writes to `~/.vibe/.env` after
`vibe --setup`, or chat.mistral.ai/code/extensions → **Vibe CLI** card →
**Advanced** → **Vibe API Key**. Its requests spend the plan's Vibe budget.
- **Studio key** (optional) — console → API › API keys. It adds the same
models on the API budget.

The Vibe key alone is enough for the Vibe wallet. Neither key expires. JSON
(`{"vibe":"…","api":"…"}`) and two bare keys separated by `;` are accepted
too.

The line holds both keys: treat it like two secrets, and don't paste it into
issues, screenshots or logs.

## Models

On 2026-11-08 the Vibe Code catalog held four models:

| id | label | context | effort levels | vision |
|---|---|---|---|---|
| `mistral-large-4-0` | Mistral Large 4 | 1M | low / medium / high | yes |
| `mistral-medium-latest` | Mistral Medium 3.5 | 262k | none / high | yes |
| `zai-glm-5-3` | GLM 5.3 (Mistral Hosted) | 1M | low / high / max | no |
| `zai-glm-5-3-flash` | GLM 5.3 Flash (Mistral Hosted) | 1M | low / high / max | yes |

DeepSeek is added because the Vibe key serves it (measured), though the CLI's
picker does not list it. With both keys every model is offered twice; the
alias picks the wallet:

| Model id | Name | Spends |
|---|---|---|
| `deepseek-v4-1-flash-1017` | `deepseek-v4-1-flash-1017 (Vibe budget)` | the plan's Vibe budget first, then PAYG |
| `deepseek-v4-1-flash-1017--api` | `deepseek-v4-1-flash-1017 (API budget)` | the API budget / PAYG |

The `--api` suffix is stripped before the request goes upstream; the fetch
picks the key from it. With one key only, only that wallet's ids are listed.

Measured on 2026-11-08 on an Education-plan account (150 USD Vibe Code
budget, 15 USD API budget), same model through magpie's gateway:

| Alias | Request | `vibe_budget` | Charged to the Vibe budget |
|---|---|---|---|
| `…--api` | 248 tokens, 200 | 0.000784 % → 0.000784 % | **$0.000000** |
| plain | 266 tokens, 200 | 0.000784 % → 0.000986 % | **$0.000303** |

If the catalog can't be read, the account's `/v1/models` is used instead,
deduped and filtered: chats only (`capabilities.completion_chat`) and one id
per family (64 entries → 14 for the account above). Families come from
`billing_model_name` and the `aliases` links; the id kept is, in order, the
one billing names, the one whose display name is the id, else `-latest`. A
request naming an aliased id from an older config still works.

### Show the models in magpie

magpie shows only the models ticked for a provider, and a plugin's new ids
start unticked. Tick them once — the app's provider page, or:

```sh
magpie provider models mistral-vibe \
+mistral-large-4-0 +mistral-large-4-0--api \
+mistral-medium-latest +mistral-medium-latest--api \
+zai-glm-5-3 +zai-glm-5-3--api \
+zai-glm-5-3-flash +zai-glm-5-3-flash--api \
+deepseek-v4-1-flash-1017 +deepseek-v4-1-flash-1017--api
```

## Quota

`auth.usage` reads the three public endpoints the official CLI reads:
`/v1/billing/budget` (both budgets, their reset), `/v1/billing/subscription`
(plan name) and `console.mistral.ai/api/vibe/whoami` (the key's scope). Both
windows are shown; the key's own budget comes first. A refused key (401)
marks the account expired; a 403 on the budget or a plan without one says so
instead of showing an empty card.

```sh
magpie quota mistral-vibe
```

## Request and reply fixes

Written from the behaviour measured against Mistral's API — the fields it
answers with 422, GLM's 4096-token cap without `max_tokens`, and its typed
content parts, in `src/request.mjs`, `src/reply.mjs`, `src/effort.mjs` and
`src/transport.mjs`. They are not a translation of another implementation. The
alias table in `src/constants.mjs` is plain facts about Mistral's ids (the same
ids mistral-gateway lists).

- aliases are rewritten to the id Mistral serves;
- `max_completion_tokens` → `max_tokens`, `seed` → `random_seed`, `user`
dropped (Mistral answers those with 422);
- `max_tokens` is filled in for GLM only (131072): without it Mistral caps a
GLM completion at 4096 tokens, which its thinking alone can spend;
- `reasoning_content` and `index` are stripped from messages a client sends
back as they came;
- a GLM tool-result turn without an effort gets `reasoning_effort: "high"`,
which avoids GLM ending such a turn with no visible text;
- `stream_options: {include_usage: true}` is added to a stream that names none;
- a rejected `reasoning_effort` is retried once at the nearest level the model
lists (nested `reasoning.effort` on `/v1/responses`);
- a 429 is returned as it came: magpie rests the account and falls back on it,
and `Retry-After` says when to try again;
- GLM's typed content parts (`[{type:"thinking"…},{type:"text"…}]`) become
`content` (a string) and `reasoning_content`, streamed or buffered, and a
stream that delta'd tool calls but ends `stop` ends `tool_calls`;
- a rebuilt reply drops the upstream's `content-encoding` and `content-length`,
which no longer describe its bytes.

One account holds both wallets, so a refusal that rests the account rests the
`--api` ids with it.

## Privacy

The keys stay in magpie's own store (`plugin-auth.json`, or OpenCode's
`auth.json`). The plugin sends no telemetry and reads nothing else; its only
network calls are the three quota reads above and the requests magpie makes
for a model.

## Disclaimer

This is an unofficial community project, not affiliated with, endorsed by or
supported by Mistral AI. It uses the credentials and endpoints the official
Mistral Vibe CLI uses; Mistral's terms still apply, and the plan's limits stay
in force. Mistral's consumer terms forbid sharing an account or its keys, and
creating accounts to get around limits — keep this to your own account. Terms
and endpoints can change at any time; Mistral decides how it enforces its own
terms. The software is provided "as is", without warranty of any kind, and the
authors accept no liability for any loss, including account suspension,
restricted keys or lost subscription fees. Check the current terms before
relying on it.

## License

MIT. See [LICENSE](LICENSE).

## Test

```sh
bun test # local stand-in for Mistral's endpoints; no network, no key
```
158 changes: 158 additions & 0 deletions packages/mistral-vibe/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Mistral Vibe

简体中文 | [English](README.md)

把 **Mistral Vibe** 的编程套餐接入 [magpie](https://usemagpie.ai) 与
[OpenCode](https://opencode.ai) 的供应商插件。**非官方**:与 Mistral AI 无隶属、
无背书、无支持关系。

一个供应商、一个模型组、两个钱包。Vibe key 登录后,模型来自 Vibe 套餐自己的
目录并追加 DeepSeek;每个模型都出现在 Vibe 钱包里,若同时提供 Studio key,还会
以 `<id>--api` 的形式出现在 API 钱包里。套餐每月的 Vibe Code 与 API 额度会显示
在 magpie 的用量卡片、`magpie quota`、额度提醒和 `GET /v1/magpie/quotas` 中。

**供应商 id:** `mistral-vibe`

| | |
|---|---|
| API | `https://api.mistral.ai/v1`(`@ai-sdk/openai-compatible`) |
| 登录 | 一条凭据装两把 key:`vibe=…;api=…`(只填 Vibe key 也可以) |
| 模型 | Vibe Code 目录(2026-11-08 为 4 个)加上 DeepSeek |
| 额度 | `GET /v1/billing/budget` → `vibe_budget`、`api_budget`、`reset_at` |

## 登录

```sh
magpie plugin login mistral-vibe
```

粘贴一行:

```
vibe=<Vibe key>;api=<Studio key>
```

- **Vibe key**:官方 CLI 执行 `vibe --setup` 后写入 `~/.vibe/.env` 的那把,
或 chat.mistral.ai/code/extensions → **Vibe CLI** 卡片 → **Advanced** →
**Vibe API Key**。它的请求先花套餐的 Vibe 额度。
- **Studio key**(可选):console 的 **API › API keys**。它让同一批模型也出现在
API 额度上。

只填 Vibe key 就能用 Vibe 钱包。两把 key 都不过期。也接受 JSON
(`{"vibe":"…","api":"…"}`)或两把裸 key 以 `;` 分隔。

这一行同时包含两把 key,等同于两个密码:不要贴到 issue、截图或日志里。

## 模型

2026-11-08 的 Vibe Code 目录有 4 个模型:

| id | 名称 | 上下文 | 思考档位 | 视觉 |
|---|---|---|---|---|
| `mistral-large-4-0` | Mistral Large 4 | 1M | low / medium / high | 是 |
| `mistral-medium-latest` | Mistral Medium 3.5 | 262k | none / high | 是 |
| `zai-glm-5-3` | GLM 5.3 (Mistral Hosted) | 1M | low / high / max | 否 |
| `zai-glm-5-3-flash` | GLM 5.3 Flash (Mistral Hosted) | 1M | low / high / max | 是 |

额外加入 DeepSeek:CLI 选择器里没有它,但实测 Vibe key 可以调用。两把 key 都在
时,每个模型出现两次,靠别名区分钱包:

| 模型 id | 显示名 | 花哪个 |
|---|---|---|
| `deepseek-v4-1-flash-1017` | `deepseek-v4-1-flash-1017 (Vibe budget)` | 先花套餐的 Vibe 额度,再按量付费 |
| `deepseek-v4-1-flash-1017--api` | `deepseek-v4-1-flash-1017 (API budget)` | API 额度 / 按量付费 |

`--api` 后缀在请求发出前去掉,fetch 用它挑 key。只有一把 key 时,只列出该钱包的 id。

2026-11-08 在 Education 套餐账号上实测(Vibe Code 额度 150 USD、API 额度
15 USD),同一个模型经 magpie 网关:

| 别名 | 请求 | `vibe_budget` | 扣在 Vibe 额度上 |
|---|---|---|---|
| `…--api` | 248 tokens,200 | 0.000784 % → 0.000784 % | **$0.000000** |
| 裸 id | 266 tokens,200 | 0.000784 % → 0.000986 % | **$0.000303** |

目录读不到时,退回账号的 `/v1/models` 并去重:只留对话模型
(`capabilities.completion_chat`),同一底层模型只留一个 id(上面的账号是
64 条 → 14 个)。归并依据 `billing_model_name` 与 `aliases` 互链;保留的 id
依次优先:billing 名、显示名与 id 相同的那个、`-latest`。老配置里用别名的请求
仍然可用。

### 在 magpie 里显示模型

magpie 只显示已勾选的模型,插件新增的 id 默认未勾选。勾一次即可——在应用里的
供应商页面,或:

```sh
magpie provider models mistral-vibe \
+mistral-large-4-0 +mistral-large-4-0--api \
+mistral-medium-latest +mistral-medium-latest--api \
+zai-glm-5-3 +zai-glm-5-3--api \
+zai-glm-5-3-flash +zai-glm-5-3-flash--api \
+deepseek-v4-1-flash-1017 +deepseek-v4-1-flash-1017--api
```

## 额度

`auth.usage` 读取官方 CLI 用的三个公开接口:`/v1/billing/budget`(两个额度和
重置时间)、`/v1/billing/subscription`(套餐名)、
`console.mistral.ai/api/vibe/whoami`(key 的作用域)。两个窗口都会显示,key
自己的那个排在前面。key 被拒(401)会标记账号过期;额度接口 403 或套餐没有该
额度时会说明原因,而不是显示空卡片。

```sh
magpie quota mistral-vibe
```

## 请求与回复修正

按对 Mistral 接口的实测行为重写(它对哪些字段返回 422、GLM 不传
`max_tokens` 时 4096 的输出上限、以及类型化 content),代码在
`src/request.mjs`、`src/reply.mjs`、`src/effort.mjs`、`src/transport.mjs`,
不是对其它实现的翻译。`src/constants.mjs` 的别名表是 Mistral id 的客观事实
(mistral-gateway 也列出同一批 id)。

- 别名改写为 Mistral 实际提供的 id;
- `max_completion_tokens` → `max_tokens`、`seed` → `random_seed`、丢弃 `user`
(Mistral 对这些返回 422);
- 只给 GLM 补 `max_tokens`(131072):不补时 Mistral 把 GLM 输出限制在
4096,思考就可能耗尽;
- 客户端原样回传的消息里去掉 `reasoning_content` 和 `index`;
- GLM 的 tool 结果轮次若未指定档位,补 `reasoning_effort: "high"`,避免它
无可见输出就结束;
- 流式请求缺少 `stream_options: {include_usage: true}` 时补上;
- 被拒的 `reasoning_effort` 会按模型支持的最接近档位重试一次(`/v1/responses`
下是嵌套的 `reasoning.effort`);
- 429 原样返回:由 magpie 停用账号并切换下一个,`Retry-After` 说明何时重试;
- GLM 的类型化 content(`[{type:"thinking"…},{type:"text"…}]`)在流式与非流式
下都换算为字符串 `content` 和 `reasoning_content`;已产生 tool_calls 却以
`stop` 结束的流改为 `tool_calls`;
- 重建的回复会去掉上游的 `content-encoding` 与 `content-length`,它们已不再
描述新的字节。

一个账号同时装两个钱包,所以一次拒绝对账号的停用也会连带 `--api` 那些 id。

## 隐私

key 只保存在 magpie 自己的存储(`plugin-auth.json`,或 OpenCode 的
`auth.json`)里。插件不上报遥测、不读取其他文件;网络请求只有上面三个额度
接口,以及 magpie 为模型发出的请求。

## 免责声明

这是非官方社区项目,与 Mistral AI 无隶属、无背书、无支持关系。它使用官方
Mistral Vibe CLI 相同的凭据与接口;Mistral 的条款仍然适用,套餐额度限制照常
生效。Mistral 的消费者条款禁止共享账号或 key、禁止通过多账号绕过限制——请只在
自己的账号上使用。条款与接口可能随时变化,如何执行由 Mistral 决定。本软件按
"现状"提供,不附带任何担保;作者不对任何损失负责,包括账号被限制、key 被停用
或订阅费用损失。依赖前请自行核对最新条款。

## 许可证

MIT,见 [LICENSE](LICENSE)。

## 测试

```sh
bun test # 本地模拟 Mistral 接口;不联网、不需要 key
```
Loading