@sunerpy/kiro-provider 0.4.0 → 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.
Files changed (3) hide show
  1. package/README.md +188 -37
  2. package/dist/cli.js +134 -88
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # kiro-provider
2
2
 
3
- > A standalone OpenAI Responses and Anthropic Messages gateway for AWS Kiro (CodeWhisperer).
3
+ > A protocol-fidelity gateway exposing a verified OpenAI Responses and Anthropic Messages subset over AWS Kiro (CodeWhisperer).
4
4
 
5
5
  [![CI](https://github.com/sunerpy/kiro-provider/actions/workflows/ci.yml/badge.svg)](https://github.com/sunerpy/kiro-provider/actions/workflows/ci.yml)
6
6
  [![codecov](https://codecov.io/gh/sunerpy/kiro-provider/branch/main/graph/badge.svg)](https://codecov.io/gh/sunerpy/kiro-provider)
@@ -12,6 +12,7 @@
12
12
  ## Table of Contents
13
13
 
14
14
  - [Features](#features)
15
+ - [Protocol compatibility](#protocol-compatibility)
15
16
  - [Install](#install)
16
17
  - [Quickstart](#quickstart)
17
18
  - [Run as a background service](#run-as-a-background-service)
@@ -19,6 +20,7 @@
19
20
  - [Proxy](#proxy)
20
21
  - [Security](#security)
21
22
  - [Using with an LLM](#using-with-an-llm)
23
+ - [Use with Zuno](#use-with-zuno)
22
24
  - [Use with Codex CLI](#use-with-codex-cli)
23
25
  - [Use with Claude Code](#use-with-claude-code)
24
26
  - [Development](#development)
@@ -29,15 +31,58 @@
29
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`.
30
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`.
31
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`.
32
- - 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 a refresh lock compatible with `opencode-kiro-auth` v0.20.6.
33
- - Standard-field session affinity: Codex/OpenAI, OpenCode, and Claude Code requests reuse a persisted account binding and Kiro conversation ID without private headers, cookies, or client patches.
34
- - Account-scoped scheduling and keep-alive transport pools: unrelated accounts can run concurrently, while one account is protected from overlapping Kiro streams; access-token refresh updates the cached client instead of rebuilding its connection pool.
35
- - Zero provider-owned prompt injection: request adapters preserve client text and structured protocol fields, and reject unsupported guarantees instead of emulating them with hidden instructions.
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.
36
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.
37
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.
38
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.
39
42
  - Ships as a self-contained compiled binary via `bun build --compile` — no runtime install required on the target machine.
40
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
+
41
86
  ## Install
42
87
 
43
88
  Pick one of three channels.
@@ -176,12 +221,16 @@ In the rest of this README, `./dist/kiro-provider` refers to any of the above; s
176
221
  ## Run as a background service
177
222
 
178
223
  For an agent host, run **one long-lived provider per OS user** and point
179
- Codex, OpenCode, Claude Code, Zuno, and other clients at that local endpoint.
224
+ compatible OpenAI/Anthropic clients, OpenCode, Zuno, and compatibility probes
225
+ for Codex or Claude Code at that local endpoint.
180
226
  Do not start a new provider for every agent or conversation. Keeping one
181
- process alive lets those standard clients share the provider's persisted
182
- session/account affinity and its process-local, account-scoped keep-alive
183
- pools. This remains best-effort connection reuse, not a promise that every
184
- request uses one physical TCP connection.
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.
185
234
 
186
235
  Use a pinned standalone binary for a service rather than fetching through
187
236
  `bunx` on every start. The examples below assume the release installers'
@@ -384,8 +433,9 @@ For an AI agent or installer, treat setup as successful only when:
384
433
  1. the binary and explicit config path exist;
385
434
  2. the service/task runs as the credential-owning user;
386
435
  3. `/health` succeeds;
387
- 4. authenticated `/ready` succeeds, proving a readable auth source and at
388
- least one active account.
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.
389
439
 
390
440
  Use the fixed service/task name above so repeated setup is idempotent. Restart
391
441
  it after changing the config or replacing the binary. Do not make the client
@@ -402,13 +452,20 @@ Config is loaded from `~/.config/kiro-provider/config.json` (or `$XDG_CONFIG_HOM
402
452
  | `port` | `8787` | `KIRO_PROVIDER_PORT` |
403
453
  | `api_keys` | required, non-empty | `KIRO_PROVIDER_API_KEYS` |
404
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` |
405
457
  | `auth_source` | `opencode-shared` | `KIRO_PROVIDER_AUTH_SOURCE` |
406
458
  | `opencode_auth_db_path` | `null` (uses the OpenCode default) | `KIRO_PROVIDER_OPENCODE_AUTH_DB_PATH` |
407
459
  | `proxy_url` | `null` | `KIRO_PROVIDER_PROXY_URL` |
408
460
  | `default_region` | `us-east-1` | `KIRO_PROVIDER_DEFAULT_REGION` |
461
+ | `sdk_http_keep_alive` | `false` | `KIRO_PROVIDER_SDK_HTTP_KEEP_ALIVE` |
409
462
  | `account_selection_strategy` | `lowest-usage` | `KIRO_PROVIDER_ACCOUNT_SELECTION_STRATEGY` |
410
463
  | `session_affinity_ttl_ms` | `86400000` | `KIRO_PROVIDER_SESSION_AFFINITY_TTL_MS` |
411
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` |
412
469
  | `log_level` | `info` | `KIRO_PROVIDER_LOG_LEVEL` |
413
470
 
414
471
  The full field reference, including retry/timeout tuning and the test-only `test_upstream_endpoint`, lives in [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md).
@@ -423,26 +480,42 @@ Some networks reach one model family directly while another needs a proxy (for e
423
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.
424
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.
425
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.
426
- - **No secrets in logs.** Proxy URLs and account tokens are never printed; don't commit a real config file, account database, or gateway key.
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.
427
485
 
428
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.
429
487
 
430
488
  ## Using with an LLM
431
489
 
432
- Use `POST /v1/responses` for new OpenAI clients and Codex. Use
433
- `POST /v1/messages` for Anthropic clients and Claude Code. Only point a
490
+ Use `POST /v1/responses` for OpenAI Responses clients. Use
491
+ `POST /v1/messages` for Anthropic Messages clients. Only point a
434
492
  Chat-Completions-only client (`@ai-sdk/openai-compatible`, older LangChain
435
493
  adapters, or an OpenCode custom provider using that package) at
436
494
  `POST /v1/chat/completions` after explicitly enabling the legacy endpoint.
437
495
 
438
- No client-specific session extension is required. The gateway derives
439
- affinity from standard/native request fields when present and otherwise from
440
- the initial user turn, stores only an irreversible key hash, and persists the
441
- selected account plus Kiro conversation ID. Connection reuse is best-effort
442
- through an account-scoped keep-alive pool; HTTP and upstream behavior can
443
- still select a different physical socket. Stateful Responses fields
444
- `previous_response_id` and `conversation` are rejected until the gateway has
445
- a real response-state store, so clients must resend the complete input.
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.
446
519
 
447
520
  <details>
448
521
  <summary>Agent command reference</summary>
@@ -457,9 +530,79 @@ Contract: human-readable status lines go to stdout, errors to stderr, non-zero e
457
530
 
458
531
  </details>
459
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
+
460
598
  ## Use with Codex CLI
461
599
 
462
- kiro-provider's `POST /v1/responses` endpoint speaks the OpenAI Responses wire format, so [Codex CLI](https://github.com/openai/codex) (verified end-to-end against 0.149.0-alpha.4.1 on 2026-08-22) can use it as a custom `model_provider` with `wire_api = "responses"`. Test it with an isolated `CODEX_HOME` so your real `~/.codex` config is never touched:
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:
463
606
 
464
607
  ```bash
465
608
  export CODEX_TEST_ROOT="$(mktemp -d)"
@@ -479,16 +622,21 @@ EOF
479
622
  codex exec --skip-git-repo-check "say hi"
480
623
  ```
481
624
 
482
- Requires the gateway running (`kiro-provider serve`) with at least one active
483
- OpenCode Kiro account in the default shared mode, or an account in the
484
- explicit local compatibility store. Full details, plus a ready-made isolated
485
- smoke test (`scripts/codex-smoke.sh`), live in
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
486
629
  [`docs/CODEX.md`](docs/CODEX.md).
487
630
 
488
631
  ## Use with Claude Code
489
632
 
490
- Claude Code uses the Anthropic Messages protocol rather than OpenAI Chat
491
- Completions. Point it at the gateway root:
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:
492
640
 
493
641
  ```bash
494
642
  export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
@@ -497,22 +645,25 @@ claude
497
645
  ```
498
646
 
499
647
  The gateway accepts either `Authorization: Bearer <key>` or `x-api-key:
500
- <key>` for Anthropic routes. Streaming text and tool calls are translated to
501
- Anthropic SSE. Extended-thinking signatures are not fabricated or exposed,
502
- and `/v1/messages/count_tokens` is an explicit estimate (the response carries
503
- `x-kiro-token-count-mode: estimate`). See
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
504
651
  [`docs/CLAUDE_CODE.md`](docs/CLAUDE_CODE.md).
505
652
 
506
- The real-client validation record for OpenCode, Codex, Claude Code, shared
507
- authentication, affinity reuse, and the legacy Chat gate is in
508
- [`docs/E2E_VALIDATION_2026-08-22.md`](docs/E2E_VALIDATION_2026-08-22.md).
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.
509
657
 
510
658
  ## Development
511
659
 
512
660
  ```bash
513
661
  bun install
662
+ bun run lint
514
663
  bun run typecheck
515
664
  bun test
665
+ bun run build
666
+ bun run build:binary
516
667
  bash scripts/security-check.sh # security regression suite (Linux, needs openssl/curl/ss)
517
668
  ```
518
669