Skip to content

Multi-user fixes, rework of #97 (kiro → kiro-auth with fallback), performance fixes, tool usage errors and Opus 4.8#100

Open
RvVeen wants to merge 21 commits into
tickernelz:masterfrom
Servoy:master
Open

Multi-user fixes, rework of #97 (kiro → kiro-auth with fallback), performance fixes, tool usage errors and Opus 4.8#100
RvVeen wants to merge 21 commits into
tickernelz:masterfrom
Servoy:master

Conversation

@RvVeen
Copy link
Copy Markdown
Contributor

@RvVeen RvVeen commented Jun 1, 2026

Sorry for the size of this one — the plan was to split it into separate PRs,
but I kept fixing small things as more people started using it and the feedback
rolled in. Then #97 broke a few things, so I reworked that part a different way,
keeping backwards compatibility.

The rename (kiro → kiro-auth)

OpenCode was adding native kiro support, which clashed with this plugin and
broke requests (anomalyco/opencode#26221). They've since reverted it, but there's
still an open PR for official Kiro support — so the rename is there to stay out
of its way. The provider id is now kiro-auth, with a fallback so the old kiro
name keeps working for existing installs (both ids share the same custom fetch).

Everything else in here

  • Added tests for the parts that were missing, bringing coverage to ~85%
  • Fixed a dropped last character when the final byte wasn't a complete UTF-8 character
  • Reuse the same generated session token after restarting OpenCode instead of
    creating a new one each time
  • Fixed IDC re-auth endlessly adding rows to the session table, which made
    startup slower and slower over time (with an automatic cleanup for existing rows)
  • Added HTTP error logging to make debugging issues easier
  • Fixed tool-name length handling for Kiro (it has an undocumented limit)
  • De-duplicate tool calls with the same name before sending them
  • Fixed rate-limit handling: a locking issue, and a timeout budget that was
    counting its own backoff sleep
  • Fixed the SDK client not closing properly (small memory leak)
  • Show Kiro's official usage value in the dialog instead of an internal one
  • Refresh that usage live on startup, so the first reading after the monthly
    reset reflects the current period instead of last month's stored value
  • Report Kiro's real session counts when it sends them, instead of always
    estimating from the context window
  • Send the parsed request body to Kiro instead of the raw JSON string
  • Added support for Opus 4.8
  • Simplified the install example — the plugin registers its provider and models automatically now

Testing

  • bun test — 254 tests pass across 18 files
  • bun run typecheck — clean
  • bun run build — green
  • Tested on multiple different machines

RvVeen and others added 21 commits May 19, 2026 12:09
TextDecoder in streaming mode buffers incomplete multi-byte sequences.
Added explicit flush after the read loop so nothing gets dropped.
Was using crypto.randomUUID() on every request, so each tool call
counted as a new Kiro session. Now persisting the ID in kiro.db
keyed on workspace + first user message, so threads survive restarts.

Also trigger reauth when all accounts are permanently unhealthy
instead of throwing immediately.
Every re-auth rotates the clientId, so the account hash changed and
a new row was inserted. Fixed the hash to use profileArn+email only,
and added cleanup of stale rows on each upsert.
HTTP errors (400/401/403/429/500) were only visible as UI toasts.
Added logger.warn calls so they land in plugin.log as well.
- Reauth: cross-process lock via SQLite, timeout after 90s, poll when
  another instance holds the lock
- Bearer token invalid: force token refresh instead of permanent failure
- Token refresher: use error.code for markUnhealthy
- Health: remove HTTP_403 and bearer token from isPermanentError
- Accounts: null-guard on round-robin, cursor anchored to full list
- IDC: deterministic account ID ignores rotating clientId
- Tests: 178 tests across 13 files
…ming

- Add agentContinuationId and agentTaskType to conversationState so Kiro
  groups agentic loop turns for credit optimization
- Determine isNewThread after mergeAdjacentMessages (prevents false 400
  on subagents/compaction)
- Tool call streaming: accept chunks by toolUseId alone (name only on
  first chunk), fixing incomplete JSON on large tool inputs
- SDK client: Connection: close header, explicit timeouts
All behind DEBUG or OPENCODE_LOG_LEVEL=debug:
- [REQ] convId, history length, agentContinuationId per request
- [REQ] done/error on completion
- [CREDITS] usage from Kiro metering event
- [TOOL_CALL] invalid JSON on tool input parse failure
- [STREAM] errors in stream transformer
- Enforce 64-char max on tool names with SHA256 hash suffix for long names
- Bidirectional name mapping: shorten on send, restore on response
- Sanitize tool inputs: strip empty-string keys that Kiro rejects
- Deduplicate tool calls in response (by name+arguments)
- User-Agent with version and stable machineId hash
- x-amzn-codewhisperer-optout header

Reviewed best practices from github.com/justlovemaki/AIClient2API
- Trim history from front when payload exceeds Kiro's ~615KB limit
- Recursively strip additionalProperties and empty required arrays from
  tool input schemas (Kiro rejects these)
- Remove empty toolUses arrays from history entries (Kiro quirk)

Reviewed best practices from github.com/jwadow/kiro-gateway
- Payload trim: incremental size accounting (O(N) instead of O(N²) on
  large histories), strip orphaned toolUses/toolResults to keep history
  valid for Kiro
- shortenToolName: don't split surrogate pairs when truncating long names
- sanitizeSchema: recurse into not/patternProperties/prefixItems/$defs
  /definitions/contains, guard against circular schemas
- deduplicateToolCallsByContent: use \\x00 separator to avoid name/input
  boundary collisions

Adds edge-case test suite covering all of the above.
- fetchUsageLimits: only chain to next param combo on FEATURE_NOT_SUPPORTED;
  bubble up 429/401/5xx/network errors instead of hitting the API 4x per call
- UsageTracker: skip retries on rate-limit errors (don't amplify), don't
  mark accounts unhealthy on 429 (the request flow handles it)
- ErrorHandler 429: track sleep time so the request timeout budget excludes
  rate-limit waits — a 60s wait shouldn't burn a 120s request timeout
- RetryStrategy: subtract excludedMs from elapsed time on shouldContinue
- Reauth lock: INSERT OR REPLACE handles the race where two instances
  both observe the same dead/expired lock and both try to claim it
noUncheckedIndexedAccess types indexed access as T | undefined, so several
test files failed tsc (TS2532) and one ManagedAccount fixture was missing a
required field (rateLimitResetTime, TS2322). release.yml gates publishing on
typecheck, so master could not be released until this was green.

- Add rateLimitResetTime to account fixtures.
- Add non-null assertions on length-checked indexed access in tests.
…request

- createSdkClient tears down the cached client when the token rotated, so its
  sockets/agent don't leak before the replacement is cached.
- RequestHandler passes the parsed body object (not the raw JSON string) to
  transformToSdkRequest.
- getUsageLimits reads currentUsageWithPrecision/usageLimitWithPrecision, so the
  usage toast matches the Kiro dashboard credit figure instead of a rounded,
  stale request count.
- AuthHandler refreshes usage from the API at startup (token-refresh aware,
  non-blocking, falls back to the stored value), so the first toast of a new
  billing period is not last month's number.
- transformSdkStream prefers Kiro's real tokenUsage over the context-% estimate.
- Extract summarizeUsage() and UsageTracker.syncNow() to remove duplication.
…ckernelz#97)

Merge PR tickernelz#97 with maintainer adjustments:\n\n- Align default plugin provider id with the new kiro provider id.\n- Harden OpenCode auth bootstrap so malformed auth.json files are not overwritten and restrictive file permissions are preserved.\n- Add regression tests for auth bootstrap, provider id, Zod enum compatibility, and empty OpenAI-compatible stream chunks.\n- Bump @opencode-ai/plugin to 1.15.11 and align docs/model context examples.
OpenCode briefly shipped a built-in `kiro` provider that collided with this
plugin's `kiro` id and crashed every request with `Y.languageModel is not a
function` (anomalyco/opencode#26221). It was reverted, but is likely to
return — so this is a pre-emptive fix.

Move the primary provider id to `kiro-auth` so installs never clash with a
future built-in `kiro`. Keep `kiro` registered as a back-compat alias so
existing installs keep working; both ids share one custom fetch.

Mechanics: OpenCode binds auth.loader to a single provider id, so the custom
fetch is attached via provider.options in the config hook. resolveSDK reads
options.fetch per provider, so both ids route through the plugin, and the
fetch self-identifies Kiro requests by URL.
Per the Kiro model docs (kiro.dev/docs/models), Opus 4.8 (1M context, 2.2x,
experimental) is the latest model and was missing. Add the mapping, default
model entry, thinking variant, README example, and a resolution test, mirroring
the Opus 4.7 entries.
…a cherry-pick)

PR tickernelz#97's changes are already in this branch (cherry-picked into 5703be6 with
conflict resolution). This -s ours merge records upstream/master as an ancestor
so the fork is purely ahead of upstream — making the PR diff clean and
auto-mergeable — without changing our tree.
The plugin registers the kiro-auth provider and its models automatically, so the
manual provider/models block is no longer needed — reduce the install example to
just the plugin entry. Also call out explicitly that the old `kiro` id still
works as a fallback alias, with `kiro-auth` recommended going forward.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants