Skip to content

fix: improve devx for instantiating multiple bedrock KBs#2722

Merged
opieter-aws merged 2 commits into
strands-agents:mainfrom
opieter-aws:opieter-aws/bedrock-kb-namespace-factory
Jun 11, 2026
Merged

fix: improve devx for instantiating multiple bedrock KBs#2722
opieter-aws merged 2 commits into
strands-agents:mainfrom
opieter-aws:opieter-aws/bedrock-kb-namespace-factory

Conversation

@opieter-aws

@opieter-aws opieter-aws commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

Running one Bedrock Knowledge Base across multiple namespaces is a first-class use case (per-user, per-team, per-org memory partitions backed by the same KB). With the constructor shipped in #2630, doing so meant retyping the entire connection config for every namespace, with only scope differing:

const personal = new BedrockKnowledgeBaseStore({ name: 'personal', knowledgeBaseId: 'KB123', dataSourceType: 'CUSTOM', dataSourceId: 'DS456', writable: true, scope: 'user-abc' })
const team     = new BedrockKnowledgeBaseStore({ name: 'team',     knowledgeBaseId: 'KB123', dataSourceType: 'CUSTOM', dataSourceId: 'DS456', writable: true, scope: 'team-xyz' })

This PR restructures the constructor into a single nested shape that cleanly separates the reusable connection from the per-store identity. Build the connection once, then spin up one store per namespace:

const config = { knowledgeBaseId: 'KB123', dataSourceType: 'CUSTOM', dataSourceId: 'DS456' }

const personal = new BedrockKnowledgeBaseStore({ config, name: 'personal', scope: 'user-abc', writable: true })
const team     = new BedrockKnowledgeBaseStore({ config, name: 'team',     scope: 'team-xyz', writable: true })
new MemoryManager({ stores: [personal, team] })

This is a DX-only change — search/ingest/validation behavior is unchanged. It only restructures the constructor input.

Key design decisions (reviewer-relevant):

  • One shape, always nested — no flat form, no factory, no builder. A factory method/class and a shared-config merge were both considered and rejected: the store should have no notion of "sharing," and a configured store is not the place to encode a caller-side reuse pattern. Reusing config across stores is just the caller passing the same object.
  • Clean split, every field in exactly one place. Connection settings (knowledgeBaseId, dataSourceType, dataSourceId, s3, scopeMetadataKey, runtimeClient, agentClient) live inside the new BedrockKnowledgeBaseConfig; per-store identity/behavior (name, scope, description, writable, maxSearchResults, filter) sit beside it. No field is settable in two places, so there is no override-precedence rule or excess-property edge case to reason about.
  • name is required and independent of scope. An earlier iteration defaulted name to scope; this was dropped in favor of keeping them distinct — name is the routing identity surfaced to the model, scope is the data partition. Requiring name lets the store config simply extends MemoryStoreConfig (which already provides name, description, maxSearchResults, writable) instead of carrying an Omit<> workaround, and removes a runtime guard.
  • Per-namespace state is immutable. scope, scopeMetadataKey, and filter are readonly — to target a different namespace, construct another store from the same config rather than mutating one in place.
  • Client reuse falls out for free. Inject runtimeClient / agentClient into config and every store built from it reuses them; omit them and each store lazily builds its own default, exactly as before.

Related Issues

Builds on #2630 (adds BedrockKnowledgeBaseStore) and should land after it. Follow-up to #2544.

Documentation PR

No docs change in this PR. Note: the pre-existing examples in designs/0011-memory-manager.md use the original flat constructor form (and reference an extraction field that does not exist on the store); they predate this change and #2630, and are left for a separate docs reconciliation.

Type of Change

Breaking change

This restructures the public constructor of BedrockKnowledgeBaseStore. Because the store is introduced by #2630 and is not yet on main, this is a pre-release API change with no released consumers to migrate.

Public API Changes

The constructor now takes a nested config plus per-store fields, and a new BedrockKnowledgeBaseConfig type is exported:

