@sunerpy/kiro-provider 0.3.1 → 0.5.0-rc.1
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 +457 -24
- package/dist/cli.js +260 -99
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# kiro-provider
|
|
2
2
|
|
|
3
|
-
> A
|
|
3
|
+
> A protocol-fidelity gateway exposing a verified OpenAI Responses and Anthropic Messages subset over AWS Kiro (CodeWhisperer).
|
|
4
4
|
|
|
5
5
|
[](https://github.com/sunerpy/kiro-provider/actions/workflows/ci.yml)
|
|
6
6
|
[](https://codecov.io/gh/sunerpy/kiro-provider)
|
|
@@ -12,25 +12,77 @@
|
|
|
12
12
|
## Table of Contents
|
|
13
13
|
|
|
14
14
|
- [Features](#features)
|
|
15
|
+
- [Protocol compatibility](#protocol-compatibility)
|
|
15
16
|
- [Install](#install)
|
|
16
17
|
- [Quickstart](#quickstart)
|
|
18
|
+
- [Run as a background service](#run-as-a-background-service)
|
|
17
19
|
- [Configuration](#configuration)
|
|
18
20
|
- [Proxy](#proxy)
|
|
19
21
|
- [Security](#security)
|
|
20
22
|
- [Using with an LLM](#using-with-an-llm)
|
|
23
|
+
- [Use with Zuno](#use-with-zuno)
|
|
21
24
|
- [Use with Codex CLI](#use-with-codex-cli)
|
|
25
|
+
- [Use with Claude Code](#use-with-claude-code)
|
|
22
26
|
- [Development](#development)
|
|
23
27
|
- [License](#license)
|
|
24
28
|
|
|
25
29
|
## Features
|
|
26
30
|
|
|
27
|
-
- OpenAI
|
|
31
|
+
- OpenAI Responses `POST /v1/responses` and Anthropic Messages `POST /v1/messages` (both streaming and non-streaming), plus `POST /v1/messages/count_tokens`, `GET /v1/models`, `GET /health`, and authenticated `GET /ready`.
|
|
32
|
+
- Legacy OpenAI Chat Completions is available at `POST /v1/chat/completions`, but is disabled by default and must be explicitly enabled with `enable_legacy_chat_completions`.
|
|
28
33
|
- Bearer API-key gate that fails closed: the server refuses to start with no configured keys, and defaults to binding `127.0.0.1`.
|
|
29
|
-
-
|
|
30
|
-
- `
|
|
34
|
+
- Live OpenCode authentication reuse by default: `auth_source: "opencode-shared"` reads the same `~/.config/opencode/kiro.db`, honors tombstones, updates shared health/usage, and uses the account schema and refresh-lock behavior of `opencode-kiro-auth` v0.20.7.
|
|
35
|
+
- Explicit-only session affinity by default: Responses requests can opt in through standard `metadata`, compatibility `client_metadata`, or `prompt_cache_key`; requests without an explicit key never derive identity from prompt text. A matching Zuno native OpenAI transport supplies `metadata.zuno_session_id` automatically.
|
|
36
|
+
- Account-scoped scheduling and cached SDK/transport objects: unrelated accounts can run concurrently, while one account is protected from overlapping Kiro streams; access-token refresh updates the cached client instead of rebuilding it. Kiro model-call HTTP keep-alive is disabled by default and is an explicit transport opt-in.
|
|
37
|
+
- Zero provider-owned prompt injection in the default `safe` mode: a canonical IR preserves client text, roles, content-block boundaries, tool identity, ordering, and source paths; unsupported guarantees are rejected before Kiro instead of being emulated with hidden instructions.
|
|
38
|
+
- Encrypted reasoning replay for complete native Kiro envelopes: opaque `kr1_...` tokens, AES-256-GCM storage, tenant/model/account/conversation/output binding, TTL/LRU cleanup, and account-locked replay.
|
|
39
|
+
- Multi-account rotation with automatic token refresh and failover. Shared mode treats OpenCode's database as the authentication authority; the provider database stores session affinity only.
|
|
40
|
+
- An explicit `auth_source: "local"` compatibility mode retains `kiro-provider login` and `accounts import`; imported accounts are snapshots and must not be confused with live shared authentication.
|
|
31
41
|
- A single global `proxy_url` that, when set, routes all upstream egress (model requests, token refresh, device-code login) through one HTTP(S) proxy.
|
|
32
42
|
- Ships as a self-contained compiled binary via `bun build --compile` — no runtime install required on the target machine.
|
|
33
43
|
|
|
44
|
+
## Protocol compatibility
|
|
45
|
+
|
|
46
|
+
v0.5 is intentionally a **verified compatibility subset**. It does not accept
|
|
47
|
+
fields and silently discard them. The default `protocol_projection_mode:
|
|
48
|
+
"safe"` never prepends or rewrites client instructions, merges adjacent
|
|
49
|
+
messages, clears repeated assistant output, removes trailing text such as `{`,
|
|
50
|
+
or creates model-visible compensation prose.
|
|
51
|
+
|
|
52
|
+
Key boundaries:
|
|
53
|
+
|
|
54
|
+
- plain text, consecutive same-role turns, function/custom tool declarations,
|
|
55
|
+
calls, and results retain their original structure and order;
|
|
56
|
+
- a message containing multiple top-level text blocks returns
|
|
57
|
+
`unsupported_content_block_projection`, because Kiro exposes only one text
|
|
58
|
+
field and concatenation would erase block boundaries;
|
|
59
|
+
- `instructions`, `system`, and `developer` return
|
|
60
|
+
`unsupported_instruction_projection` in safe mode because the tested Kiro
|
|
61
|
+
`additionalContext` channel was rejected;
|
|
62
|
+
- `tool_choice: auto` is supported; required/named choice,
|
|
63
|
+
`parallel_tool_calls: false`, strict schemas, custom grammars, and namespace
|
|
64
|
+
tools are rejected rather than weakened;
|
|
65
|
+
- base64/data-URL images are supported, while remote image URLs and detail
|
|
66
|
+
controls are rejected;
|
|
67
|
+
- an output-token limit is probe-confirmed only for `claude-sonnet-5` variants
|
|
68
|
+
in the range 1,024–128,000;
|
|
69
|
+
- stateful Responses fields and native Web Search remain unsupported, and the
|
|
70
|
+
provider never fabricates search/citation events.
|
|
71
|
+
|
|
72
|
+
Current compiled-binary acceptance on 2026-08-26: OpenAI JavaScript SDK 7.5.0
|
|
73
|
+
passes Responses, explicit Chat, function/custom tool loops, and encrypted
|
|
74
|
+
reasoning replay across restart. OpenCode Responses passes only in explicit
|
|
75
|
+
`legacy-user-prefix` mode with Claude Sonnet 5; OpenCode Chat is blocked by
|
|
76
|
+
its nonstandard `cache_control`. Codex 0.149.0-alpha.4.1 is blocked by
|
|
77
|
+
`parallel_tool_calls: false`, and Claude Code 2.1.209 is blocked by
|
|
78
|
+
`output_config.format`, `context_management`, and its retry that places
|
|
79
|
+
`system` in `messages.1.role`. These are RC findings; stable v0.5.0 remains
|
|
80
|
+
gated rather than silently discarding or relocating those fields.
|
|
81
|
+
|
|
82
|
+
For the complete capability matrix, error codes, reasoning replay contract,
|
|
83
|
+
and v0.4 migration steps, see
|
|
84
|
+
[`docs/PROTOCOL_COMPATIBILITY.md`](docs/PROTOCOL_COMPATIBILITY.md).
|
|
85
|
+
|
|
34
86
|
## Install
|
|
35
87
|
|
|
36
88
|
Pick one of three channels.
|
|
@@ -91,15 +143,20 @@ In the rest of this README, `./dist/kiro-provider` refers to any of the above; s
|
|
|
91
143
|
|
|
92
144
|
## Quickstart
|
|
93
145
|
|
|
94
|
-
1. **
|
|
146
|
+
1. **Authenticate Kiro through OpenCode.** The default shared-auth mode uses
|
|
147
|
+
OpenCode's live account database:
|
|
95
148
|
|
|
96
149
|
```bash
|
|
97
|
-
|
|
150
|
+
opencode auth login
|
|
98
151
|
```
|
|
99
152
|
|
|
100
|
-
|
|
153
|
+
Select Kiro and complete the normal login flow. If you intentionally want
|
|
154
|
+
an independent compatibility store instead, set `"auth_source": "local"`
|
|
155
|
+
and then use:
|
|
101
156
|
|
|
102
157
|
```bash
|
|
158
|
+
./dist/kiro-provider login
|
|
159
|
+
# or take a one-time snapshot:
|
|
103
160
|
./dist/kiro-provider accounts import
|
|
104
161
|
```
|
|
105
162
|
|
|
@@ -117,7 +174,7 @@ In the rest of this README, `./dist/kiro-provider` refers to any of the above; s
|
|
|
117
174
|
./dist/kiro-provider serve
|
|
118
175
|
```
|
|
119
176
|
|
|
120
|
-
4. **Call
|
|
177
|
+
4. **Call the default Responses endpoint.**
|
|
121
178
|
|
|
122
179
|
```bash
|
|
123
180
|
curl -fsS http://127.0.0.1:8787/v1/models \
|
|
@@ -132,15 +189,18 @@ In the rest of this README, `./dist/kiro-provider` refers to any of the above; s
|
|
|
132
189
|
apiKey: "sk-your-private-key",
|
|
133
190
|
});
|
|
134
191
|
|
|
135
|
-
const
|
|
192
|
+
const response = await client.responses.create({
|
|
136
193
|
model: "auto",
|
|
137
|
-
|
|
194
|
+
input: "Explain this repository.",
|
|
138
195
|
});
|
|
139
196
|
|
|
140
|
-
console.log(
|
|
197
|
+
console.log(response.output_text);
|
|
141
198
|
```
|
|
142
199
|
|
|
143
|
-
|
|
200
|
+
OpenAI-compatible libraries that only implement Chat Completions require
|
|
201
|
+
`"enable_legacy_chat_completions": true` in the gateway config. For example,
|
|
202
|
+
with the [Vercel AI SDK](https://sdk.vercel.ai/) via
|
|
203
|
+
`@ai-sdk/openai-compatible`:
|
|
144
204
|
|
|
145
205
|
```ts
|
|
146
206
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
@@ -158,6 +218,230 @@ In the rest of this README, `./dist/kiro-provider` refers to any of the above; s
|
|
|
158
218
|
});
|
|
159
219
|
```
|
|
160
220
|
|
|
221
|
+
## Run as a background service
|
|
222
|
+
|
|
223
|
+
For an agent host, run **one long-lived provider per OS user** and point
|
|
224
|
+
compatible OpenAI/Anthropic clients, OpenCode, Zuno, and compatibility probes
|
|
225
|
+
for Codex or Claude Code at that local endpoint.
|
|
226
|
+
Do not start a new provider for every agent or conversation. Keeping one
|
|
227
|
+
process alive lets requests with an explicit affinity key reuse their
|
|
228
|
+
persisted account/Kiro-conversation binding, while all requests can reuse
|
|
229
|
+
process-local, account-scoped SDK clients and transport objects. A request
|
|
230
|
+
without an explicit key gets a fresh Kiro conversation. Kiro model-call HTTP
|
|
231
|
+
sockets are fresh by default (`sdk_http_keep_alive: false`); enabling it is a
|
|
232
|
+
best-effort transport optimization, never a promise that one session owns one
|
|
233
|
+
physical TCP connection.
|
|
234
|
+
|
|
235
|
+
Use a pinned standalone binary for a service rather than fetching through
|
|
236
|
+
`bunx` on every start. The examples below assume the release installers'
|
|
237
|
+
defaults:
|
|
238
|
+
|
|
239
|
+
- binary: `~/.local/bin/kiro-provider` on Linux,
|
|
240
|
+
`%USERPROFILE%\.local\bin\kiro-provider.exe` on Windows;
|
|
241
|
+
- config: `~/.config/kiro-provider/config.json`;
|
|
242
|
+
- service/task name: `kiro-provider`.
|
|
243
|
+
|
|
244
|
+
Run the service as the **same OS user** that ran `opencode auth login`.
|
|
245
|
+
Default `auth_source: "opencode-shared"` resolves that user's OpenCode
|
|
246
|
+
database and home/XDG directories; running as `root`, `LocalSystem`, or
|
|
247
|
+
another user will normally select different credentials. Use absolute paths,
|
|
248
|
+
keep the API key in the protected config file rather than service arguments,
|
|
249
|
+
and set `opencode_auth_db_path` explicitly if the service has a different XDG
|
|
250
|
+
environment.
|
|
251
|
+
|
|
252
|
+
### Linux: systemd user service
|
|
253
|
+
|
|
254
|
+
Verify the installed binary and config first:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
test -x "$HOME/.local/bin/kiro-provider"
|
|
258
|
+
test -r "$HOME/.config/kiro-provider/config.json"
|
|
259
|
+
chmod 600 "$HOME/.config/kiro-provider/config.json"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Install a [systemd user service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html):
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
SERVICE_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
|
|
266
|
+
install -d -m 700 "$SERVICE_DIR"
|
|
267
|
+
cat > "$SERVICE_DIR/kiro-provider.service" <<'EOF'
|
|
268
|
+
[Unit]
|
|
269
|
+
Description=kiro-provider local Kiro gateway
|
|
270
|
+
|
|
271
|
+
[Service]
|
|
272
|
+
Type=exec
|
|
273
|
+
ExecStart=%h/.local/bin/kiro-provider serve --config %h/.config/kiro-provider/config.json
|
|
274
|
+
Restart=on-failure
|
|
275
|
+
RestartSec=5s
|
|
276
|
+
TimeoutStopSec=30s
|
|
277
|
+
UMask=0077
|
|
278
|
+
|
|
279
|
+
[Install]
|
|
280
|
+
WantedBy=default.target
|
|
281
|
+
EOF
|
|
282
|
+
chmod 600 "$SERVICE_DIR/kiro-provider.service"
|
|
283
|
+
|
|
284
|
+
systemctl --user daemon-reload
|
|
285
|
+
systemctl --user enable --now kiro-provider.service
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
If the binary or config is elsewhere, replace `ExecStart` with those absolute
|
|
289
|
+
paths. For a custom `XDG_CONFIG_HOME`, also add an explicit
|
|
290
|
+
`Environment=XDG_CONFIG_HOME=/absolute/path` line or configure
|
|
291
|
+
`opencode_auth_db_path`.
|
|
292
|
+
|
|
293
|
+
Operate and inspect the service:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
systemctl --user is-active kiro-provider.service
|
|
297
|
+
systemctl --user restart kiro-provider.service
|
|
298
|
+
journalctl --user -u kiro-provider.service -n 100 --no-pager
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
User services normally start with that user's service manager. If the
|
|
302
|
+
provider must start at boot and remain after logout, an administrator may
|
|
303
|
+
enable lingering with `loginctl enable-linger <user>` after reviewing the
|
|
304
|
+
machine's security policy.
|
|
305
|
+
|
|
306
|
+
To remove the unit:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
systemctl --user disable --now kiro-provider.service
|
|
310
|
+
rm "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/kiro-provider.service"
|
|
311
|
+
systemctl --user daemon-reload
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Windows: per-user scheduled task
|
|
315
|
+
|
|
316
|
+
`kiro-provider.exe` is a normal foreground executable, not a native Windows
|
|
317
|
+
Service Control Manager executable. Do not register it directly with
|
|
318
|
+
`sc.exe`. The built-in, dependency-free option is a
|
|
319
|
+
[Scheduled Task](https://learn.microsoft.com/powershell/module/scheduledtasks/register-scheduledtask)
|
|
320
|
+
that starts at sign-in, runs as the current user, and restarts after failure.
|
|
321
|
+
|
|
322
|
+
Run the following in PowerShell as the same user that owns the OpenCode
|
|
323
|
+
credentials. It creates a small launcher so stdout/stderr are retained under
|
|
324
|
+
`%LOCALAPPDATA%\kiro-provider`:
|
|
325
|
+
|
|
326
|
+
```powershell
|
|
327
|
+
$Binary = Join-Path $HOME ".local\bin\kiro-provider.exe"
|
|
328
|
+
$Config = Join-Path $HOME ".config\kiro-provider\config.json"
|
|
329
|
+
$ServiceDir = Join-Path $HOME ".config\kiro-provider"
|
|
330
|
+
$LogDir = Join-Path $env:LOCALAPPDATA "kiro-provider"
|
|
331
|
+
$Launcher = Join-Path $ServiceDir "service.ps1"
|
|
332
|
+
|
|
333
|
+
if (-not (Test-Path -LiteralPath $Binary -PathType Leaf)) {
|
|
334
|
+
throw "kiro-provider binary not found: $Binary"
|
|
335
|
+
}
|
|
336
|
+
if (-not (Test-Path -LiteralPath $Config -PathType Leaf)) {
|
|
337
|
+
throw "kiro-provider config not found: $Config"
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
New-Item -ItemType Directory -Force -Path $ServiceDir, $LogDir | Out-Null
|
|
341
|
+
@'
|
|
342
|
+
$ErrorActionPreference = "Stop"
|
|
343
|
+
$Binary = Join-Path $HOME ".local\bin\kiro-provider.exe"
|
|
344
|
+
$Config = Join-Path $HOME ".config\kiro-provider\config.json"
|
|
345
|
+
$LogDir = Join-Path $env:LOCALAPPDATA "kiro-provider"
|
|
346
|
+
$Log = Join-Path $LogDir "service.log"
|
|
347
|
+
$PreviousLog = Join-Path $LogDir "service.previous.log"
|
|
348
|
+
|
|
349
|
+
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
|
|
350
|
+
if ((Test-Path -LiteralPath $Log) -and ((Get-Item -LiteralPath $Log).Length -gt 10MB)) {
|
|
351
|
+
Move-Item -Force -LiteralPath $Log -Destination $PreviousLog
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
& $Binary serve --config $Config *>> $Log
|
|
355
|
+
exit $LASTEXITCODE
|
|
356
|
+
'@ | Set-Content -LiteralPath $Launcher -Encoding UTF8
|
|
357
|
+
|
|
358
|
+
$User = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
|
359
|
+
$PowerShell = (Get-Command powershell.exe).Source
|
|
360
|
+
$Action = New-ScheduledTaskAction `
|
|
361
|
+
-Execute $PowerShell `
|
|
362
|
+
-Argument ('-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "{0}"' -f $Launcher)
|
|
363
|
+
$Trigger = New-ScheduledTaskTrigger -AtLogOn -User $User
|
|
364
|
+
$Principal = New-ScheduledTaskPrincipal `
|
|
365
|
+
-UserId $User `
|
|
366
|
+
-LogonType Interactive `
|
|
367
|
+
-RunLevel Limited
|
|
368
|
+
$Settings = New-ScheduledTaskSettingsSet `
|
|
369
|
+
-RestartCount 999 `
|
|
370
|
+
-RestartInterval (New-TimeSpan -Minutes 1) `
|
|
371
|
+
-ExecutionTimeLimit ([TimeSpan]::Zero) `
|
|
372
|
+
-MultipleInstances IgnoreNew `
|
|
373
|
+
-AllowStartIfOnBatteries `
|
|
374
|
+
-DontStopIfGoingOnBatteries `
|
|
375
|
+
-StartWhenAvailable
|
|
376
|
+
|
|
377
|
+
Stop-ScheduledTask -TaskName "kiro-provider" -ErrorAction SilentlyContinue
|
|
378
|
+
Register-ScheduledTask `
|
|
379
|
+
-TaskName "kiro-provider" `
|
|
380
|
+
-Action $Action `
|
|
381
|
+
-Trigger $Trigger `
|
|
382
|
+
-Principal $Principal `
|
|
383
|
+
-Settings $Settings `
|
|
384
|
+
-Description "Local AWS Kiro gateway for AI agents" `
|
|
385
|
+
-Force | Out-Null
|
|
386
|
+
Start-ScheduledTask -TaskName "kiro-provider"
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Inspect, restart, and follow logs:
|
|
390
|
+
|
|
391
|
+
```powershell
|
|
392
|
+
Get-ScheduledTask -TaskName "kiro-provider" | Get-ScheduledTaskInfo
|
|
393
|
+
Stop-ScheduledTask -TaskName "kiro-provider"
|
|
394
|
+
Start-ScheduledTask -TaskName "kiro-provider"
|
|
395
|
+
Get-Content "$env:LOCALAPPDATA\kiro-provider\service.log" -Tail 100 -Wait
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
To remove the task and launcher:
|
|
399
|
+
|
|
400
|
+
```powershell
|
|
401
|
+
Stop-ScheduledTask -TaskName "kiro-provider" -ErrorAction SilentlyContinue
|
|
402
|
+
Unregister-ScheduledTask -TaskName "kiro-provider" -Confirm:$false
|
|
403
|
+
Remove-Item "$HOME\.config\kiro-provider\service.ps1"
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
This task intentionally runs only in the current user's interactive session,
|
|
407
|
+
so it can use that user's network access and OpenCode credentials without
|
|
408
|
+
storing a Windows password. A true pre-login Windows service requires a
|
|
409
|
+
service wrapper and a deliberately configured user account; do not run it as
|
|
410
|
+
`LocalSystem` and expect the same OpenCode database.
|
|
411
|
+
|
|
412
|
+
### Health checks and automation contract
|
|
413
|
+
|
|
414
|
+
After either installation, verify both process liveness and authenticated
|
|
415
|
+
readiness:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
curl -fsS http://127.0.0.1:8787/health
|
|
419
|
+
curl -fsS http://127.0.0.1:8787/ready \
|
|
420
|
+
-H 'Authorization: Bearer sk-your-private-key'
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
PowerShell equivalent:
|
|
424
|
+
|
|
425
|
+
```powershell
|
|
426
|
+
Invoke-RestMethod "http://127.0.0.1:8787/health"
|
|
427
|
+
$Headers = @{ Authorization = "Bearer sk-your-private-key" }
|
|
428
|
+
Invoke-RestMethod "http://127.0.0.1:8787/ready" -Headers $Headers
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
For an AI agent or installer, treat setup as successful only when:
|
|
432
|
+
|
|
433
|
+
1. the binary and explicit config path exist;
|
|
434
|
+
2. the service/task runs as the credential-owning user;
|
|
435
|
+
3. `/health` succeeds;
|
|
436
|
+
4. authenticated `/ready` succeeds, proving a readable auth source, at least
|
|
437
|
+
one active account, writable provider state, an available reasoning keyring,
|
|
438
|
+
and coverage for every key ID referenced by an unexpired replay record.
|
|
439
|
+
|
|
440
|
+
Use the fixed service/task name above so repeated setup is idempotent. Restart
|
|
441
|
+
it after changing the config or replacing the binary. Do not make the client
|
|
442
|
+
responsible for starting a private provider process; configure clients only
|
|
443
|
+
with the stable base URL and gateway API key.
|
|
444
|
+
|
|
161
445
|
## Configuration
|
|
162
446
|
|
|
163
447
|
Config is loaded from `~/.config/kiro-provider/config.json` (or `$XDG_CONFIG_HOME/kiro-provider/config.json`), overridable by `KIRO_PROVIDER_*` environment variables and, for `serve`, by CLI flags. Precedence is **CLI flag > environment variable > config file > schema default**.
|
|
@@ -167,9 +451,21 @@ Config is loaded from `~/.config/kiro-provider/config.json` (or `$XDG_CONFIG_HOM
|
|
|
167
451
|
| `host` | `127.0.0.1` | `KIRO_PROVIDER_HOST` |
|
|
168
452
|
| `port` | `8787` | `KIRO_PROVIDER_PORT` |
|
|
169
453
|
| `api_keys` | required, non-empty | `KIRO_PROVIDER_API_KEYS` |
|
|
454
|
+
| `enable_legacy_chat_completions` | `false` | `KIRO_PROVIDER_ENABLE_LEGACY_CHAT_COMPLETIONS` |
|
|
455
|
+
| `protocol_projection_mode` | `safe` | `KIRO_PROVIDER_PROTOCOL_PROJECTION_MODE` |
|
|
456
|
+
| `session_affinity_mode` | `explicit-only` | `KIRO_PROVIDER_SESSION_AFFINITY_MODE` |
|
|
457
|
+
| `auth_source` | `opencode-shared` | `KIRO_PROVIDER_AUTH_SOURCE` |
|
|
458
|
+
| `opencode_auth_db_path` | `null` (uses the OpenCode default) | `KIRO_PROVIDER_OPENCODE_AUTH_DB_PATH` |
|
|
170
459
|
| `proxy_url` | `null` | `KIRO_PROVIDER_PROXY_URL` |
|
|
171
460
|
| `default_region` | `us-east-1` | `KIRO_PROVIDER_DEFAULT_REGION` |
|
|
461
|
+
| `sdk_http_keep_alive` | `false` | `KIRO_PROVIDER_SDK_HTTP_KEEP_ALIVE` |
|
|
172
462
|
| `account_selection_strategy` | `lowest-usage` | `KIRO_PROVIDER_ACCOUNT_SELECTION_STRATEGY` |
|
|
463
|
+
| `session_affinity_ttl_ms` | `86400000` | `KIRO_PROVIDER_SESSION_AFFINITY_TTL_MS` |
|
|
464
|
+
| `session_affinity_max_entries` | `10000` | `KIRO_PROVIDER_SESSION_AFFINITY_MAX_ENTRIES` |
|
|
465
|
+
| `reasoning_replay_key_path` | auto-generated config path | `KIRO_PROVIDER_REASONING_REPLAY_KEY_PATH` |
|
|
466
|
+
| `reasoning_replay_keys` | `[]` | `KIRO_PROVIDER_REASONING_REPLAY_KEYS` |
|
|
467
|
+
| `reasoning_replay_ttl_ms` | `86400000` | `KIRO_PROVIDER_REASONING_REPLAY_TTL_MS` |
|
|
468
|
+
| `reasoning_replay_max_entries` | `10000` | `KIRO_PROVIDER_REASONING_REPLAY_MAX_ENTRIES` |
|
|
173
469
|
| `log_level` | `info` | `KIRO_PROVIDER_LOG_LEVEL` |
|
|
174
470
|
|
|
175
471
|
The full field reference, including retry/timeout tuning and the test-only `test_upstream_endpoint`, lives in [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md).
|
|
@@ -180,36 +476,139 @@ Some networks reach one model family directly while another needs a proxy (for e
|
|
|
180
476
|
|
|
181
477
|
## Security
|
|
182
478
|
|
|
183
|
-
- **Fail-closed authentication.** The server will not start without at least one non-empty `api_keys` entry
|
|
479
|
+
- **Fail-closed authentication.** The server will not start without at least one non-empty `api_keys` entry. OpenAI routes require `Authorization: Bearer <key>`; Anthropic routes also accept `x-api-key: <key>`.
|
|
184
480
|
- **Local bind by default.** `host` defaults to `127.0.0.1`; only bind `0.0.0.0` behind a firewall or authenticated reverse proxy.
|
|
185
|
-
- **
|
|
186
|
-
- **
|
|
481
|
+
- **Single authentication authority.** Shared mode reads and updates OpenCode's existing Kiro database and fails closed on an incompatible schema; it never runs provider-owned migrations against that database.
|
|
482
|
+
- **Locked-down provider state.** `accounts.db` (and its WAL/SHM files) are created with mode `0600`; in shared mode this database contains affinity/state, not the authoritative credentials.
|
|
483
|
+
- **Authenticated reasoning replay.** The database stores token/fingerprint hashes and AES-256-GCM ciphertext, not raw `kr1_...` tokens. Missing active decryption keys fail startup.
|
|
484
|
+
- **No sensitive content in logs.** Gateway/account secrets, replay tokens, signatures, reasoning, and request prompt text are not logged; structured audit fields contain hashes and field names only. Don't commit a real config file, account database, keyring, or gateway key.
|
|
187
485
|
|
|
188
486
|
> **Responsible use.** kiro-provider reuses AWS Kiro accounts you already control and consumes your own account quota. Supply your own accounts — this project is not a way to share or resell someone else's Kiro access, and it should not be used to circumvent per-account usage limits.
|
|
189
487
|
|
|
190
488
|
## Using with an LLM
|
|
191
489
|
|
|
192
|
-
|
|
490
|
+
Use `POST /v1/responses` for OpenAI Responses clients. Use
|
|
491
|
+
`POST /v1/messages` for Anthropic Messages clients. Only point a
|
|
492
|
+
Chat-Completions-only client (`@ai-sdk/openai-compatible`, older LangChain
|
|
493
|
+
adapters, or an OpenCode custom provider using that package) at
|
|
494
|
+
`POST /v1/chat/completions` after explicitly enabling the legacy endpoint.
|
|
495
|
+
|
|
496
|
+
Standard clients must also stay within the verified subset. In safe mode a
|
|
497
|
+
client that always sends system/developer instructions, custom grammars,
|
|
498
|
+
namespace tools, or Anthropic `cache_control` receives a field-level 400; the
|
|
499
|
+
gateway does not modify that request to force it through Kiro. The optional
|
|
500
|
+
`legacy-user-prefix` projection is a temporary instruction-only migration aid
|
|
501
|
+
for v0.5.x/v0.6.x and is scheduled for removal in v0.7.0.
|
|
502
|
+
|
|
503
|
+
The default `session_affinity_mode: "explicit-only"` never hashes prompt text
|
|
504
|
+
to guess a conversation. Responses checks, in order,
|
|
505
|
+
`metadata.zuno_session_id`, `metadata.kiro_provider_session_id`, compatibility
|
|
506
|
+
`client_metadata.thread_id|session_id|conversation_id`, and
|
|
507
|
+
`prompt_cache_key`. Chat checks only `prompt_cache_key`; Anthropic Messages
|
|
508
|
+
has no verified explicit affinity field. With no key, the request gets a
|
|
509
|
+
fresh Kiro conversation but can still reuse account-scoped SDK clients and
|
|
510
|
+
transport objects. The Kiro SDK's direct/proxy agents use fresh sockets by default;
|
|
511
|
+
set `sdk_http_keep_alive: true` only when the deployment has validated pooled
|
|
512
|
+
socket behavior.
|
|
513
|
+
The temporary `legacy-initial-input` mode restores only the old affinity
|
|
514
|
+
heuristics and logs a startup warning; it does not alter request content.
|
|
515
|
+
|
|
516
|
+
Stateful Responses fields `previous_response_id` and `conversation` are
|
|
517
|
+
rejected until the gateway has a real response-state store, so clients must
|
|
518
|
+
resend the complete input.
|
|
193
519
|
|
|
194
520
|
<details>
|
|
195
521
|
<summary>Agent command reference</summary>
|
|
196
522
|
|
|
197
523
|
- `kiro-provider serve [--config <path>] [--host <host>] [--port <port>] [--proxy <url>]` — start the gateway.
|
|
198
|
-
- `kiro-provider login [--config <path>] [--start-url <url>] [--region <region>]` —
|
|
199
|
-
- `kiro-provider accounts list` — list
|
|
200
|
-
- `kiro-provider accounts import [--from <path>] [--config <path>]` —
|
|
201
|
-
- `kiro-provider accounts remove <id|email>` — remove one account
|
|
524
|
+
- `kiro-provider login [--config <path>] [--start-url <url>] [--region <region>]` — local compatibility mode only; shared mode directs you to `opencode auth login`.
|
|
525
|
+
- `kiro-provider accounts list` — list accounts in the local compatibility store.
|
|
526
|
+
- `kiro-provider accounts import [--from <path>] [--config <path>]` — take a one-time snapshot into the local compatibility store.
|
|
527
|
+
- `kiro-provider accounts remove <id|email>` — remove one account from the local compatibility store.
|
|
202
528
|
|
|
203
|
-
Contract: human-readable status lines go to stdout, errors to stderr, non-zero exit on failure. `GET /v1/models` and `GET /
|
|
529
|
+
Contract: human-readable status lines go to stdout, errors to stderr, non-zero exit on failure. `GET /v1/models`, `GET /health`, and authenticated `GET /ready` return structured JSON.
|
|
204
530
|
|
|
205
531
|
</details>
|
|
206
532
|
|
|
533
|
+
## Use with Zuno
|
|
534
|
+
|
|
535
|
+
Run one compiled kiro-provider service as the credential-owning OS user, then
|
|
536
|
+
configure Zuno's native Rust OpenAI transport. No Node package, AI SDK, private
|
|
537
|
+
header, or provider-spawn hook is required:
|
|
538
|
+
|
|
539
|
+
```json
|
|
540
|
+
{
|
|
541
|
+
"model": "kiro/auto",
|
|
542
|
+
"small_model": "kiro/auto",
|
|
543
|
+
"provider": {
|
|
544
|
+
"kiro": {
|
|
545
|
+
"name": "Local kiro-provider",
|
|
546
|
+
"transport": "openai",
|
|
547
|
+
"surface": "responses",
|
|
548
|
+
"env": ["KIRO_GATEWAY_API_KEY"],
|
|
549
|
+
"options": {
|
|
550
|
+
"baseURL": "http://127.0.0.1:8787/v1",
|
|
551
|
+
"maxTokens": null
|
|
552
|
+
},
|
|
553
|
+
"models": {
|
|
554
|
+
"auto": {
|
|
555
|
+
"name": "Kiro Auto",
|
|
556
|
+
"reasoning": true,
|
|
557
|
+
"tool_call": true
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Set `KIRO_GATEWAY_API_KEY` to one key from the provider's `api_keys`, then
|
|
566
|
+
verify the native route:
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
export KIRO_GATEWAY_API_KEY='sk-your-private-key'
|
|
570
|
+
zuno debug config
|
|
571
|
+
zuno models kiro --verbose
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
The matching Zuno OpenAI Responses transport maps the durable Zuno session ID
|
|
575
|
+
to standard `metadata.zuno_session_id` on every main turn and tool
|
|
576
|
+
continuation. It does not add that ID to input, messages, instructions, tool
|
|
577
|
+
descriptions, or any other model-visible field; internal title/summary calls
|
|
578
|
+
do not join the main provider conversation. Therefore one Zuno session is
|
|
579
|
+
serialized onto one persisted account/Kiro-conversation binding, while
|
|
580
|
+
different sessions remain isolated even if their first prompt and upstream
|
|
581
|
+
tool aliases are identical. Tool declaration and alias state remains local to
|
|
582
|
+
each request.
|
|
583
|
+
|
|
584
|
+
Keep `surface: "responses"` for this integration. Selecting `chat` requires
|
|
585
|
+
the separately enabled legacy endpoint and does not carry the Zuno Responses
|
|
586
|
+
session metadata.
|
|
587
|
+
|
|
588
|
+
Current Zuno sends agent instructions, while the live Kiro
|
|
589
|
+
`additionalContext` probe did not prove a lossless instruction projection.
|
|
590
|
+
Consequently the verified functional path currently requires the provider's
|
|
591
|
+
explicit `protocol_projection_mode: "legacy-user-prefix"`; `safe` correctly
|
|
592
|
+
returns `unsupported_instruction_projection` and never rewrites the request.
|
|
593
|
+
Set Zuno `options.maxTokens` to `null` as shown so its generic layer does not
|
|
594
|
+
add the unsupported `max_output_tokens: 32000`. Neither setting uses a private
|
|
595
|
+
Header or client-side prompt patch; the legacy mode is an explicit migration
|
|
596
|
+
exception scheduled for removal in v0.7.0.
|
|
597
|
+
|
|
207
598
|
## Use with Codex CLI
|
|
208
599
|
|
|
209
|
-
|
|
600
|
+
Codex uses the correct Responses endpoint, but the current compiled RC gate
|
|
601
|
+
against 0.149.0-alpha.4.1 does not pass: Codex sends
|
|
602
|
+
`parallel_tool_calls: false`, and Kiro cannot guarantee that constraint. The
|
|
603
|
+
provider returns `unsupported_parallel_tool_calls` before Kiro instead of
|
|
604
|
+
ignoring the field. The following isolated configuration reproduces the
|
|
605
|
+
compatibility check without touching the real `~/.codex` state:
|
|
210
606
|
|
|
211
607
|
```bash
|
|
212
|
-
export
|
|
608
|
+
export CODEX_TEST_ROOT="$(mktemp -d)"
|
|
609
|
+
export CODEX_HOME="$CODEX_TEST_ROOT/home"
|
|
610
|
+
export CODEX_SQLITE_HOME="$CODEX_TEST_ROOT/sqlite"
|
|
611
|
+
mkdir -p "$CODEX_HOME" "$CODEX_SQLITE_HOME"
|
|
213
612
|
export LOCALGW_KEY="sk-...your gateway api key..."
|
|
214
613
|
cat > "$CODEX_HOME/config.toml" <<'EOF'
|
|
215
614
|
model = "gpt-5.6-sol"
|
|
@@ -223,14 +622,48 @@ EOF
|
|
|
223
622
|
codex exec --skip-git-repo-check "say hi"
|
|
224
623
|
```
|
|
225
624
|
|
|
226
|
-
|
|
625
|
+
For Codex 0.149.0-alpha.4.1 the expected RC result is a non-zero exit carrying
|
|
626
|
+
that field-level error. A future successful basic request must still pass a
|
|
627
|
+
real shell/custom-tool loop, continuation, and restart reasoning replay before
|
|
628
|
+
Codex is marked supported. Full details live in
|
|
629
|
+
[`docs/CODEX.md`](docs/CODEX.md).
|
|
630
|
+
|
|
631
|
+
## Use with Claude Code
|
|
632
|
+
|
|
633
|
+
Claude Code uses Anthropic Messages, but Claude Code 2.1.209 currently sends
|
|
634
|
+
`output_config.format` and `context_management`; after the first rejection it
|
|
635
|
+
also retries with `system` inside `messages.1.role`, which is not a valid
|
|
636
|
+
Anthropic Messages role and cannot be silently moved. The provider rejects
|
|
637
|
+
these shapes before Kiro in both safe and legacy instruction modes. The
|
|
638
|
+
standard configuration below is therefore a compatibility probe, not a
|
|
639
|
+
current support claim:
|
|
640
|
+
|
|
641
|
+
```bash
|
|
642
|
+
export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
|
|
643
|
+
export ANTHROPIC_AUTH_TOKEN="sk-your-private-key"
|
|
644
|
+
claude
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
The gateway accepts either `Authorization: Bearer <key>` or `x-api-key:
|
|
648
|
+
<key>` for Anthropic routes. Direct Messages requests within the verified
|
|
649
|
+
subset support typed JSON/SSE and tools, while `/v1/messages/count_tokens` is
|
|
650
|
+
an explicit estimate. See
|
|
651
|
+
[`docs/CLAUDE_CODE.md`](docs/CLAUDE_CODE.md).
|
|
652
|
+
|
|
653
|
+
The current compiled-service validation record is in
|
|
654
|
+
[`docs/audits/kiro-provider-v0.5.0-rc.1-validation-2026-08-26.md`](docs/audits/kiro-provider-v0.5.0-rc.1-validation-2026-08-26.md).
|
|
655
|
+
The older [`docs/E2E_VALIDATION_2026-08-22.md`](docs/E2E_VALIDATION_2026-08-22.md)
|
|
656
|
+
is retained as historical v0.4 evidence only.
|
|
227
657
|
|
|
228
658
|
## Development
|
|
229
659
|
|
|
230
660
|
```bash
|
|
231
661
|
bun install
|
|
662
|
+
bun run lint
|
|
232
663
|
bun run typecheck
|
|
233
664
|
bun test
|
|
665
|
+
bun run build
|
|
666
|
+
bun run build:binary
|
|
234
667
|
bash scripts/security-check.sh # security regression suite (Linux, needs openssl/curl/ss)
|
|
235
668
|
```
|
|
236
669
|
|