Problem
AK's backend-selection factories have drifted apart. Across InputGuardrailFactory/OutputGuardrailFactory, Trace.get(), SessionStoreBuilder, ThreadStoreBuilder, the multimodal _build_driver, and the AWS response-store handler:
- Unknown
type is handled inconsistently — guardrail/trace raise a bare Exception; session/thread/response stores silently fall back to an in-memory default (a production footgun).
- The "install the extra" hint is ad hoc — only
SessionStoreBuilder's valkey branch has it, though redis/dynamodb/cosmos/firestore need extras too.
- No shared, typed config error — bare
raise Exception(...) in several places.
- No bring-your-own (BYO) path — a user on an unsupported backend (e.g. Datadog for tracing) can't plug in their own implementation without forking AK.
Goal
One house pattern for every pluggable surface:
- Built-ins resolved via
if/elif + real imports (grep/mypy/refactor-safe).
- A shared
resolve_dotted(path, base=…) else branch on every surface → first-class BYO (point type at a dotted path to your own subclass, e.g. acme_obs.datadog.DatadogTrace).
- A shared
require_extra(...) for uniform, friendly missing-dependency errors.
- A shared
AKConfigError (in core/util/) replacing bare Exception.
Decisions
- Fail loud on an unknown, non-dotted-path
type — drop the silent in-memory fallback (behavior change for session/thread/response stores).
- Per-surface construction contract (a BYO session store gets
cache=…, a guardrail is no-arg, etc.); no forced-uniform params.
- Relax the Pydantic
pattern= constraints on type fields (they currently reject dotted paths at config-load).
- Retire the
Types StrEnum + from_str in the store builders.
- The pluggable ABCs (
BaseTrace, InputGuardrail/OutputGuardrail, SessionStore, ThreadStore, AttachmentStore, and the sandbox ABCs) become public, stability-bearing interfaces.
Scope (incremental)
- Shared helpers +
AKConfigError, applied to trace + guardrail first.
- Session, thread, and multimodal storage builders.
- Converge the sandbox factory (built-ins → real imports) and the AWS response-store handler.
Design note: docs/specs/<this-issue>-pluggable-backend-factories/design.md.
Problem
AK's backend-selection factories have drifted apart. Across
InputGuardrailFactory/OutputGuardrailFactory,Trace.get(),SessionStoreBuilder,ThreadStoreBuilder, the multimodal_build_driver, and the AWS response-store handler:typeis handled inconsistently — guardrail/trace raise a bareException; session/thread/response stores silently fall back to an in-memory default (a production footgun).SessionStoreBuilder'svalkeybranch has it, though redis/dynamodb/cosmos/firestore need extras too.raise Exception(...)in several places.Goal
One house pattern for every pluggable surface:
if/elif+ real imports (grep/mypy/refactor-safe).resolve_dotted(path, base=…)elsebranch on every surface → first-class BYO (pointtypeat a dotted path to your own subclass, e.g.acme_obs.datadog.DatadogTrace).require_extra(...)for uniform, friendly missing-dependency errors.AKConfigError(incore/util/) replacing bareException.Decisions
type— drop the silent in-memory fallback (behavior change for session/thread/response stores).cache=…, a guardrail is no-arg, etc.); no forced-uniformparams.pattern=constraints ontypefields (they currently reject dotted paths at config-load).TypesStrEnum +from_strin the store builders.BaseTrace,InputGuardrail/OutputGuardrail,SessionStore,ThreadStore,AttachmentStore, and the sandbox ABCs) become public, stability-bearing interfaces.Scope (incremental)
AKConfigError, applied to trace + guardrail first.Design note:
docs/specs/<this-issue>-pluggable-backend-factories/design.md.