// Before (#2630): flat
new BedrockKnowledgeBaseStore({
  name: 'personal',
  knowledgeBaseId: 'KB123',
  dataSourceType: 'CUSTOM',
  dataSourceId: 'DS456',
  writable: true,
  scope: 'user-abc',
})

// After: connection nested under `config`, identity beside it
new BedrockKnowledgeBaseStore({
  config: { knowledgeBaseId: 'KB123', dataSourceType: 'CUSTOM', dataSourceId: 'DS456' },
  name: 'personal',
  scope: 'user-abc',
  writable: true,
})

name is now required. scope, scopeMetadataKey, and filter are exposed as readonly instance fields — to target a different namespace, construct another store from the same config rather than mutating one in place.

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

TypeScript-only change, verified with the strands-ts gates: npm run build, npm run test (unit, including a @ts-expect-error assertion that name is required and a config-reuse suite covering client reuse, per-store defaults, and MemoryManager registration/dedup), npm run type-check (src + integ), npm run lint, npm run format:check — all green. All existing unit tests and the 15 integ-test constructions were migrated to the nested shape with no behavior assertions lost.

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@opieter-aws opieter-aws changed the title opieter aws/bedrock kb namespace factory fix: improve devx for instantiating multiple bedrock KBs Jun 10, 2026
@github-actions github-actions Bot added size/l area-community Related to community and contributor health chore Maintenance tasks, dependency updates, CI changes, refactoring with no user-facing impact labels Jun 10, 2026
@opieter-aws opieter-aws removed area-community Related to community and contributor health chore Maintenance tasks, dependency updates, CI changes, refactoring with no user-facing impact labels Jun 10, 2026
@opieter-aws opieter-aws force-pushed the opieter-aws/bedrock-kb-namespace-factory branch from d3629fa to 74a2f8d Compare June 10, 2026 21:21
@github-actions github-actions Bot added size/l and removed size/l labels Jun 10, 2026
@opieter-aws opieter-aws force-pushed the opieter-aws/bedrock-kb-namespace-factory branch from 74a2f8d to 10c461f Compare June 10, 2026 21:23
@github-actions github-actions Bot added size/l and removed size/l labels Jun 10, 2026
@opieter-aws opieter-aws marked this pull request as ready for review June 10, 2026 21:24
Comment thread strands-ts/src/vended-memory-stores/bedrock-knowledge-base/store.ts
@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Comment

Clean, well-motivated refactor: the nested config / per-store split is the right shape for the multi-namespace use case, the PR description documents the design tradeoffs thoroughly, build and all Node unit tests pass, and the existing behavior coverage was migrated without loss. Two non-blocking items below plus one process flag.

Review Categories
  • API design: The connection/identity split aligns with the SDK tenets and reads naturally. One open question on whether scopeMetadataKey belongs in the shared connection vs. beside scope (inline comment).
  • API review process: This changes a public, exported constructor contract and adds a new exported BedrockKnowledgeBaseConfig type. Per API_BAR_RAISING.md this is a "moderate" change that should carry the needs-api-review label — it's currently absent. Pre-release status lowers the migration cost but not the design-review bar.
  • Testing: Strong coverage including the @ts-expect-error name-required assertion and the config-reuse/MemoryManager suite. A couple of spots use per-field assertions where a single whole-object toStrictEqual would be stronger (inline comment).
  • Docs: PR notes the designs/0011-memory-manager.md examples still use the old flat form; deferring to a separate docs PR is reasonable but worth tracking so the design doc doesn't drift.

Nice work keeping the diff focused on the constructor reshape while preserving every behavior assertion.

@notowen333 notowen333 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in the same PR we can add some nuance to where nested constructor configs is valid. Can also follow up with it.

@opieter-aws

Copy link
Copy Markdown
Contributor Author

Maybe in the same PR we can add some nuance to where nested constructor configs is valid. Can also follow up with it.

@notowen333 do you mean adding a code example like in the description to a docstring?

@opieter-aws opieter-aws enabled auto-merge (squash) June 11, 2026 12:04
@opieter-aws opieter-aws merged commit e21098a into strands-agents:main Jun 11, 2026
24 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants