Slice/m2.1#348
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Real providers from appSettingsStore are now the primary lookup source; the temporary stub registry stays as fallback until Slice 2.7 removes it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
429 is special-cased before the generic 4xx rule so it stays retryable; parseRetryAfter handles seconds and HTTP-date values. retryAfterMs lives on the classifier return object only — CallRetryError is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Provider retry attempts now wait classified.retryAfterMs (from a Retry-After header) or exponential backoff (500ms base, 30s cap) between attempts. The delay is abortable — aborting mid-backoff resolves the promise with {status:'aborted'} immediately. Parse retries are unaffected. Tests for both new timing paths added; existing provider-retry tests converted to fake timers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wraps generateText/streamText so every provider call carries maxRetries:0 (callWithRetry is the sole retry authority), SDK-native timeout config, and the caller's abort signal. mapCallError distinguishes APICallError (rethrow for classifyProviderError), internal SDK timeout (→ ProviderTimeoutError), and genuine user cancel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Promotes the CallRetryError→PipelineError mapper from a test-local function into lib/pipeline/call-error.ts, re-exported from the pipeline barrel. lib/ai stays free of the upward PipelineError dependency; fault-scenarios now imports via public barrels only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Once an action imported AGENT_IDS from @/lib/ai, vitest.setup.ts's registerAllDomains pulled the whole @/lib/ai barrel — the 'ai' SDK plus transport/fetch and model — into every unit test's setup graph, loading those modules before the test files' vi.mocks registered and silently breaking them. AGENT_IDS is config data that indexes app_settings.assignments, so lib/db is its proper home; lib/ai re-exports it so its public surface is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Real provider keys were never fed to the redaction comparator (only the stub registry was), so a configured OAI-compat call leaked its raw Authorization key into the diagnostics buffer; app_settings hydrate now syncs the comparator from providers[] on every (re)hydrate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
setHttpCallKnownSecretValues replaces the whole comparator and app_settings hydrate is the other writer, so registerStubProvider() overwrote it with only the stub key and dropped a configured provider's real key; the stub sync now merges the configured keys so a real API key can never be evicted from redaction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An unbounded Retry-After header (e.g. 3600s) made callWithRetry sleep for the full duration, bypassing BACKOFF_CAP_MS and stalling the phase; the honored delay is now capped at the same ceiling as the exponential fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
opts is now the SDK's own generateText/streamText options type (Parameters<typeof ...>), so timeout (TimeoutConfiguration) and the output schema flow through with no hand-rolled TimeoutConfig or narrow opts object; the proxies just force maxRetries:0 and pass through, returning the full SDK result. Error classification is consolidated in classifyProviderError (dropped the proxy-level mapCallError + .text extraction), which also resolves the prior streamProviderCall asymmetry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dev smoke phase now resolves the quick-wired narrative model and makes a real streamed call against the user's endpoint (the only real-generation path until 2.7), surfacing the reply as the entry content and landing a redacted streamed call in httpCallSink; it falls back to the stub when no provider is configured so the smoke and its tests still run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (7)
📝 WalkthroughWalkthroughThis PR implements a complete provider abstraction system enabling users to configure and use OpenAI-compatible AI providers. It introduces agent ID registry, model resolution logic, provider mutations, catalog fetching, retry/backoff handling with Retry-After support, secret redaction, UI components for provider setup, and deep-linked settings routing. All layers are comprehensively tested and documented. ChangesProvider Configuration System
🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces AI provider configuration and model routing. It adds an AI configuration banner on the landing page when no providers are configured, a provider setup form in settings to configure an OpenAI-compatible provider, and updates the settings route to support deep linking to specific tabs. It also implements model resolution, exponential backoff with Retry-After support, and API key redaction in diagnostics. The review feedback highlights several important improvements: using React effects to properly sync asynchronous store values and route parameters in the UI, using unsaved input values when fetching the model catalog, conditionally omitting the Authorization header for local providers that do not require an API key, and performing case-insensitive header lookups for retry-after.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
The /models catalog fetch hand-rolled an unconditional Authorization header, sending a bare `Bearer ` for keyless local endpoints (LM Studio, llama.cpp) where createOpenAICompatible already omits it — and that fetch is the first call such a setup makes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (6)
components/compounds/provider-setup-form.tsx (1)
169-175: 🗄️ Data Integrity & Integration | ⚡ Quick winMake custom model insertion idempotent to avoid duplicate persisted IDs.
At Line 174, appending directly can store repeated
customModelIdswhen the same model is added multiple times.Suggested refactor
await updateProvider( provider.id, - { customModelIds: [...(provider.customModelIds ?? []), ref.modelId] }, + { + customModelIds: Array.from( + new Set([...(provider.customModelIds ?? []), ref.modelId]), + ), + }, { db }, )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/compounds/provider-setup-form.tsx` around lines 169 - 175, The onAddCustom handler currently appends ref.modelId into provider.customModelIds and can create duplicates; update the logic in onAddCustom to first read provider.customModelIds (via provider.customModelIds) and only add ref.modelId if it isn't already present (e.g., check includes or use a Set) before calling updateProvider(provider.id, { customModelIds: ... }, { db }) so persisted customModelIds remain idempotent.app/settings/index.tsx (1)
51-53: 🎯 Functional Correctness | ⚡ Quick winSync selected tab with query param updates, not just initial mount.
At Line 53, the
useStateinitializer runs once, so latertabquery changes won’t updateselectedTab.Suggested refactor
-import { useState } from 'react' +import { useEffect, useState } from 'react' @@ - const { tab } = useLocalSearchParams<{ tab?: string }>() - const initialTab = SETTINGS_TAB_IDS.includes(tab as SettingsTabId) ? (tab as SettingsTabId) : null - const [selectedTab, setSelectedTab] = useState<SettingsTabId | null>(initialTab) + const { tab } = useLocalSearchParams<{ tab?: string | string[] }>() + const tabParam = Array.isArray(tab) ? tab[0] : tab + const resolvedTab = SETTINGS_TAB_IDS.find((id) => id === tabParam) ?? null + const [selectedTab, setSelectedTab] = useState<SettingsTabId | null>(resolvedTab) + + useEffect(() => { + setSelectedTab(resolvedTab) + }, [resolvedTab])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/settings/index.tsx` around lines 51 - 53, The selectedTab state only uses the initialTab computed once, so subsequent changes to the URL query param `tab` (from useLocalSearchParams) won’t update it; add a useEffect that watches `tab` (or `initialTab`) and calls setSelectedTab with the computed SettingsTabId (or null) whenever `tab` changes to keep selectedTab in sync with the query param; reference the existing identifiers useLocalSearchParams, initialTab, selectedTab, and setSelectedTab when implementing this effect.lib/ai/resolve-model.test.ts (1)
81-102: 📐 Maintainability & Code Quality | ⚡ Quick winAdd a regression test for
wizard-assistignoringstoryModelsoverrides.Current tests validate override short-circuit generally, but don’t pin the documented exception for
wizard-assist. A focused case here would prevent contract drift.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/ai/resolve-model.test.ts` around lines 81 - 102, Add a regression test in resolve-model.test.ts that specifically asserts that resolveModel('wizard-assist', cfg) ignores any entry in cfg.storyModels (e.g., storyModels: { 'wizard-assist': 'override-model' }) — create a ResolveModelConfig mirroring the other tests (use base/defaultProviderId as needed) and assert the result does NOT short-circuit to the override and instead follows the normal wizard-assist resolution path (i.e., the returned providerId/modelId should match the existing base behavior for wizard-assist rather than 'override-model'); place this alongside the other tests using the same expect/shape as resolveModel(...) assertions.lib/ai/providers.test.ts (1)
15-25: 📐 Maintainability & Code Quality | ⚡ Quick winAdd regression coverage for the required endpoint guard.
The suite currently doesn’t assert the new endpoint requirement from
createProviderModel(Line 45 inlib/ai/providers.ts). Adding this test prevents silent regressions.Suggested test addition
describe('createProviderModel · openai-compatible', () => { + it('throws when endpoint is blank/whitespace', () => { + expect(() => + createProviderModel({ ...oai, endpoint: ' ' }, 'my-model'), + ).toThrow(/requires an endpoint/) + }) + it('builds a language model for an openai-compatible provider', () => { const model = createProviderModel(oai, 'my-model', 'action-1') expect(model).toBeDefined() })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/ai/providers.test.ts` around lines 15 - 25, The test suite is missing coverage for the new required endpoint guard in createProviderModel; add a test that copies the existing oai test fixture but removes or clears its endpoint (e.g., const broken = { ...oai, endpoint: undefined } or delete broken.endpoint) and assert that calling createProviderModel(broken, 'm', 'action-1') throws; place this alongside the existing openai-compatible tests so the provider endpoint requirement is enforced and prevents regressions.lib/ai/model.test.ts (1)
89-102: 📐 Maintainability & Code Quality | ⚡ Quick winAdd an explicit precedence test for ID collisions (configured vs temporary).
This file validates configured resolution and fallback separately, but not the key new rule: configured provider should win when both sources contain the same
providerId.Suggested test addition
it('resolves a real openai-compatible provider from app settings', () => { @@ const model = getModel('prov-real', 'my-model') expect(model).toBeDefined() }) + + it('prefers configured provider over temporary provider when ids collide', () => { + appSettings.providers = [ + { + id: 'shared-id', + type: 'openai-compatible', + displayName: 'Configured', + apiKey: 'sk-real', + endpoint: 'http://localhost:1234/v1', + favoriteModelIds: [], + }, + ] + setTemporaryProvidersForTests([ + { + id: 'shared-id', + type: 'anthropic', + displayName: 'Temporary', + apiKey: 'sk-temp', + favoriteModelIds: ['claude-3-haiku-20240307'], + }, + ]) + + expect(() => getModel('shared-id', 'my-model')).not.toThrow() + })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/ai/model.test.ts` around lines 89 - 102, Add a unit test to assert configured providers take precedence over temporary providers when IDs collide: create appSettings.providers with an entry id 'prov-collide' (type 'openai-compatible', apiKey 'sk-config', endpoint etc.), also ensure the temporary/ephemeral provider store (the same source getModel consults for temp providers) contains a provider with the same id 'prov-collide' but different metadata (e.g. apiKey 'sk-temp'); call getModel('prov-collide', 'any-model') and assert the returned model corresponds to the configured provider (inspect provider id/type or apiKey) rather than the temporary one; reference getModel and appSettings.providers to locate where to add the test.lib/ai/catalog.test.ts (1)
54-58: 📐 Maintainability & Code Quality | ⚡ Quick winExtend endpoint-validation tests to include whitespace-only values.
The current test catches
undefinedendpoints, but not' '. Add a whitespace case to protect the normalization contract.Suggested test addition
it('throws a clear error when the endpoint is missing', async () => { await expect(fetchModelCatalog({ ...provider, endpoint: undefined })).rejects.toThrow( /endpoint/, ) }) + + it('throws a clear error when the endpoint is whitespace', async () => { + await expect(fetchModelCatalog({ ...provider, endpoint: ' ' })).rejects.toThrow( + /endpoint/, + ) + })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/ai/catalog.test.ts` around lines 54 - 58, Add a test case in lib/ai/catalog.test.ts that calls fetchModelCatalog with provider where endpoint is a whitespace-only string (e.g., ' ') and assert it rejects with an error matching /endpoint/; specifically, mirror the existing test that uses fetchModelCatalog({ ...provider, endpoint: undefined }) but pass endpoint: ' ' to ensure endpoint normalization rejects whitespace-only values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@components/compounds/provider-setup-form.tsx`:
- Around line 86-95: The wired success flag is not cleared when the selection
changes or when a quick-wire attempt fails, leaving stale success UI; update the
onQuickWire error path to call setWired(false) and ensure the selection-change
flow/reset for picked also clears wired (e.g., in the handler that sets picked
or a useEffect watching picked call setWired(false)). Reference functions/vars:
onQuickWire, quickWireModel, picked, wired, setWired so the wired state is reset
on failure and whenever picked changes.
In `@lib/actions/settings/providers.ts`:
- Around line 44-49: The update currently silently no-ops if no provider with
the given id exists; before calling providerInstanceSchema.parse and mapping,
check for existence by using the current providers array returned by
appSettingsStore.getAppSettings().providers (e.g., const current =
appSettingsStore.getAppSettings().providers; const existing = current.find(p =>
p.id === id)); if existing is undefined throw an error (or return a rejected
Promise) indicating the provider id was not found, otherwise proceed to build
next by mapping and call providerInstanceSchema.parse and persistConfig(ctx, {
providers: next }).
- Around line 26-28: After updating appSettings in save flow, the call to
rehydrateAppSettings(ctx.db) (invoked after await
ctx.db.update(...).where(eq(appSettings.id, APP_SETTINGS_SINGLETON_ID))) can
return a failure status that is currently ignored; change the code to capture
the result of rehydrateAppSettings and if it indicates failure (e.g., status ===
'config-corrupt' or similar error result) propagate that by throwing or
returning an error so the save action does not resolve successfully when
hydration failed—locate the save function around the ctx.db.update call and add
handling for rehydrateAppSettings' return value to surface the failure.
In `@lib/ai/providers.ts`:
- Around line 45-52: The provider endpoint isn’t normalized; update
createProviderModel and fetchModelCatalog to trim provider.endpoint once,
validate the trimmed value (e.g., ensure trimmed.length > 0) and use the trimmed
value for subsequent logic (instead of the raw provider.endpoint) — for example,
compute const endpoint = (provider.endpoint || '').trim() at the top of
createProviderModel and fetchModelCatalog, throw the existing error if endpoint
is empty, and pass endpoint into createOpenAICompatible / any URL construction
or fetch logic.
In `@lib/ai/resolve-model.ts`:
- Around line 60-66: The current override branch (`const override =
config.storyModels?.[target]`) applies storyModels for any ResolveTarget, which
lets disallowed targets like "wizard-assist" bypass normal resolution; restrict
this by only honoring overrides for the documented story-model targets: add an
allowlist (e.g., ALLOWED_STORY_MODEL_TARGETS) and check `if
(!ALLOWED_STORY_MODEL_TARGETS.includes(target))` before using `override`; keep
the rest of the logic (finding provider via `config.providers.find(p => p.id ===
config.defaultProviderId)` and returning the provider/model) unchanged so
disallowed targets ignore `storyModels` entries.
In `@lib/pipeline/call-error.ts`:
- Line 10: The provider error mapping in lib/pipeline/call-error.ts currently
drops empty-string details because it uses a truthy check; update the mapping
that builds the provider object (the line producing ? { kind: 'provider',
reason: e.reason, ...(e.detail ? { detail: e.detail } : {}) }) to use an
explicit undefined check (e.detail !== undefined) so that detail: '' is
preserved and only undefined is omitted.
---
Nitpick comments:
In `@app/settings/index.tsx`:
- Around line 51-53: The selectedTab state only uses the initialTab computed
once, so subsequent changes to the URL query param `tab` (from
useLocalSearchParams) won’t update it; add a useEffect that watches `tab` (or
`initialTab`) and calls setSelectedTab with the computed SettingsTabId (or null)
whenever `tab` changes to keep selectedTab in sync with the query param;
reference the existing identifiers useLocalSearchParams, initialTab,
selectedTab, and setSelectedTab when implementing this effect.
In `@components/compounds/provider-setup-form.tsx`:
- Around line 169-175: The onAddCustom handler currently appends ref.modelId
into provider.customModelIds and can create duplicates; update the logic in
onAddCustom to first read provider.customModelIds (via provider.customModelIds)
and only add ref.modelId if it isn't already present (e.g., check includes or
use a Set) before calling updateProvider(provider.id, { customModelIds: ... }, {
db }) so persisted customModelIds remain idempotent.
In `@lib/ai/catalog.test.ts`:
- Around line 54-58: Add a test case in lib/ai/catalog.test.ts that calls
fetchModelCatalog with provider where endpoint is a whitespace-only string
(e.g., ' ') and assert it rejects with an error matching /endpoint/;
specifically, mirror the existing test that uses fetchModelCatalog({
...provider, endpoint: undefined }) but pass endpoint: ' ' to ensure endpoint
normalization rejects whitespace-only values.
In `@lib/ai/model.test.ts`:
- Around line 89-102: Add a unit test to assert configured providers take
precedence over temporary providers when IDs collide: create
appSettings.providers with an entry id 'prov-collide' (type 'openai-compatible',
apiKey 'sk-config', endpoint etc.), also ensure the temporary/ephemeral provider
store (the same source getModel consults for temp providers) contains a provider
with the same id 'prov-collide' but different metadata (e.g. apiKey 'sk-temp');
call getModel('prov-collide', 'any-model') and assert the returned model
corresponds to the configured provider (inspect provider id/type or apiKey)
rather than the temporary one; reference getModel and appSettings.providers to
locate where to add the test.
In `@lib/ai/providers.test.ts`:
- Around line 15-25: The test suite is missing coverage for the new required
endpoint guard in createProviderModel; add a test that copies the existing oai
test fixture but removes or clears its endpoint (e.g., const broken = { ...oai,
endpoint: undefined } or delete broken.endpoint) and assert that calling
createProviderModel(broken, 'm', 'action-1') throws; place this alongside the
existing openai-compatible tests so the provider endpoint requirement is
enforced and prevents regressions.
In `@lib/ai/resolve-model.test.ts`:
- Around line 81-102: Add a regression test in resolve-model.test.ts that
specifically asserts that resolveModel('wizard-assist', cfg) ignores any entry
in cfg.storyModels (e.g., storyModels: { 'wizard-assist': 'override-model' }) —
create a ResolveModelConfig mirroring the other tests (use
base/defaultProviderId as needed) and assert the result does NOT short-circuit
to the override and instead follows the normal wizard-assist resolution path
(i.e., the returned providerId/modelId should match the existing base behavior
for wizard-assist rather than 'override-model'); place this alongside the other
tests using the same expect/shape as resolveModel(...) assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f766c7fe-0635-428b-b3bb-ad16873e648d
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (44)
app/index.tsxapp/settings/index.tsxcomponents/compounds/ai-config-banner.stories.tsxcomponents/compounds/ai-config-banner.tsxcomponents/compounds/provider-setup-form.stories.tsxcomponents/compounds/provider-setup-form.tsxcomponents/reader/smoke/smoke-pipeline.tsdocs/implementation/lessons-learned/README.mddocs/implementation/lessons-learned/test-setup-import-graph-breaks-mocks.mddocs/implementation/milestones/02-first-user-loop/slices/01-provider.mdlib/actions/index.tslib/actions/settings/index.tslib/actions/settings/providers.test.tslib/actions/settings/providers.tslib/ai/agents.test.tslib/ai/agents.tslib/ai/catalog.test.tslib/ai/catalog.tslib/ai/index.tslib/ai/model.test.tslib/ai/model.tslib/ai/providers.test.tslib/ai/providers.tslib/ai/resolve-model.test.tslib/ai/resolve-model.tslib/ai/stub/temporary-registry.test.tslib/ai/stub/temporary-registry.tslib/ai/transport/call-with-retry.test.tslib/ai/transport/call-with-retry.tslib/ai/transport/classify-provider-error.test.tslib/ai/transport/classify-provider-error.tslib/ai/transport/provider-call.test.tslib/ai/transport/provider-call.tslib/db/app-settings/agents.tslib/db/index.tslib/diagnostics/sinks/http-redaction.test.tslib/pipeline/__tests__/fault-scenarios.test.tslib/pipeline/call-error.test.tslib/pipeline/call-error.tslib/pipeline/index.tslib/stores/app-settings/app-settings.tslocales/en/common.jsonlocales/en/settings.jsonpackage.json
Summary by CodeRabbit
New Features
Tests
Documentation