Skip to content

fix: stateful bootstrap, snapshot turn lookup, per-endpoint auth, stream metadata (v0.2.2) - #6

Merged
Clarit-AI merged 1 commit into
mainfrom
fix/stateful-bootstrap-and-metadata
May 25, 2026
Merged

fix: stateful bootstrap, snapshot turn lookup, per-endpoint auth, stream metadata (v0.2.2)#6
Clarit-AI merged 1 commit into
mainfrom
fix/stateful-bootstrap-and-metadata

Conversation

@Clarit-AI

Copy link
Copy Markdown
Owner

Summary

Closes out the stateful path so the comparative demo can validate end-to-end. Four targeted fixes; all blockers are provider-side (server is confirmed done).

1. Inject conversation_id on the generation request (bootstrap-critical)

Engram keys WARM-tier state by conversation_id on /v1/chat/completions. The compatibility fallback was generating via baseModel.doGenerate without a conversation_id, so turn 1 never seeded WARM state and the next turn had nothing to restore. New prepareBaseCallOptions helper replaces providerOptions.clarit with a clean snake_case body ({ conversation_id }) before delegating — @ai-sdk/openai-compatible spreads that into the request body. Applied to doStandardGenerate, doStandardStream, and doCompatibilityFallback.

2. Fix off-by-one in compatibility bridge snapshot lookup

The caller's turnNumber is the turn this generation will produce; the snapshot we want was saved at the end of the previous turn (turnNumber - 1). /get_snapshot_info requires an exact turn, so the arithmetic happens there. The restore call now omits turn_number entirely — server resolves to the latest snapshot for the conversation, avoiding a second round of arithmetic. When turnNumber is 0 or undefined the bridge short-circuits to no-snapshot (no prior turn to restore from).

3. Per-endpoint API keys

/v1/tokenize takes the regular key; snapshot routes take the admin key. Provider factory wires both via the new tokenizeApiKey on the snapshot client. Aligns with Engram's intentional auth split and lets the temporary server-side Option A patch be reverted.

4. Stream wrapper preserves providerMetadata

doStandardStream now threads conversationId/turnNumber/branchName/rid and (when autoSaveSnapshot is set) the save outcome into the finish part's providerMetadata, so streamText sees {clarit:{...}} just like generateText does. wrapGenerateResultAsStream (restore-and-generate and compatibility fast-path) also forwards providerMetadata on its finish chunk.

Test plan

  • npm test — 67 / 67 passing (was 56)
  • npm run typecheck — clean
  • npm run build — clean (dist/ verified)
  • New unit coverage:
    • conversation_id injection on doGenerate and doStream
    • camelCase keys stripped from forwarded providerOptions.clarit
    • tokenize uses tokenizeApiKey, snapshot endpoints use admin apiKey
    • streamText surfaces clarit metadata on finish part
  • Comparative recorder (downstream): 5-turn generateText AND streamText, fixed conversationId. Expect snapshotSaved:true on turn 1, snapshot list grows, fast-path on turn ≥ 2, flat new-token count, streamText surfaces clarit metadata.
  • After validation: revert server-side Option A patch, re-validate per-endpoint keys against restored auth.

This is the Engram-Vercel-Provider repo (separate from Clarit-AI/Engram); merge-gate from PR #95 does NOT apply.

…eam metadata

Close out the stateful path for the demo's production usage. Four changes:

1. Inject conversation_id (snake_case) into /v1/chat/completions body.
   The OpenAI-compatible base spreads providerOptions.<name> into the
   request body, stripping only its own schema keys. Replace
   providerOptions.clarit with a clean snake_case body on every standard
   generation and stream, plus the compatibility fallback. Engram keys
   WARM-tier state by conversation_id, so this seeds state for the next
   turn's restore on turn 1.

2. Fix off-by-one in the compatibility bridge snapshot lookup. The
   caller's turnNumber is the turn this generation will produce; the
   snapshot we want was saved at turnNumber - 1. /get_snapshot_info
   requires an exact turn (no "latest"), so the arithmetic happens
   there; the restore call now omits turn_number, letting the server
   resolve it to the latest snapshot. When turnNumber is 0 or undefined
   the bridge short-circuits to no-snapshot (no prior turn to restore
   from).

3. Per-endpoint API key routing on the snapshot client. /v1/tokenize
   takes the regular key; snapshot routes (save/list/get_info/restore/
   delete) take the admin key. Provider factory wires both. Aligns with
   Engram's intentional auth split and lets the temporary server-side
   Option A patch be reverted.

4. Stream wrapper now surfaces clarit metadata. The standard streaming
   path threads conversationId/turnNumber/branchName/rid and (when
   autoSaveSnapshot is set) the save outcome into the finish part's
   providerMetadata, so streamText sees {clarit:{...}} just like
   generateText does. wrapGenerateResultAsStream (used by restore-and-
   generate and the compatibility fast-path) also forwards
   providerMetadata on its finish chunk.
@Clarit-AI Clarit-AI added the Release Triggers an automatic GitHub Release and npm publish on merge label May 25, 2026
@kilo-code-bot

kilo-code-bot Bot commented May 25, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

This PR implements four targeted fixes for the stateful path. All changes are well-reasoned and the new tests provide good coverage.

Changes Reviewed

File Change Assessment
package.json Version bump 0.2.1 → 0.2.2 Correct
src/clarit-chat-model.ts conversation_id injection, turn-lookup fix, stream metadata threading Correct
src/clarit-provider.ts Per-endpoint auth wiring Correct
src/snapshots/snapshot-client.ts tokenizeApiKey support for /v1/tokenize Correct
test/clarit-provider.test.ts New tests for all four fixes Correct
test/snapshot-client.test.ts New tests for per-endpoint key routing Correct

Key Logic Verified

  1. prepareBaseCallOptions — correctly strips camelCase internal keys (autoSaveSnapshot, turnNumber, branchName) and injects only conversation_id into providerOptions.clarit for the base model. Applied consistently to doStandardGenerate, doStandardStream, and doCompatibilityFallback.

  2. Turn lookup off-by-onelookupTurn = turnNumber - 1 when turnNumber > 0 correctly targets the prior turn's snapshot. The restore call omits turn_number so the server resolves to latest.

  3. Per-endpoint authtokenizeApiKey is correctly used only for /v1/tokenize, while all snapshot endpoints continue using apiKey (admin key).

  4. Stream metadata — finish chunk correctly receives providerMetadata.clarit with rid, conversationId, turnNumber, branchName, and save outcome.

Test Coverage

New tests cover:

  • conversation_id injection on doGenerate and doStream
  • camelCase keys stripped from forwarded providerOptions.clarit
  • tokenizeApiKey used for /v1/tokenize, admin apiKey for snapshot endpoints
  • clarit metadata surfaced on finish stream part
Files Reviewed (6 files)
  • package.json
  • src/clarit-chat-model.ts
  • src/clarit-provider.ts
  • src/snapshots/snapshot-client.ts
  • test/clarit-provider.test.ts
  • test/snapshot-client.test.ts

Reviewed by minimax-m2.7 · 206,360 tokens

@Clarit-AI
Clarit-AI merged commit 624a569 into main May 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Release Triggers an automatic GitHub Release and npm publish on merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants