Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
459cdbc
QVAC-24251 feat[bc]: drop n_discarded from the llamacpp config schema
donriddo Aug 31, 2026
139867a
QVAC-24251 fix: parse every context-overflow wording the llm addon emits
donriddo Aug 31, 2026
f627488
QVAC-24251 refactor: drop the sliding-era tool-block resend from the …
donriddo Aug 31, 2026
b274754
QVAC-24251 test: cover the context boundary and prefill overflow in t…
donriddo Aug 31, 2026
aae991c
QVAC-24251 fix[bc]: fail the retired n_discarded closed on every inge…
donriddo Aug 31, 2026
7b008c8
QVAC-24251 feat[api]: carry cached and required context on ContextOve…
donriddo Aug 31, 2026
21ccd34
QVAC-24251 doc: correct the public stop reason in the KV-cache guide
donriddo Aug 31, 2026
77915ae
QVAC-24251 test: grow a real warm cache into the overflow guard in e2e
donriddo Aug 31, 2026
444aaea
QVAC-24251 fix: keep promptTokens unset for the retired short overflo…
donriddo Aug 31, 2026
8224ac2
QVAC-24251 chore: adopt @qvac/llm-llamacpp 0.48.0
donriddo Aug 31, 2026
00d004e
Merge branch 'main' into feat/QVAC-24251-sdk-drop-n-discarded
donriddo Sep 1, 2026
204c6dc
QVAC-24251 fix[bc]: reject the retired key at dispatch, before the re…
donriddo Sep 1, 2026
0939614
QVAC-24251 fix[bc]: exclude built-in types from the custom-plugin arm…
donriddo Sep 1, 2026
4502a53
QVAC-24251 fix: neutral required-only overflow message and honest ctx…
donriddo Sep 1, 2026
0f25495
QVAC-24251 test: prove the warm path and the boundary; surface cleanu…
donriddo Sep 1, 2026
4271825
QVAC-24251 chore: tighten comments and fix Python import order
donriddo Sep 1, 2026
d86b428
QVAC-24251 fix: keep overflow wording unit-neutral and coherent at eq…
donriddo Sep 1, 2026
122c4fb
QVAC-24251 test: narrow the union for mypy and harden dispatch and wa…
donriddo Sep 1, 2026
c02b42d
QVAC-24251 chore: trim new comments to two lines
donriddo Sep 1, 2026
bf05a30
QVAC-24251 fix: take the larger measure on multimodal overflow guards
donriddo Sep 1, 2026
3db9ba5
QVAC-24251 fix: accept the generated ModelType enum in load_model
donriddo Sep 1, 2026
676a3c7
QVAC-24251 test: widen the e2e budgets clear of the window
donriddo Sep 1, 2026
6a58374
QVAC-24251 chore: drop redundant strict() calls and guard the exclusi…
donriddo Sep 1, 2026
bac5e69
QVAC-24251 fix: floor the warm signature and neutralize the Python de…
donriddo Sep 1, 2026
1edea5b
QVAC-24251 fix: generate Python enums as value subclasses
donriddo Sep 1, 2026
7ce9389
Merge branch 'main' into feat/QVAC-24251-sdk-drop-n-discarded
donriddo Sep 1, 2026
74c4fbb
QVAC-24251 fix: keep the committed cache through a pre-mutation overflow
donriddo Sep 1, 2026
9879f02
QVAC-24251 test: retry the warm overflow before cleanup in e2e
donriddo Sep 1, 2026
2a8c5e3
QVAC-24251 chore: label defensive parser probes and refresh stale com…
donriddo Sep 1, 2026
faf569b
QVAC-24251 doc: note the parallel predict reservation and the release…
donriddo Sep 1, 2026
135630f
Merge branch 'main' into feat/QVAC-24251-sdk-drop-n-discarded
donriddo Sep 1, 2026
7858bf7
QVAC-24251 fix: preserve the committed cache through scheduler admiss…
donriddo Sep 1, 2026
c726b3e
QVAC-24251 chore: name the constructor extras param and flow each siz…
donriddo Sep 1, 2026
544b83a
QVAC-24251 doc: point the implementation table at the post-split paths
donriddo Sep 1, 2026
d68da41
QVAC-24251 feat[api]: make the sizes record the canonical ContextOver…
donriddo Sep 1, 2026
22ce793
QVAC-24251 fix: regenerate the Python client over the merged schema
donriddo Sep 1, 2026
0f2fbb9
QVAC-24251 fix: cover the batcher submit refusals and require the rea…
donriddo Sep 1, 2026
ce54ebc
QVAC-24251 fix: export the sizes record type and tighten the legacy o…
donriddo Sep 1, 2026
182adaa
QVAC-24251 doc: describe the current session layers and the parallel …
donriddo Sep 1, 2026
b265b2f
QVAC-24251 fix: honest units on the mtmd single-prompt guard; cover g…
donriddo Sep 1, 2026
e824d69
fix: match pre-mutation refusals on the transported message alone
donriddo Sep 1, 2026
cf720ee
doc: align kv-cache docs with conditional release and tighten comments
donriddo Sep 1, 2026
37d8666
QVAC-24251 test: pin the destructive rollback branch; fix stale doc c…
donriddo Sep 1, 2026
6080f68
QVAC-24251 fix: preserve the warm cache on a missing-attachment rejec…
donriddo Sep 1, 2026
326a928
QVAC-24251 mod: restore no-op .strict() calls and pre-existing commen…
donriddo Sep 1, 2026
feda854
QVAC-24251 fix: treat a present status code as authoritative in overf…
donriddo Sep 1, 2026
7c1a813
QVAC-24251 fix: reject non-string status codes in overflow detection
donriddo Sep 1, 2026
891c91f
QVAC-24251 fix: drop the added strictness and follow the retired-key …
donriddo Sep 1, 2026
002b550
QVAC-24251 fix: roll back a cache the failing turn itself primed
donriddo Sep 1, 2026
559ff35
QVAC-24251 chore: drop dead code and stale test descriptions
donriddo Sep 1, 2026
5766f06
Merge remote-tracking branch 'upstream/main' into feat/QVAC-24251-sdk…
donriddo Sep 1, 2026
2ce478e
QVAC-24251 doc: restore pre-existing comment content the comments pas…
donriddo Sep 1, 2026
52735ef
QVAC-24251 fix: return the load-model request union to its previous s…
donriddo Sep 1, 2026
8739f72
QVAC-24251 test: pin stripping and the auto-path fresh prime; restore…
donriddo Sep 1, 2026
fbe5d49
Merge remote-tracking branch 'upstream/main' into feat/QVAC-24251-sdk…
donriddo Sep 1, 2026
ccdc0fd
QVAC-24251 feat[api]: type batch capacity refusals as overflows; pres…
donriddo Sep 2, 2026
58475d0
QVAC-24251 fix: resolve error reconstructors from own keys only
donriddo Sep 2, 2026
69b7294
QVAC-24251 doc: state the true rationale on the overload and factory …
donriddo Sep 2, 2026
5643433
QVAC-24251 doc: reword two comments to state behavior, not process
donriddo Sep 2, 2026
a6a6039
Merge branch 'main' into feat/QVAC-24251-sdk-drop-n-discarded
iancris Sep 2, 2026
87e66e1
Merge branch 'main' into feat/QVAC-24251-sdk-drop-n-discarded
iancris Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 46 additions & 26 deletions .cursor/rules/sdk/docs/kv-cache-system.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ Named string-key caches are not inferred from their directory names and remain c

