@bivelio/savings-layer 0.4.24 → 0.4.26
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 +105 -21
- package/README.md +601 -28
- package/dist/adapters/ai-sdk.d.ts +46 -0
- package/dist/adapters/ai-sdk.js +84 -0
- package/dist/adapters/anthropic-sdk.d.ts +35 -0
- package/dist/adapters/anthropic-sdk.js +100 -0
- package/dist/adapters/langchain.d.ts +29 -0
- package/dist/adapters/langchain.js +58 -0
- package/dist/adapters/mastra.d.ts +41 -0
- package/dist/adapters/mastra.js +74 -0
- package/dist/gateway/bin.js +963 -630
- package/dist/index.d.ts +2912 -1516
- package/dist/index.js +1368 -865
- package/docs/terminales/README.md +173 -17
- package/docs/terminales/aider.md +74 -0
- package/docs/terminales/claude-code.md +7 -2
- package/docs/terminales/continue.md +47 -0
- package/docs/terminales/copilot.md +114 -0
- package/docs/terminales/kilo.md +54 -31
- package/docs/terminales/no-soportados.md +41 -0
- package/docs/terminales/opencode.md +33 -11
- package/package.json +89 -5
|
@@ -8,15 +8,19 @@ terminal). Cada afirmación va marcada **[V]** (verificada en fuente) o **[I]**
|
|
|
8
8
|
## Qué es esto
|
|
9
9
|
|
|
10
10
|
`bvsala gateway` es un proxy local medidor: escucha en `127.0.0.1`, reenvía
|
|
11
|
-
cada petición
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
cada petición al proveedor (`https://api.anthropic.com` por defecto) —**byte a
|
|
12
|
+
byte**, salvo las palancas que se explican abajo (con licencia PRO, la de tarifa
|
|
13
|
+
va encendida por defecto)— y, una vez servida la respuesta, lee el `usage` del
|
|
14
|
+
stream y lo convierte en coste. Ni tus prompts, ni las respuestas, ni la clave de
|
|
15
|
+
tu proveedor salen de tu máquina hacia BiVelio: solo viaja el uso de cada
|
|
16
|
+
petición —cuentas de tokens, coste, el id del modelo, un id de petición y los ids
|
|
17
|
+
opacos de asiento y de sesión—, y la lista exacta de campos está en la
|
|
18
|
+
LICENSE §5. Es fail-closed como el SDK: arranca solo con tu clave de servicio
|
|
19
|
+
(`BIVELIO_SERVICE_KEY`) y una licencia BiVelio activa, que recoge con esa clave y
|
|
20
|
+
cuya firma verifica en tu máquina. Una vez arrancado, jamás corta una petición en
|
|
21
|
+
curso: si la licencia caduca o se revoca, solo las peticiones NUEVAS reciben un
|
|
22
|
+
HTTP 402 hasta renovarla. La medición es best-effort: con la ingesta caída,
|
|
23
|
+
reenvía y avisa.
|
|
20
24
|
|
|
21
25
|
Mide cada petición. Con licencia PRO aplica por defecto **una sola palanca**:
|
|
22
26
|
rebaja el TTL de escritura de caché mientras la sesión sigue caliente — cambia la
|
|
@@ -38,11 +42,17 @@ igual.
|
|
|
38
42
|
| [Codex CLI](codex.md) | `http://127.0.0.1:8402/v1` (API key) · `…/backend-api/codex` (ChatGPT) | **con** | `codex -c openai_base_url=…` | `bvsala codex` ✅ | [V] validado en mano el 30-08 (426 → fallback HTTP, stream íntegro) |
|
|
39
43
|
| [Goose](goose.md) | `http://127.0.0.1:8402` | **sin** | env `ANTHROPIC_HOST` | `bvsala goose` ✅ | [V] |
|
|
40
44
|
| [Qwen Code](qwen-code.md) | `http://127.0.0.1:8402` | **sin** | env `ANTHROPIC_BASE_URL` + `~/.qwen/settings.json` | `bvsala qwen` ✅ | [V] |
|
|
41
|
-
| [opencode](opencode.md) | `http://127.0.0.1:8402/v1` | **con** | `~/.config/opencode/opencode.json` |
|
|
45
|
+
| [opencode](opencode.md) | `http://127.0.0.1:8402/v1` | **con** | env `OPENCODE_CONFIG_CONTENT` o `~/.config/opencode/opencode.json` | `bvsala opencode` ✅ (sin escribir en disco) | [V] en código (v1.18.32) |
|
|
46
|
+
| [Kilo Code](kilo.md) (CLI y extensiones) | `http://127.0.0.1:8402/v1` | **con** | env `KILO_CONFIG_CONTENT` o `~/.config/kilo/kilo.json` | `bvsala kilo` ✅ (CLI) | [V] en código (v7.8.1, fork de opencode) |
|
|
47
|
+
| [Copilot CLI](copilot.md) (solo BYOK) | anthropic: `http://127.0.0.1:8402` · openai: `…/v1` | anthropic **sin**, openai **con** | env `COPILOT_PROVIDER_BASE_URL` | `bvsala copilot` ✅ (tipo anthropic) | [V] en la doc oficial; sin validar en mano. Tipo openai: a mano, sin validar (WebSocket → 426) |
|
|
48
|
+
| [Copilot en VS Code](copilot.md#copilot-en-vs-code-byok-custom-endpoint) (solo BYOK) | `http://127.0.0.1:8402/v1/messages` (ruta completa) | ruta completa | UI → Custom Endpoint (`chatLanguageModels.json`) | — | [V] en la doc oficial; sin validar en mano |
|
|
49
|
+
| [Aider](aider.md) | Anthropic: `http://127.0.0.1:8402` · OpenAI: `…/v1` | Anthropic **sin**, OpenAI **con** | env `ANTHROPIC_API_BASE` / `OPENAI_API_BASE` (litellm) | `bvsala aider` ✅ | [V] en código (litellm 1.82.3); OpenAI en stream solo con `BVSALA_GATEWAY_USAGE_INJECT=1` |
|
|
50
|
+
| [Continue](continue.md) (CLI `cn` y extensiones) | `http://127.0.0.1:8402/v1` | **con** | `~/.continue/config.yaml` (`apiBase`) | — (config de usuario) | [V] en código |
|
|
42
51
|
| [Crush](crush.md) | `http://127.0.0.1:8402/v1` | **con**, sin barra final | `~/.config/crush/crushrc` | — (config de usuario) | [V] |
|
|
43
52
|
| [Droid](droid.md) | `http://127.0.0.1:8402` | sin **[I]** | `~/.factory/settings.json` | — (config de usuario) | validar en mano |
|
|
44
53
|
| [Cline](cline.md) | `http://127.0.0.1:8402/v1` | **con** | UI | — | [V] |
|
|
45
|
-
| [
|
|
54
|
+
| [Gemini CLI](no-soportados.md#gemini-cli--no-se-mide-todavía) | — | — | env `GOOGLE_GEMINI_BASE_URL` | — | **no se mide**: el gateway no lee el dialecto de Gemini |
|
|
55
|
+
| [Cursor](no-soportados.md#cursor--no-se-puede) | — | — | sus servidores, no tu máquina | — | **no se puede**: Cursor no alcanza `127.0.0.1` |
|
|
46
56
|
| [Python y cualquier SDK](../../README.md#python-and-any-other-language-the-local-gateway) (OpenAI · Anthropic) | OpenAI: `http://127.0.0.1:8403/v1` · Anthropic: `http://127.0.0.1:8402` | OpenAI **con**, Anthropic **sin** | `base_url` del SDK | `bvsala gateway --upstream openai` | [V] en test (upstream falso) |
|
|
47
57
|
|
|
48
58
|
Reglas de la columna «Base URL»: **nunca barra final**, **nunca redirecciones**
|
|
@@ -50,12 +60,28 @@ Reglas de la columna «Base URL»: **nunca barra final**, **nunca redirecciones*
|
|
|
50
60
|
en vez de seguirlo). Y nunca copies el URL de un terminal a otro: cada SDK añade
|
|
51
61
|
su propio tramo de ruta y el error es silencioso (§ «Comprobar que mide»).
|
|
52
62
|
|
|
53
|
-
Claude Code, Codex, Goose
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
Claude Code, Codex, Goose, Qwen Code, opencode, Kilo, Copilot CLI (BYOK) y Aider
|
|
64
|
+
tienen **envoltorio propio** (`bvsala
|
|
65
|
+
claude|codex|goose|qwen|opencode|kilo|copilot|aider`): arrancan un gateway en
|
|
66
|
+
puerto efímero, lanzan el terminal apuntándole y lo apagan al salir. Cero
|
|
67
|
+
configuración persistente: opencode y Kilo reciben la suya por variable
|
|
68
|
+
(`OPENCODE_CONFIG_CONTENT`, `KILO_CONFIG_CONTENT`), fusionada con la tuya. La
|
|
56
69
|
receta manual de cada guía hace exactamente lo mismo. Para el resto,
|
|
57
70
|
`bvsala doctor` imprime el bloque exacto de cada terminal instalado.
|
|
58
71
|
|
|
72
|
+
**Al salir, cada envoltorio dice lo que midió.** Dentro de un envoltorio el log
|
|
73
|
+
por petición va callado para no pisar el TUI, así que al terminar imprime por
|
|
74
|
+
stderr una línea como esta:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
[bvsala copilot] metering in this run: 41 request(s) metered with the provider's usage · 3 forwarded but NOT metered (nothing is estimated in their place): 3 × the request did not ask for usage (stream_options.include_usage). What each reason means and what to do: docs/terminales/README.md.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Los motivos son los de la tabla `· not metered: …` de abajo. Si ninguna petición
|
|
81
|
+
pasó por el gateway, lo dice también: el terminal no estaba apuntado. `bvsala
|
|
82
|
+
gateway` imprime la misma línea al pararlo con Ctrl-C. Es local, como el aviso de
|
|
83
|
+
tráfico degradado: no viaja a BiVelio.
|
|
84
|
+
|
|
59
85
|
## Lo común a todas las guías
|
|
60
86
|
|
|
61
87
|
### 1 · Instalar y arrancar el gateway
|
|
@@ -188,12 +214,15 @@ Y una condición dura: el terminal debe estar instalado con su **instalador
|
|
|
188
214
|
nativo** (un `claude.exe` / `codex.exe` en el PATH — Claude Code, Codex, Goose
|
|
189
215
|
y Qwen Code lo tienen [V]). El shim `.cmd` que deja `npm i -g <terminal>` no
|
|
190
216
|
puede lanzarse de forma segura con argumentos (CVE-2024-27980) y `bvsala` se
|
|
191
|
-
niega con una guía en vez de fallar con un ENOENT mudo.
|
|
217
|
+
niega con una guía en vez de fallar con un ENOENT mudo. opencode, Kilo y Copilot
|
|
218
|
+
CLI también se instalan por npm: en Windows, usa su binario nativo (releases de
|
|
219
|
+
GitHub, winget o scoop) **[I: no validado en Windows]**. Aider se instala con pip,
|
|
220
|
+
que deja un `aider.exe`.
|
|
192
221
|
|
|
193
222
|
### 4 · Regla BYOK, sin excepción
|
|
194
223
|
|
|
195
|
-
Todas las recetas del anillo 2 (Goose, Qwen Code, opencode,
|
|
196
|
-
|
|
224
|
+
Todas las recetas del anillo 2 (Goose, Qwen Code, opencode, Kilo, Copilot, Aider,
|
|
225
|
+
Crush, Droid, Cline, Continue) son **API key exclusivamente**. Anthropic prohíbe usar el OAuth de Claude
|
|
197
226
|
Pro/Max en harnesses de terceros (opencode lo documenta; Crush retiró su OAuth en
|
|
198
227
|
ene-2026). El gateway reenviaría un Bearer de suscripción sin inmutarse — y eso
|
|
199
228
|
no se promociona ni se documenta como receta.
|
|
@@ -205,3 +234,130 @@ no se promociona ni se documenta como receta.
|
|
|
205
234
|
di eso, nunca «aprobado por Anthropic». El contrato del gateway es una lista
|
|
206
235
|
abierta de cabeceras y campos que crece con cada release del terminal; el
|
|
207
236
|
passthrough byte a byte es lo que lo mantiene vivo sin tocar nada.
|
|
237
|
+
|
|
238
|
+
## What the gateway guarantees: it forwards what your client sends
|
|
239
|
+
|
|
240
|
+
A proxy in front of your provider can raise your bill without breaking anything
|
|
241
|
+
you can see: a lost cache marker, a dropped beta header, a block it does not
|
|
242
|
+
recognise. This gateway is built not to do that, and a test suite checks it
|
|
243
|
+
against a fake upstream on 127.0.0.1: `test/gateway-no-empeora.test.ts`, which
|
|
244
|
+
runs in our CI on every pull request and every push to `main`. The source
|
|
245
|
+
repository is not public, so this section lists exactly what the suite checks.
|
|
246
|
+
|
|
247
|
+
**With no lever armed, your provider receives what your client sent, byte for
|
|
248
|
+
byte:**
|
|
249
|
+
|
|
250
|
+
- **The request body**, including `tool_reference` blocks (from the provider's
|
|
251
|
+
tool search and from a client-side search tool such as Claude Code's), tools
|
|
252
|
+
with `defer_loading`, `cache_control` in every place the API reads it (top
|
|
253
|
+
level, `system`, `tools`, and text, image, document, `tool_use` and
|
|
254
|
+
`tool_result` blocks, including blocks nested inside a `tool_result` or inside
|
|
255
|
+
a document's `source.content`), each with its `ttl: "1h"`, the advisor tool
|
|
256
|
+
with its `advisor_tool_result` blocks, thinking signatures, and fields the
|
|
257
|
+
gateway does not know. Not a JSON equivalent: the same bytes.
|
|
258
|
+
- **The path and query string** (`/v1/messages?beta=true`).
|
|
259
|
+
- **Every request header**, including every `anthropic-beta` value (the 1-hour
|
|
260
|
+
cache TTL, the advisor, context management, OAuth, and betas that do not exist
|
|
261
|
+
yet). Three kinds stay on the hop from your client to the gateway, as HTTP
|
|
262
|
+
requires: hop-by-hop headers (RFC 7230 §6.1, plus `expect` and any header named
|
|
263
|
+
in `Connection`), `host` and `content-length`. One more stays with the gateway
|
|
264
|
+
because it is addressed to it: `x-bvsala-report`, with which a client asks for
|
|
265
|
+
its per-request report (below).
|
|
266
|
+
- **The response**: the same bytes and headers, except the transport ones
|
|
267
|
+
(`content-encoding`, `content-length`, `transfer-encoding`), because the
|
|
268
|
+
gateway receives the body already decompressed. A request sent with
|
|
269
|
+
`x-bvsala-report: 1` also gets one header added, `x-bvsala-request-id`; a
|
|
270
|
+
request without it gets none.
|
|
271
|
+
|
|
272
|
+
**Per-request reports, in any language.** Send `x-bvsala-report: 1` with a
|
|
273
|
+
request and the gateway keeps the report it recorded for your dashboard for
|
|
274
|
+
that request, and answers with `x-bvsala-request-id`. Read it back from the
|
|
275
|
+
same gateway with `GET /_bvsala/v1/reports/<x-bvsala-request-id>` or
|
|
276
|
+
`GET /_bvsala/v1/reports?response_id=<the id of the provider's response>`;
|
|
277
|
+
add `wait_ms=<milliseconds>` (30,000 at most) to wait for a request still in
|
|
278
|
+
flight. The answer carries `status` (`metered`, `not_metered` with the same
|
|
279
|
+
`reason` as the log line, or `pending`) and, when metered, the `SavingsReport`
|
|
280
|
+
the gateway queued for your dashboard: nothing is computed for this answer.
|
|
281
|
+
`GET /_bvsala/v1/status` returns the gateway's version, upstream origin and
|
|
282
|
+
license state. These routes are answered by the gateway and never forwarded;
|
|
283
|
+
the gateway listens on 127.0.0.1 only, they send no CORS headers, they answer
|
|
284
|
+
403 to a `Host` other than 127.0.0.1 or localhost (so a web page cannot reach
|
|
285
|
+
them by rebinding its own name to 127.0.0.1), no route lists reports (you need
|
|
286
|
+
the id), and like every other route they answer 402 when the license does not
|
|
287
|
+
serve. The gateway
|
|
288
|
+
keeps the last 1,000 reports for one hour at most, in memory; nothing is
|
|
289
|
+
written to disk and nothing more is sent to BiVelio.
|
|
290
|
+
|
|
291
|
+
"No lever armed" means any of: a license without that lever's feature,
|
|
292
|
+
`BVSALA_GATEWAY_ELISION=0`, or a lever you have not turned on (the sibling
|
|
293
|
+
model, per-turn effort, the context-editing dials and usage injection are off by
|
|
294
|
+
default). The suite checks each of these with the request exactly as Claude
|
|
295
|
+
Code sends it (compact JSON, which every armed lever would rewrite) and with a
|
|
296
|
+
hand-formatted one, and next to each it runs the same setup with the lever armed
|
|
297
|
+
and checks that the request does change, so a lever that stopped switching off
|
|
298
|
+
would fail it.
|
|
299
|
+
|
|
300
|
+
**With a lever armed, the only change is the one it declares:**
|
|
301
|
+
|
|
302
|
+
| Lever | Applies to | What changes | What does not |
|
|
303
|
+
|---|---|---|---|
|
|
304
|
+
| Cache TTL (`cache_ttl_tuning`, on by default with PRO) | `/v1/messages` requests where a large part of the prompt is new (session start, compaction); a chained turn travels untouched | every `cache_control` with `ttl: "1h"` becomes `"5m"`, the top-level one included (a 1-hour top-level marker behind 5-minute block markers would be a 400) | a key named `cache_control` inside a tool call's `input` or a tool's `input_schema` is content and stays as it is; so does the advisor's `caching`; headers are untouched |
|
|
305
|
+
| Per-turn effort (`BVSALA_GATEWAY_ESFUERZO=low` or `medium`) | `/v1/messages` for `claude-fable-5-1`, `claude-mythos-5-1`, `claude-opus-5-5` and `claude-opus-5`, when the level is below the model's default effort (`high`; `medium` on `claude-opus-5-5`) and the request carries no `output_config` of its own (top level or in a message); a level at or above the default leaves the request untouched | one message appended at the end of `messages`, `{"role":"system","content":[],"output_config":{"effort":…}}`, and `mid-conversation-output-config-2026-07-01` appended after your `anthropic-beta` value | your `anthropic-beta` value is kept verbatim in front; nothing earlier in `messages` moves |
|
|
306
|
+
| Sibling model (`BVSALA_GATEWAY_MODELO_HERMANO=1`) | `/v1/messages` and `/v1/messages/count_tokens` for `claude-fable-5`, except with a forced `tool_choice` or the 1M-context beta | `model` becomes `claude-fable-5-1` | headers are untouched |
|
|
307
|
+
| Context-editing dials (`BVSALA_GATEWAY_DIALES_ELISION=1`; measured as a net loss, off) | `/v1/messages` | your `clear_tool_uses_20250919` edit in `context_management` is replaced by ours | your other edits are kept, `clear_thinking_20251015` first; your `anthropic-beta` value is kept verbatim, with `context-management-2025-06-27` appended if it was not there |
|
|
308
|
+
| Usage in Chat Completions streams (`BVSALA_GATEWAY_USAGE_INJECT=1`, off) | streaming `…/chat/completions` requests without `stream_options` of their own | `"stream_options":{"include_usage":true},` inserted as text right after the opening `{` | the rest of the body, byte for byte (nothing is re-serialized); headers are untouched; a 400 or 422 gets your original request once more |
|
|
309
|
+
|
|
310
|
+
A lever that changes the body parses it and writes it back: your provider reads
|
|
311
|
+
the same JSON values, although whitespace and the way strings are escaped may
|
|
312
|
+
differ. When writing it back would change anything else (a number JavaScript
|
|
313
|
+
prints differently, such as `1.0`, `1e5`, `-0` or an integer beyond 2^53; an
|
|
314
|
+
object key that looks like an array index, which JavaScript moves to the front;
|
|
315
|
+
a key repeated in the same object; invalid UTF-8; a compressed body), no lever
|
|
316
|
+
is applied and the request travels byte for byte. If the provider answers 400 to
|
|
317
|
+
a request a lever changed, the gateway sends your original request once more,
|
|
318
|
+
unchanged, and meters that one.
|
|
319
|
+
|
|
320
|
+
**Degraded traffic.** The gateway also watches, with the provider's own usage
|
|
321
|
+
counters, for requests that come out worse than your client asked for:
|
|
322
|
+
|
|
323
|
+
| Log line: `[gateway] degraded traffic (session …) · …` | What it means |
|
|
324
|
+
|---|---|
|
|
325
|
+
| `prompt caching: … no cache read and no cache write` | the request marked `cache_control` at its end (top level or in the last message), the provider counted at least 4,096 input tokens (the largest minimum cacheable prompt in [Anthropic's prompt caching documentation](https://platform.claude.com/docs/en/build-with-claude/prompt-caching), checked on 2026-09-27) and reported neither a cache read nor a cache write |
|
|
326
|
+
| `cache TTL: … wrote the cache at the 5-minute TTL only` | every `cache_control` asked for `ttl: "1h"`, the TTL lever did not touch the request, and the provider wrote only 5-minute entries |
|
|
327
|
+
| `tool search: … tool search is off` | Claude Code traffic (a `x-claude-code-session-id` header or a `claude-cli/` user agent) sent at least 40 full tool definitions, none with `defer_loading` and no `tool_reference`. Claude Code turns tool search off by default behind any proxy, this gateway included: `bvsala claude` turns it back on in a new window, or export `ENABLE_TOOL_SEARCH=true` |
|
|
328
|
+
|
|
329
|
+
Each kind is logged once per session (Claude Code's session id; once per gateway
|
|
330
|
+
process for clients that send none) and every case is counted. `bvsala` prints
|
|
331
|
+
the totals when it exits, because the per-request log is silent inside `bvsala
|
|
332
|
+
claude|codex|goose|qwen` (unless `BVSALA_GATEWAY_LOG=1`). None of this is sent to BiVelio: the usage record has
|
|
333
|
+
no field for it (LICENSE §5), so it stays on your machine.
|
|
334
|
+
|
|
335
|
+
**Limits.**
|
|
336
|
+
|
|
337
|
+
- The guarantee covers what the gateway sends. It cannot make the provider
|
|
338
|
+
cache: the watcher reports, it does not fix.
|
|
339
|
+
- The cache TTL lever changes the price of a cache write, never the content the
|
|
340
|
+
model reads, and it is a trade: if a 5-minute entry expires before the next
|
|
341
|
+
turn starts, that turn pays for a cache write that a 1-hour entry would have
|
|
342
|
+
saved. The lever only acts where a large part of the prompt is being written
|
|
343
|
+
anyway (session start, compaction), and `BVSALA_GATEWAY_ELISION=0` turns it
|
|
344
|
+
off.
|
|
345
|
+
- On a request that declares server tools (web search, web fetch, code
|
|
346
|
+
execution, tool search, the advisor, MCP servers; the gateway counts any typed
|
|
347
|
+
tool other than a client tool such as bash or the text editor), the cache TTL
|
|
348
|
+
lever still applies but its saving is recorded as zero. When Claude uses a
|
|
349
|
+
server tool, the provider caches its result at the 5-minute TTL on its own,
|
|
350
|
+
whatever TTL your markers ask for, and reports that write in the same
|
|
351
|
+
`ephemeral_5m_input_tokens` counter
|
|
352
|
+
([Anthropic's documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-use-with-prompt-caching#server-tool-results-are-cached-automatically),
|
|
353
|
+
checked on 2026-09-27), so the invoice cannot tell which part the lever wrote.
|
|
354
|
+
- The two cache checks need the provider's usage: a request that is not metered
|
|
355
|
+
is not checked. The prompt-caching check uses the largest documented minimum
|
|
356
|
+
for every model, so a future model with a larger minimum would raise false
|
|
357
|
+
alarms until the threshold moves.
|
|
358
|
+
- For the same reason, the TTL check skips requests that declare server tools.
|
|
359
|
+
- The tool-search check only looks at Claude Code traffic: another client with
|
|
360
|
+
many tools may never have used tool search, and that is not degraded traffic.
|
|
361
|
+
- Header names arrive in lower case (HTTP header names are case-insensitive),
|
|
362
|
+
and a header your client sends twice arrives once, with both values joined by
|
|
363
|
+
a comma, in order.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Aider a través del gateway
|
|
2
|
+
|
|
3
|
+
**Fuente:** `docs/investigacion/2026-09-27/agentes-de-codigo.md`: código de
|
|
4
|
+
`Aider-AI/aider` (rama `main` a 2026-05-22; la última release publicada es la
|
|
5
|
+
v0.86, de agosto de 2025) y de `BerriAI/litellm` 1.82.3, la versión que fija
|
|
6
|
+
`main` de aider. Aider llama a los modelos a través de litellm, así que las
|
|
7
|
+
variables que mandan son las de litellm [V].
|
|
8
|
+
|
|
9
|
+
## Qué necesitas
|
|
10
|
+
|
|
11
|
+
- `aider` en el PATH y tu **API key** (`ANTHROPIC_API_KEY` o `OPENAI_API_KEY`).
|
|
12
|
+
- `bvsala` instalado, `BIVELIO_SERVICE_KEY` exportada y una licencia BiVelio activa (ver [README](README.md)).
|
|
13
|
+
|
|
14
|
+
## Envoltorio: `bvsala aider [args…]`
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bvsala aider # modelos de Anthropic
|
|
18
|
+
BVSALA_GATEWAY_UPSTREAM=openai bvsala aider --model gpt-… # modelos de OpenAI
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Un gateway habla con un solo proveedor, así que el envoltorio enruta uno:
|
|
22
|
+
|
|
23
|
+
- **Anthropic (por defecto).** Con `ANTHROPIC_API_KEY` presente, aider elige
|
|
24
|
+
Sonnet por defecto [V]. El envoltorio exporta `ANTHROPIC_API_BASE`, que litellm
|
|
25
|
+
lee **antes** que `ANTHROPIC_BASE_URL`, y litellm añade `/v1/messages` si la
|
|
26
|
+
URL no termina así: **sin `/v1`** [V].
|
|
27
|
+
- **OpenAI**, con `BVSALA_GATEWAY_UPSTREAM=openai`: exporta `OPENAI_BASE_URL` y
|
|
28
|
+
`OPENAI_API_BASE` (litellm las lee en ese orden), **con `/v1`** [V].
|
|
29
|
+
|
|
30
|
+
Lo que no es del proveedor enrutado va directo y no se mide (por ejemplo, un
|
|
31
|
+
modelo débil de otro proveedor). Al salir, el envoltorio imprime cuántas
|
|
32
|
+
peticiones midió y cuáles reenvió sin medir, y por qué.
|
|
33
|
+
|
|
34
|
+
### La trampa de OpenAI: el usage en stream
|
|
35
|
+
|
|
36
|
+
litellm solo añade `stream_options: {"include_usage": true}` cuando habla con
|
|
37
|
+
`api.openai.com` **directamente** (`get_stream_options`: sin `api_base`, o con
|
|
38
|
+
host `api.openai.com`) [V]. Detrás del gateway el host es `127.0.0.1`, así que
|
|
39
|
+
los streams de OpenAI **no piden su contador** y se reenvían sin medir. Dos
|
|
40
|
+
salidas:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
BVSALA_GATEWAY_UPSTREAM=openai BVSALA_GATEWAY_USAGE_INJECT=1 bvsala aider --model gpt-…
|
|
44
|
+
BVSALA_GATEWAY_UPSTREAM=openai bvsala aider --model gpt-… --no-stream
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
La primera añade la opción en el gateway (el último chunk llega con `choices`
|
|
48
|
+
vacío, lo mismo que aider recibe cuando habla con OpenAI directo); la segunda
|
|
49
|
+
pide respuestas enteras, que traen el `usage` en el JSON. Anthropic no tiene
|
|
50
|
+
esta trampa: su stream siempre trae el contador.
|
|
51
|
+
|
|
52
|
+
## Manual
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bvsala gateway # 8402, Anthropic
|
|
56
|
+
ANTHROPIC_API_BASE=http://127.0.0.1:8402 aider # SIN /v1
|
|
57
|
+
|
|
58
|
+
bvsala gateway --upstream openai --port 8403
|
|
59
|
+
OPENAI_API_BASE=http://127.0.0.1:8403/v1 aider --model gpt-… # CON /v1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## La trampa típica
|
|
63
|
+
|
|
64
|
+
- `--openai-api-base` en la línea de comandos o `openai-api-base:` en
|
|
65
|
+
`.aider.conf.yml` pisan la variable (aider la reescribe al arrancar) [V].
|
|
66
|
+
- Un `api_base` en `extra_params` de `.aider.model.settings.yml` manda sobre
|
|
67
|
+
todo: esa petición no pasa por el gateway.
|
|
68
|
+
|
|
69
|
+
## Qué ya mide aider
|
|
70
|
+
|
|
71
|
+
Aider enseña tokens y coste por mensaje, con los precios de litellm; cuando la
|
|
72
|
+
respuesta no trae `usage`, cuenta los tokens con su tokenizador local, que es
|
|
73
|
+
una estimación [V]. El gateway añade el contador del proveedor en cada
|
|
74
|
+
petición, el aviso de lo que no pudo medir y el panel del equipo.
|
|
@@ -117,8 +117,13 @@ con cada release de Claude Code; BV-SALA repite el smoke test de `bvsala claude`
|
|
|
117
117
|
contra cada versión nueva.
|
|
118
118
|
|
|
119
119
|
Las cabeceras `x-claude-code-session-id` / `agent-id` / `parent-agent-id`
|
|
120
|
-
llegan en el tráfico real y
|
|
121
|
-
|
|
120
|
+
llegan en el tráfico real y se reenvían al proveedor sin tocarlas. Además, el
|
|
121
|
+
gateway LEE las dos primeras y, si tienen forma de identificador, adjunta su
|
|
122
|
+
valor (`sessionId`, `agentId`) al registro de uso que manda a BiVelio: es lo que
|
|
123
|
+
reparte el coste por sesión y por subagente en el panel. Son los ids que Claude
|
|
124
|
+
Code ya pone en sus propias peticiones, no una persona ni un contenido;
|
|
125
|
+
`parent-agent-id` no se lee. La lista completa de lo que viaja está en la
|
|
126
|
+
LICENSE §5.
|
|
122
127
|
|
|
123
128
|
## Nota BYOK y wording
|
|
124
129
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Continue (CLI `cn` y extensiones) a través del gateway
|
|
2
|
+
|
|
3
|
+
**Fuente:** `docs/investigacion/2026-09-27/agentes-de-codigo.md`: código de
|
|
4
|
+
`continuedev/continue` (extensión v2.1.0, junio de 2026) y su doc de `cn`. Continue
|
|
5
|
+
se configura por **archivo** (`~/.continue/config.yaml`, el mismo para la CLI y
|
|
6
|
+
las extensiones de VS Code y JetBrains) [V]: no hay envoltorio, `bvsala doctor`
|
|
7
|
+
imprime el bloque.
|
|
8
|
+
|
|
9
|
+
## La forma del URL [V]
|
|
10
|
+
|
|
11
|
+
El proveedor `anthropic` de Continue tiene `apiBase` por defecto
|
|
12
|
+
`https://api.anthropic.com/v1/`, añade la barra final si falta y resuelve
|
|
13
|
+
`new URL("messages", apiBase)`. Por eso: **con `/v1`**; la barra final la pone él.
|
|
14
|
+
|
|
15
|
+
## `~/.continue/config.yaml`
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
models:
|
|
19
|
+
- name: Claude via bvsala
|
|
20
|
+
provider: anthropic
|
|
21
|
+
model: <Anthropic model id>
|
|
22
|
+
apiKey: <your Anthropic API key>
|
|
23
|
+
apiBase: http://127.0.0.1:8402/v1
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Y `bvsala gateway` corriendo aparte. En la CLI también vale `cn --config <fichero>`
|
|
27
|
+
con un fichero que lleve ese `apiBase`.
|
|
28
|
+
|
|
29
|
+
## Comprobar
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
[gateway] POST /v1/messages · <modelo> · $0.001234 (in 120, cache↑0 cache↓0, out 8)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- `[gateway] POST /messages → 404` → falta el `/v1`.
|
|
36
|
+
- nada en el log → el modelo activo no es el de este bloque.
|
|
37
|
+
|
|
38
|
+
## La trampa típica
|
|
39
|
+
|
|
40
|
+
- **Gateway apagado con la config escrita**: Continue falla con ese modelo hasta
|
|
41
|
+
que arranques `bvsala gateway`.
|
|
42
|
+
- El autocompletado usa su propio modelo (`roles: [autocomplete]`): si no apunta
|
|
43
|
+
al gateway, no se mide.
|
|
44
|
+
|
|
45
|
+
## Nota BYOK
|
|
46
|
+
|
|
47
|
+
**API key exclusivamente.** Nunca el OAuth de una suscripción Claude Pro/Max.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# GitHub Copilot (CLI y VS Code) a través del gateway — solo con tu propia clave
|
|
2
|
+
|
|
3
|
+
**Fuente:** `docs/investigacion/2026-09-27/agentes-de-codigo.md`: la doc oficial
|
|
4
|
+
de GitHub «Using your own LLM models in GitHub Copilot CLI» (fuente en
|
|
5
|
+
`github/docs`, consultada el 2026-09-27) y la de VS Code «AI language models in
|
|
6
|
+
VS Code» (fechada el 16-09-2026).
|
|
7
|
+
|
|
8
|
+
**Lo primero:** Copilot solo pasa por un base URL cuando usas **tu propia clave
|
|
9
|
+
de proveedor (BYOK)**. Los modelos alojados por GitHub van a GitHub y no se
|
|
10
|
+
pueden medir aquí; su gasto lo enseña `/usage` (créditos de IA de GitHub y
|
|
11
|
+
tokens por modelo). Con BYOK, la CLI funciona **sin cuenta de GitHub** [V].
|
|
12
|
+
|
|
13
|
+
## Copilot CLI
|
|
14
|
+
|
|
15
|
+
### Qué necesitas
|
|
16
|
+
|
|
17
|
+
- `copilot` en el PATH (en Windows, el instalador nativo: el shim `.cmd` de npm no
|
|
18
|
+
se puede lanzar con argumentos de forma segura y `bvsala` se niega con una guía).
|
|
19
|
+
- BYOK configurado y funcionando **directo** [V]:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
export COPILOT_PROVIDER_TYPE=anthropic
|
|
23
|
+
export COPILOT_PROVIDER_BASE_URL=https://api.anthropic.com
|
|
24
|
+
export COPILOT_PROVIDER_API_KEY=… # tu clave de Anthropic
|
|
25
|
+
export COPILOT_MODEL=<modelo de Claude>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
(Con OpenAI, el tipo por defecto, el base URL es `https://api.openai.com/v1`: ver «El tipo `openai`» abajo.)
|
|
29
|
+
- `bvsala` instalado, `BIVELIO_SERVICE_KEY` exportada y una licencia BiVelio activa (ver [README](README.md)).
|
|
30
|
+
|
|
31
|
+
### Envoltorio: `bvsala copilot [args…]`
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bvsala copilot
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Con `COPILOT_PROVIDER_TYPE=anthropic`, arranca el gateway contra
|
|
38
|
+
`api.anthropic.com` y lanza `copilot` con `COPILOT_PROVIDER_BASE_URL` apuntando
|
|
39
|
+
al gateway, **con la misma ruta que ya tenías**. Tu modelo y tu clave no se
|
|
40
|
+
tocan. Al salir imprime cuántas peticiones midió y cuáles reenvió sin medir, y
|
|
41
|
+
por qué.
|
|
42
|
+
|
|
43
|
+
Se niega, antes de arrancar nada y con el motivo, cuando:
|
|
44
|
+
|
|
45
|
+
- no hay `COPILOT_PROVIDER_BASE_URL` (estás en los modelos de GitHub: nada que medir);
|
|
46
|
+
- el tipo es `openai` (el de por defecto): todavía no, ver abajo;
|
|
47
|
+
- el tipo es `azure` u otro, o el base URL no es `https://api.anthropic.com`: el
|
|
48
|
+
gateway solo tarifa la API del propio proveedor a su precio de lista, y Azure,
|
|
49
|
+
un modelo local o un revendedor facturan distinto (o nada).
|
|
50
|
+
|
|
51
|
+
### Manual (tipo `anthropic`)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bvsala gateway # Anthropic, 8402
|
|
55
|
+
COPILOT_PROVIDER_BASE_URL=http://127.0.0.1:8402 copilot # SIN /v1
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Cada `POST /v1/messages` se mide con su contador (Messages siempre lo trae).
|
|
59
|
+
|
|
60
|
+
### El tipo `openai`: sin envoltorio hasta validarlo en mano
|
|
61
|
+
|
|
62
|
+
La doc oficial lo describe como «any other OpenAI Chat Completions API‑compatible
|
|
63
|
+
endpoint» [V], pero el changelog de la CLI dice que desde la 1.0.64 también
|
|
64
|
+
habla la **Responses API por WebSocket** con BYOK («Add websocket responses
|
|
65
|
+
support for BYOK OpenAI-compatible providers») [V]. El gateway responde **426**
|
|
66
|
+
a todo intento de WebSocket (así cae Codex a HTTP), y **no sabemos** si la CLI
|
|
67
|
+
de Copilot hace lo mismo: la CLI no es de código abierto. Un envoltorio que
|
|
68
|
+
puede romper la sesión no se publica sin probarlo. A mano, y mirando el log:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
bvsala gateway --upstream openai --port 8403
|
|
72
|
+
COPILOT_PROVIDER_BASE_URL=http://127.0.0.1:8403/v1 copilot # CON /v1
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `… → 426 (WebSocket not supported …)` seguido de líneas `POST /v1/responses`
|
|
76
|
+
o `POST /v1/chat/completions` con `$` → la CLI cayó a HTTP y se mide.
|
|
77
|
+
- Solo el 426 y la sesión falla → no funciona detrás del gateway; vuelve a la
|
|
78
|
+
URL directa.
|
|
79
|
+
- `not metered: the request did not ask for usage` → relanza el gateway con
|
|
80
|
+
`BVSALA_GATEWAY_USAGE_INJECT=1`.
|
|
81
|
+
|
|
82
|
+
### Lo que no pasa por aquí
|
|
83
|
+
|
|
84
|
+
Lo que va a GitHub con BYOK igualmente (`/delegate`, búsqueda de código,
|
|
85
|
+
telemetría sin `COPILOT_OFFLINE=true`) no es inferencia de tu proveedor [V].
|
|
86
|
+
|
|
87
|
+
## Copilot en VS Code (BYOK, «Custom Endpoint»)
|
|
88
|
+
|
|
89
|
+
No se detecta ni se envuelve (es una extensión): la receta la imprime `bvsala doctor`.
|
|
90
|
+
|
|
91
|
+
1. **Manage Language Models** → **Add Models** → **Custom Endpoint**.
|
|
92
|
+
2. Tipo de API: **Messages** (Anthropic). VS Code abre `chatLanguageModels.json`.
|
|
93
|
+
3. En el modelo, la **ruta completa** en `url`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
"url": "http://127.0.0.1:8402/v1/messages"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
VS Code usa tal cual una URL que ya lleva `/messages`, `/chat/completions` o
|
|
100
|
+
`/responses`; si no, añade la ruta y, si falta, `/v1` [V]. Con la ruta
|
|
101
|
+
completa no hay nada que adivinar.
|
|
102
|
+
4. `bvsala gateway` corriendo aparte.
|
|
103
|
+
|
|
104
|
+
El BYOK de VS Code cubre el chat y las tareas auxiliares (títulos, mensajes de
|
|
105
|
+
commit) [V]; las sugerencias en línea y los embeddings siguen en GitHub y no se
|
|
106
|
+
miden aquí. Las tareas auxiliares usan `chat.utilityModel` y
|
|
107
|
+
`chat.utilitySmallModel`, no el modelo del chat: si quieres medirlas, apúntalas
|
|
108
|
+
también a un modelo del Custom Endpoint.
|
|
109
|
+
|
|
110
|
+
## Nota BYOK
|
|
111
|
+
|
|
112
|
+
Tu clave, tu factura: es exactamente el caso que el gateway mide. Nunca enrutes
|
|
113
|
+
por aquí el OAuth de una suscripción Claude Pro/Max: Anthropic lo prohíbe en
|
|
114
|
+
harnesses de terceros.
|
package/docs/terminales/kilo.md
CHANGED
|
@@ -1,50 +1,73 @@
|
|
|
1
1
|
# Kilo Code a través del gateway
|
|
2
2
|
|
|
3
|
-
**Fuente:** `docs/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
**Fuente:** `docs/investigacion/2026-09-27/agentes-de-codigo.md` (código de
|
|
4
|
+
`Kilo-Org/kilocode` v7.8.1, 2026-09-25). Desde la serie 7, Kilo es un fork de
|
|
5
|
+
opencode (`.opencode-version`: v1.18.26): la CLI (`kilo`), la extensión de VS
|
|
6
|
+
Code y la de JetBrains leen la misma configuración, `kilo.json`, y el proveedor
|
|
7
|
+
`anthropic` se apunta con `provider.anthropic.options.baseURL`. Su capa de
|
|
8
|
+
protocolo añade `/messages` a `https://api.anthropic.com/v1`: **con `/v1`** [V].
|
|
9
|
+
Esto sustituye a la receta anterior (proveedor custom por UI, forma inferida).
|
|
8
10
|
|
|
9
11
|
## Qué necesitas
|
|
10
12
|
|
|
11
|
-
- Kilo
|
|
12
|
-
-
|
|
13
|
-
- `bvsala gateway` corriendo en `http://127.0.0.1:8402` (necesita `BIVELIO_SERVICE_KEY` y una licencia BiVelio activa; ver [README](README.md)).
|
|
13
|
+
- Kilo (CLI `kilo`, o la extensión) con el proveedor **`anthropic`** y tu **API key** de Anthropic.
|
|
14
|
+
- `bvsala` instalado, `BIVELIO_SERVICE_KEY` exportada y una licencia BiVelio activa (la recoge el gateway con la clave; ver [README](README.md)).
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
**Lo que no pasa por aquí:** el proveedor por defecto de Kilo es su propia
|
|
17
|
+
pasarela (Kilo Gateway, modelos alojados por Kilo con su cuenta). Ese tráfico va
|
|
18
|
+
a Kilo, no a un base URL tuyo, y no se mide. Tampoco los demás proveedores.
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
2. **Provider API**: «Anthropic Messages».
|
|
19
|
-
3. Pega tu **API key** de Anthropic.
|
|
20
|
-
4. **Base URL** — prueba primero:
|
|
20
|
+
## Envoltorio (CLI): `bvsala kilo [args…]`
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
```bash
|
|
23
|
+
export BIVELIO_SERVICE_KEY=bvk_…
|
|
24
|
+
bvsala kilo
|
|
25
|
+
```
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
Kilo acepta la configuración entera en `KILO_CONFIG_CONTENT` y la fusiona por
|
|
28
|
+
encima de la global y de la de proyecto [V]. El envoltorio arranca un gateway
|
|
29
|
+
efímero y lanza `kilo` con esa variable apuntando el proveedor `anthropic` a
|
|
30
|
+
`http://127.0.0.1:<puerto>/v1`. **No escribe nada en disco.** Si ya exportas tu
|
|
31
|
+
propio `KILO_CONFIG_CONTENT`, lo fusiona y solo cambia ese `baseURL`; si no es un
|
|
32
|
+
objeto JSON, se niega antes de arrancar sin repetir su valor. Al salir imprime
|
|
33
|
+
cuántas peticiones midió y cuáles reenvió sin medir, y por qué.
|
|
28
34
|
|
|
29
|
-
##
|
|
35
|
+
## Manual (CLI y extensiones): `~/.config/kilo/kilo.json`
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"provider": {
|
|
40
|
+
"anthropic": {
|
|
41
|
+
"options": {
|
|
42
|
+
"baseURL": "http://127.0.0.1:8402/v1"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
32
48
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
**Con `/v1`, sin barra final.** Precedencia (de menos a más): global
|
|
50
|
+
(`~/.config/kilo/kilo.json`), `KILO_CONFIG`, proyecto (`./kilo.json`,
|
|
51
|
+
`.kilo/kilo.json`), `KILO_CONFIG_CONTENT`, gestionada [V]. Arranca el gateway
|
|
52
|
+
aparte con `bvsala gateway`.
|
|
53
|
+
|
|
54
|
+
## Comprobar
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
[gateway] POST /v1/messages · <modelo> · $0.001234 (in 120, cache↑0 cache↓0, out 8)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `[gateway] POST /messages → 404` → falta el `/v1`.
|
|
61
|
+
- `[gateway] POST /v1/v1/messages → 404` → sobra un `/v1`.
|
|
62
|
+
- nada en el log → el modelo activo no es del proveedor `anthropic` (¿Kilo Gateway?).
|
|
39
63
|
|
|
40
64
|
## La trampa típica
|
|
41
65
|
|
|
42
|
-
- **
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
corriendo, Kilo fallará hasta que lo arranques o cambies de proveedor.
|
|
66
|
+
- **Gateway apagado con la config escrita**: `kilo.json` recuerda el base URL;
|
|
67
|
+
sin `bvsala gateway` corriendo, Kilo falla hasta que lo arranques o quites la
|
|
68
|
+
clave. El envoltorio no tiene esta trampa.
|
|
46
69
|
|
|
47
70
|
## Nota BYOK
|
|
48
71
|
|
|
49
72
|
**API key exclusivamente.** Anthropic prohíbe usar el OAuth de Claude Pro/Max en
|
|
50
|
-
harnesses de terceros; esta receta es la del proveedor
|
|
73
|
+
harnesses de terceros; esta receta es la del proveedor `anthropic` con API key.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Lo que el gateway no mide hoy, y por qué
|
|
2
|
+
|
|
3
|
+
**Fuente:** `docs/investigacion/2026-09-27/agentes-de-codigo.md`. Decir que no es
|
|
4
|
+
parte de la receta: un terminal apuntado al gateway que no se puede medir sería
|
|
5
|
+
pagar una licencia por un proxy vacío.
|
|
6
|
+
|
|
7
|
+
## Gemini CLI — no se mide todavía
|
|
8
|
+
|
|
9
|
+
Gemini CLI acepta un base URL propio: `GOOGLE_GEMINI_BASE_URL` (y
|
|
10
|
+
`GOOGLE_VERTEX_BASE_URL` con Vertex), en HTTPS salvo que apunte a `localhost` o
|
|
11
|
+
`127.0.0.1` [V: `docs/reference/configuration.md` de `google-gemini/gemini-cli`,
|
|
12
|
+
2026-09-27]. El problema no es enrutarlo: es que habla la **API de Gemini**
|
|
13
|
+
(`…/models/<modelo>:streamGenerateContent`, contador en `usageMetadata`), y el
|
|
14
|
+
gateway solo sabe leer el contador de Anthropic Messages y de OpenAI Chat
|
|
15
|
+
Completions y Responses. Cada petición se reenviaría con la línea
|
|
16
|
+
`not metered: no usage dialect for this route`, sin coste.
|
|
17
|
+
|
|
18
|
+
Hasta que el gateway lea ese dialecto, el contador de Gemini CLI es su propio
|
|
19
|
+
`/stats model` (tokens por modelo y cuota) [V]. Qué haría falta para medirlo, y
|
|
20
|
+
por qué no se ha hecho hoy (los precios de contexto largo de los modelos Pro),
|
|
21
|
+
está en el informe.
|
|
22
|
+
|
|
23
|
+
## Cursor — no se puede
|
|
24
|
+
|
|
25
|
+
Cursor manda **todas** las peticiones, también las de tu propia clave, a través
|
|
26
|
+
de sus servidores: «all requests are routed through Cursor's servers for final
|
|
27
|
+
prompt building» [V: cursor.com/docs/settings/api-keys, 2026-09-27]. Un gateway
|
|
28
|
+
en `127.0.0.1` es inalcanzable desde ahí, y exponerlo a Internet no es una
|
|
29
|
+
opción (escucha solo en loopback a propósito). Las claves propias, además, solo
|
|
30
|
+
cubren los modelos de chat; Tab sigue con los modelos de Cursor [V]. El contador
|
|
31
|
+
de Cursor es su panel de uso.
|
|
32
|
+
|
|
33
|
+
## Copilot con modelos de GitHub — no pasa por un base URL
|
|
34
|
+
|
|
35
|
+
Sin BYOK, Copilot (CLI y VS Code) usa los modelos alojados por GitHub, que van a
|
|
36
|
+
GitHub y no a un base URL tuyo. Con BYOK sí se mide: ver [copilot.md](copilot.md).
|
|
37
|
+
|
|
38
|
+
## Kilo Gateway — no pasa por un base URL tuyo
|
|
39
|
+
|
|
40
|
+
El proveedor por defecto de Kilo son sus modelos alojados; ese tráfico va a Kilo.
|
|
41
|
+
Con el proveedor `anthropic` y tu clave sí se mide: ver [kilo.md](kilo.md).
|