| File | Purpose |
|------|---------|
| `server/bare/plugins/llamacpp-completion/ops/kv-cache-session.ts` | **`KvCacheSession` β€” single owner of the three KV-cache bookkeeping layers** (on-disk `.bin`, `initializedCaches`, `cachedMessageCounts`). Exposes `beginTurn` / `commitTurn` / `rollback` / `dropStaleSavedCount` plus the module-level `deleteKvCacheState(...)` administrative API. (QVAC-18182). |
| `server/bare/plugins/llamacpp-completion/ops/completion-stream.ts` | Completion handler. Calls `session.beginTurn(...)`, registers `scope.defer(() => session.rollback(turn))` once, and calls `session.commitTurn(...)` on the happy path (which suppresses the deferred rollback). No direct references to the three layers. |
| `server/bare/plugins/llamacpp-completion/ops/kv-cache-state.ts` | Pure `decideCachedHistorySlice(...)` helper used by the session β€” slice decision for the next addon call. No state. |
| `server/bare/ops/kv-cache-retention.ts` | Plans idle and quota-based auto-cache evictions while excluding active turn paths. |
| `server/bare/ops/kv-cache-utils.ts` | Path / hash / fs utilities: `getCacheFilePath`, `generateConfigHash`, `findMatchingCache`, `getCurrentCacheInfo`, `renameCacheFile`, `deleteCache`. No in-memory state. |
| `server/bare/plugins/llamacpp-completion/ops/cache-logger.ts` | Debug logging for cache operations |
| `server/rpc/handlers/delete-cache.ts` | `handleDeleteCache` RPC entry point. Delegates to `deleteKvCacheState(...)` β€” zero direct references to the three layers. |
| `server/utils/cache.ts` | `getKVCacheDir()` base directory |
| `client/api/delete-cache.ts` | Client-side delete cache API |
| `packages/inference/src/plugins/builtin/llamacpp-completion/ops/kv-cache-session.ts` | **`KvCacheSession` β€” single owner of the KV-cache bookkeeping layers** (on-disk `.bin`, `initializedCaches`, `cachedPrefixes`, per-path write locks/active refs, auto-cache markers). Exposes `beginTurn` / `commitTurn` / `rollback` / `releaseTurn` (non-destructive: a thrown overflow, an enumerated pre-mutation refusal, or a pre-addon missing-attachment rejection never persists the turn, so the committed cache stays valid; a cache the failing turn itself primed rolls back instead) / `dropStaleSavedCount` plus the module-level `deleteKvCacheState(...)` administrative API. (QVAC-18182). |
| `packages/inference/src/plugins/builtin/llamacpp-completion/ops/completion-stream.ts` | Completion handler. Calls `session.beginTurn(...)`, registers one deferred cleanup (rollback, or the non-destructive `releaseTurn` on a thrown addon overflow, an enumerated pre-mutation refusal, or a pre-addon missing-attachment rejection), and calls `session.commitTurn(...)` on the happy path (which suppresses it). No direct references to the session's layers. |
| `packages/inference/src/plugins/builtin/llamacpp-completion/ops/kv-cache-state.ts` | Pure `decideCachedHistorySlice(...)` helper used by the session β€” slice decision for the next addon call. No state. |
| `packages/inference/src/plugins/ops/kv-cache-retention.ts` | Plans idle and quota-based auto-cache evictions while excluding active turn paths. |
| `packages/inference/src/plugins/ops/kv-cache-utils.ts` | Path / hash / fs utilities: `getCacheFilePath`, `generateConfigHash`, `findMatchingCache`, `getCurrentCacheInfo`, `renameCacheFile`, `deleteCache`. No in-memory state. |
| `packages/inference/src/plugins/builtin/llamacpp-completion/ops/cache-logger.ts` | Debug logging for cache operations |
| `packages/inference/src/handlers/delete-cache.ts` | `handleDeleteCache` RPC entry point. Delegates to `deleteKvCacheState(...)` β€” zero direct references to the session's layers. |
| `packages/inference/src/utils/cache/paths.ts` | `getKVCacheDir()` base directory |
| `packages/sdk/src/client/api/delete-cache.ts` | Client-side delete cache API |

## Key Behaviors

Expand All @@ -129,21 +129,23 @@ Before 0.11.0 the completion handler coordinated three independent bookkeeping l

Three near-identical cleanup blocks in `completion-stream.ts` had to touch all three on every cancel / zero-token / rename-failed / tool-call exit. Any one of those blocks forgetting a layer produced the drift bugs the pitch documents (QVAC-17780 family).

**0.11.0 collapses this into `KvCacheSession`**, the **single mutation point** for the three layers. The handler's loop is now:
**0.11.0 collapses this into `KvCacheSession`**, the **single mutation point** for the bookkeeping layers (five today β€” see the table above). The handler's loop is now:

```typescript
const session = createKvCacheSession(modelId);
const turn = await session.beginTurn({ ... }); // primes cache if missing, returns handle
scope.defer(() => session.rollback(turn)); // ONE cleanup hook for every exit path
let preserveCacheOnUnwind = false; // set on a recognised pre-addon or pre-mutation failure
scope.defer(() => // ONE cleanup hook for every exit path
preserveCacheOnUnwind ? session.releaseTurn(turn) : session.rollback(turn));
// ... run model ...
if (shouldCommit) await session.commitTurn(turn, ...); // suppresses the deferred rollback
if (shouldCommit) await session.commitTurn(turn, ...); // suppresses the deferred cleanup
```

`commitTurn` flips an internal flag on the turn handle; `rollback` reads the flag and short-circuits. The happy path commits and the deferred rollback becomes a no-op. Every other exit path (cancel, zero-token, addon error, rename failure, tool-call turn) lets `scope[Symbol.asyncDispose]` run the deferred rollback, which atomically unlinks the `.bin` file, deletes the `initializedCaches` entry, and forgets the `cachedMessageCounts` entry.
`commitTurn` flips an internal flag on the turn handle; `rollback` reads the flag and short-circuits. The happy path commits and the deferred rollback becomes a no-op. Every other exit path (cancel, zero-token, addon error, rename failure, tool-call turn) lets `scope[Symbol.asyncDispose]` run the deferred cleanup: `rollback` unlinks the `.bin` file and clears the `initializedCaches`/`cachedPrefixes` entries, while a thrown addon overflow, an enumerated pre-mutation refusal (scheduler submit guards, generationParams validation), or a pre-addon missing-attachment rejection takes `releaseTurn`, which frees locks and refs but keeps the committed file and prefix valid for a retry β€” unless the failing turn itself primed the cache, in which case there is nothing committed to keep and it rolls back.

**Late-commit vs cancel is intentional, not a race.** A commit only proceeds past its abort re-check for a turn that fully generated and whose file passed `verifySaveAndRecord`. If a cancel lands during the async commit (after that check, during rename/verify), the commit finishes: a **complete, verified** turn is persisted while the operation reports cancelled. This is by design β€” the persisted cache matches the tokens the client already received, and committing fully-generated verified work beats discarding it. A strict "cancel wins" rollback here would need target-aware cleanup and risks deleting valid completed state, so it is not done.

The maps that backed `clearCacheRegistry` and `cachedMessageCounts` are **private to `kv-cache-session.ts`**. No other module reads or writes them.
The maps behind the session (`initializedCaches`, `cachedPrefixes`, locks and refs) are **private to `kv-cache-session.ts`**. No other module reads or writes them.

### Cache Initialization (primeIfMissing) and Addon Non-Transactional Save

Expand Down Expand Up @@ -197,9 +199,9 @@ await deleteCache({ kvCacheKey: "session-a" }); // remove session
await deleteCache({ kvCacheKey: "session-a", modelId: "..." }); // remove only one model's session-a cache
```

`handleDeleteCache` delegates to `deleteKvCacheState(...)` β€” a module-level export from `kv-cache-session.ts` that owns the same three layers. It removes the matching on-disk directory tree, prefix-cleans `cachedMessageCounts` against the removed path, and scope-clears `initializedCaches` by `(kvCacheKey[, modelId])`. The RPC handler itself has **zero direct references** to `fsPromises.unlink`, the in-memory `initializedCaches` set, or the `cachedMessageCounts` map.
`handleDeleteCache` delegates to `deleteKvCacheState(...)` β€” a module-level export from `kv-cache-session.ts` that owns the same layers. It removes the matching on-disk directory tree and scope-clears the `initializedCaches`/`cachedPrefixes` entries by `(kvCacheKey[, modelId])`. The RPC handler itself has **zero direct references** to `fsPromises.unlink` or the session's in-memory maps.

See `schemas/delete-cache.ts` for the request schema.
See `schemas/model-ops.ts` for the request schema.

## Cache Persistence

Expand All @@ -210,23 +212,41 @@ See `schemas/delete-cache.ts` for the request schema.

## Context Overflow with KV Cache

When using KV Cache with sliding window (`n_discarded`), the context doesn't overflow because:
1. Cache stores the compressed KV state, not raw tokens
2. Sliding window discards oldest tokens when context fills
3. **First message (system prompt + tools) is NEVER removed** β€” protected from `n_discarded`
4. Only the last message is appended to the cached context

**Required config for long conversations:**
Nothing is evicted from the cache to make room. A conversation that grows past
`ctx_size` runs out of context, and there are two ways to see it:

1. A prompt that does not fit is refused before any decoding, with a typed `ContextOverflowError` carrying the parsed sizes.
2. A generation that fills the window stops and reports `stopReason: "length"`, keeping the tokens it already produced.

The second one is a normal completion, not an error. `stopReason` alone does not
distinguish a full context from a positive `predict` cutoff β€” the SDK maps both
to `"length"` (with `predict: -1` there is no cutoff, so `"length"` can only
mean the boundary). With `parallel >= 2` the scheduler treats a positive
`predict` as a reservation: a budget that cannot fit the slot is rejected at
admission instead of stopping at the boundary. Those admission refusals also
surface as `ContextOverflowError` β€” `requiredTokens` carries the cache-plus-
prompt total (plus the reservation on the `n_predict` form) and `ctxSize` the
per-slot cap β€” recognised by wording, since the transport strips the addon's
status; giving them a real `ContextOverflow` status addon-side is a recorded
follow-up. Use `predict: -1`/`-2` or a budget within the slot to avoid the
reservation refusal.

**Config for long conversations:** size `ctx_size` for the whole conversation you
intend to hold. With `parallel > 1` the window is split across slots, so each
request's effective ceiling β€” and the `ctxSize` an overflow error reports β€” is
`ctx_size / parallel`, not the configured total.

```typescript
const modelId = await loadModel({
modelSrc: MODEL,
modelType: "llm",
modelConfig: { ctx_size: 2048, n_discarded: 512 },
modelConfig: { ctx_size: 8192 },
});
```

**Note:** `n_discarded` only works during token generation, not during prefill. Ensure your initial prompt fits in `ctx_size`.
**Note:** the sliding-window option `n_discarded` was removed. `loadModel()`
rejects it at schema validation; only a direct addon caller sees it fail model
load as an unknown option.

## Debug Logging

Expand All @@ -244,7 +264,7 @@ KV Cache works with MCP tools. Complete canonical tool definitions are hashed: o
| Issue | Cause | Fix |
|-------|-------|-----|
| Cache not reused (full history sent, slow TTFT) | Different system prompt or tools between requests | Ensure consistent system prompt and tools for same cache key |
| Context overflow at prefill | `n_discarded` not configured | Add `n_discarded` to `modelConfig` |
| Context overflow at prefill | Conversation outgrew `ctx_size`; nothing is evicted to make room | Raise `ctx_size`, or start a new cache key for a fresh conversation |
| Tools changed mid-session | Expected behavior | New cache created automatically; old cache preserved |

## See Also
Expand Down
4 changes: 2 additions & 2 deletions packages/inference/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
"@qvac/diffusion-cpp": "^0.21.0",
"@qvac/embed-llamacpp": "^0.36.0",
"@qvac/langdetect-text": "^0.1.2",
"@qvac/llm-llamacpp": "^0.47.0",
"@qvac/llm-llamacpp": "^0.48.0",
"@qvac/ocr-ggml": "^0.20.0",
"@qvac/translation-nmtcpp": "^0.12.0",
"@qvac/tts-ggml": "^0.8.0",
Expand Down Expand Up @@ -254,7 +254,7 @@
"@qvac/diffusion-cpp": "^0.21.0",
"@qvac/embed-llamacpp": "^0.36.0",
"@qvac/langdetect-text": "^0.1.2",
"@qvac/llm-llamacpp": "^0.47.0",
"@qvac/llm-llamacpp": "^0.48.0",
"@qvac/ocr-ggml": "^0.20.0",
"@qvac/translation-nmtcpp": "^0.12.0",
"@qvac/tts-ggml": "^0.8.0",
Expand Down
102 changes: 85 additions & 17 deletions packages/inference/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,49 +270,117 @@ export class CompletionFailedError extends QvacErrorBase {
}
}

/** The overflow sizes as one record; fields admit explicit `undefined` so a parser result assigns directly. */
export type ContextOverflowErrorSizes = {
promptTokens?: number | undefined
cachedTokens?: number | undefined
requiredTokens?: number | undefined
ctxSize?: number | undefined
}

function normalizeContextOverflowArgs(
sizesOrPromptTokens?: ContextOverflowErrorSizes | number,
modelIdOrCtxSize?: string | number,
causeOrModelId?: unknown,
cause?: unknown,
extraSizes?: { cachedTokens?: number | undefined; requiredTokens?: number | undefined }
): ContextOverflowErrorSizes & { modelId?: string | undefined; cause?: unknown } {
if (typeof sizesOrPromptTokens === 'object' && sizesOrPromptTokens !== null) {
return {
...sizesOrPromptTokens,
modelId: modelIdOrCtxSize as string | undefined,
cause: causeOrModelId
}
}
// Only the two supported extra fields β€” a spread would let a wider,
// structurally assignable extras object override the positional args.
return {
promptTokens: sizesOrPromptTokens,
ctxSize: modelIdOrCtxSize as number | undefined,
modelId: causeOrModelId as string | undefined,
cause,
cachedTokens: extraSizes?.cachedTokens,
requiredTokens: extraSizes?.requiredTokens
}
}

/**
* Thrown when the prompt exceeds the loaded model's configured context
* window β€” distinct from a generic `CompletionFailedError` so consumers
* Thrown when a request no longer fits the model's effective context
* capacity β€” distinct from a generic `CompletionFailedError` so consumers
* can drive UX (truncate, summarize, or surface a "increase ctx_size /
* start a new thread" CTA) instead of treating it as an opaque failure.
*
* Carries the addon-reported prompt size and the model's context window
* when the addon's error message includes them (the C++ overflow paths
* in `TextLlmContext.cpp` and `MtmdLlmContext.cpp` format both numbers
* into the message; the bare `processPromptImpl: context overflow`
* fallback in `LlamaModel.cpp` carries neither β€” both fields are
* therefore optional). `modelId` is supplied by the handler that wraps
* the addon error.
* All size fields are optional: they carry whatever the addon guard
* reported (a cold prompt, a warm cached-plus-prompt split, or a bare
* overflow with no numbers). `modelId` is supplied by the handler that
* wraps the addon error.
*
* Serializes its typed fields (`toErrorResponseFields`) so a receiver can
* rebuild it after the error crosses a serialization boundary (an RPC
* response).
*/
export class ContextOverflowError extends QvacErrorBase {
/** The prompt alone, in tokens; unset when the source reported KV cells. */
readonly promptTokens?: number
/** Cached conversation on a warm-cache overflow, in `ctxSize` units. */
readonly cachedTokens?: number
/** Total the failing guard reported, in `ctxSize` units; can equal the window (`>=` triggers). */
readonly requiredTokens?: number
/** Effective per-request ceiling: `ctx_size` split across slots at `parallel > 1`. */
readonly ctxSize?: number
readonly modelId?: string

constructor(promptTokens?: number, ctxSize?: number, modelId?: string, cause?: unknown) {
/** Canonical form: the parsed sizes as one record. */
// lunte-disable-next-line constructor-super -- overload declaration, no body; the implementation calls super
constructor(contextSizes: ContextOverflowErrorSizes, modelId?: string, cause?: unknown)
/** @deprecated Kept for external consumers of the published package; in-repo callers use the record form. */
// lunte-disable-next-line constructor-super -- overload declaration, no body; the implementation calls super
constructor(
promptTokens?: number,
ctxSize?: number,
modelId?: string,
cause?: unknown,
extraSizes?: { cachedTokens?: number | undefined; requiredTokens?: number | undefined }
)
constructor(
sizesOrPromptTokens?: ContextOverflowErrorSizes | number,
modelIdOrCtxSize?: string | number,
causeOrModelId?: unknown,
cause?: unknown,
extraSizes?: { cachedTokens?: number | undefined; requiredTokens?: number | undefined }
) {
const n = normalizeContextOverflowArgs(
sizesOrPromptTokens,
modelIdOrCtxSize,
causeOrModelId,
cause,
extraSizes
)
super(
createErrorOptions(
ERROR_CODES.CONTEXT_OVERFLOW,
[
promptTokens !== undefined ? String(promptTokens) : '',
ctxSize !== undefined ? String(ctxSize) : '',
modelId ?? ''
n.promptTokens !== undefined ? String(n.promptTokens) : '',
n.ctxSize !== undefined ? String(n.ctxSize) : '',
n.modelId ?? '',
n.cachedTokens !== undefined ? String(n.cachedTokens) : '',
n.requiredTokens !== undefined ? String(n.requiredTokens) : ''
],
cause
n.cause
)
)
if (promptTokens !== undefined) this.promptTokens = promptTokens
if (ctxSize !== undefined) this.ctxSize = ctxSize
if (modelId !== undefined) this.modelId = modelId
if (n.promptTokens !== undefined) this.promptTokens = n.promptTokens
if (n.ctxSize !== undefined) this.ctxSize = n.ctxSize
if (n.modelId !== undefined) this.modelId = n.modelId
if (n.cachedTokens !== undefined) this.cachedTokens = n.cachedTokens
if (n.requiredTokens !== undefined) this.requiredTokens = n.requiredTokens
}

toErrorResponseFields(): Record<string, unknown> {
return {
...(this.promptTokens !== undefined && { promptTokens: this.promptTokens }),
...(this.cachedTokens !== undefined && { cachedTokens: this.cachedTokens }),
...(this.requiredTokens !== undefined && { requiredTokens: this.requiredTokens }),
...(this.ctxSize !== undefined && { ctxSize: this.ctxSize }),
...(this.modelId !== undefined && { modelId: this.modelId })
}
Expand Down
Loading
Loading