import { BedrockAgentRuntimeClient, type RetrievalFilter } from '@aws-sdk/client-bedrock-agent-runtime'; import { BedrockAgentClient } from '@aws-sdk/client-bedrock-agent'; import type { S3Client } from '@aws-sdk/client-s3'; import type { MemoryEntry, MemoryStore, MemoryStoreConfig, SearchOptions } from '../../memory/types.js'; import type { ExtractionConfig } from '../../memory/extraction/types.js'; import type { JSONValue } from '../../types/json.js'; /** * Knowledge base types as defined by `GetKnowledgeBase`. A `MANAGED` KB uses * `managedSearchConfiguration`; all others use `vectorSearchConfiguration`. */ type KbType = 'KENDRA' | 'MANAGED' | 'SQL' | 'VECTOR'; /** * S3 ingestion settings for {@link BedrockKnowledgeBaseStore}, required when `dataSourceType` is `'S3'`. * * An S3 data source indexes objects from a bucket — there is no inline-text path — so `add` uploads * to this bucket and then ingests directly (`IngestKnowledgeBaseDocuments`). Unlike a `CUSTOM` * document, an S3 document can't carry metadata inline, so a single `add` may write **two** objects: * - the content, as a `.txt` object; and * - when `scope`/`metadata` are present, a `.metadata.json` *sidecar* beside it. This * is Bedrock's out-of-band convention for attaching attributes to an S3 object — it's paired to * the content by name and used for retrieval filtering. With no scope/metadata, no sidecar is * written. * * Direct ingestion indexes whatever object you point it at, so `add` works with any `bucket`/`prefix` * the credentials can write to, regardless of where the data source is configured to read. * * The `bucket`/`prefix` choice only governs durability across future data-source *syncs* * (`StartIngestionJob`): a sync reconciles the index to match the data source's scanned location, so * an object outside that location is treated as deleted and removed from the index. If syncs will * run against this data source, upload to the bucket it reads from and a `prefix` within its * inclusion prefixes so directly-ingested memories survive them; otherwise the location is free. */ export interface BedrockKnowledgeBaseS3Config { /** Bucket the content object and its optional `.metadata.json` sidecar are uploaded to before ingestion. */ bucket: string; /** Client used to upload objects. When omitted, a default `S3Client` is constructed using the default credential chain. */ client?: S3Client; /** * Key prefix for uploaded objects (e.g. `'memories/'`). A trailing slash is added when missing. * Both the content object and its sidecar (when written) land under this prefix. */ prefix: string; } /** * Connection to a Bedrock Knowledge Base: which knowledge base, which data source, and the clients * used to reach them. This is the reusable half of a store's config — build one and pass it to many * {@link BedrockKnowledgeBaseStoreConfig}s that differ only by namespace. */ export interface BedrockKnowledgeBaseConfig { /** The Bedrock Knowledge Base identifier to query and ingest into. */ knowledgeBaseId: string; /** * The type of data source backing this knowledge base, matching Bedrock's `dataSourceType`. Only * `'CUSTOM'` and `'S3'` data sources accept direct document ingestion * (`IngestKnowledgeBaseDocuments`), so only those can be written to: * - `'CUSTOM'`: `add` ingests its `content` argument as inline text, with scope/metadata attached * as inline attributes. * - `'S3'`: `add` uploads its `content` to the configured `s3` bucket and ingests that object, so * the write is self-contained (no separate upload or sync needed). When scope/metadata are * present they're written as a *second* object — a `.metadata.json` sidecar beside the content — * since an S3 document can't carry attributes inline; with none, only the content object is * written. Requires `s3`; see {@link BedrockKnowledgeBaseS3Config}. * - `'OTHER'`: any other backend (Confluence, SharePoint, Salesforce, Web, SQL/Redshift, …), * which sync from an external store or are query-only and so are read-only. * * Effective writability is `writable && (dataSourceType === 'CUSTOM' || dataSourceType === 'S3')`: * a store is only writable when the caller opts in *and* the backend supports direct ingestion. * When omitted, the store is read-only. */ dataSourceType?: 'CUSTOM' | 'S3' | 'OTHER'; /** * Data source to ingest into when writing. Required for `add` to succeed — without it, write * calls throw, since the knowledge base has no destination to ingest into. */ dataSourceId?: string; /** S3 ingestion settings. Required when `dataSourceType` is `'S3'`; ignored otherwise. */ s3?: BedrockKnowledgeBaseS3Config; /** Metadata attribute key used for scope-based filtering. Defaults to `'namespace'`. */ scopeMetadataKey?: string; /** Knowledge base type (e.g. `'MANAGED'`, `'VECTOR'`). When provided, skips the `GetKnowledgeBase` call during initialization. */ knowledgeBaseType?: KbType; /** Pre-constructed runtime client for Retrieve calls. When omitted, a default client is constructed. */ runtimeClient?: BedrockAgentRuntimeClient; /** Pre-constructed agent client for IngestKnowledgeBaseDocuments calls. When omitted, a default client is constructed lazily on first write. */ agentClient?: BedrockAgentClient; } /** * Configuration for {@link BedrockKnowledgeBaseStore}. * * The reusable connection lives in {@link config}; the per-store identity and behavior fields * (`name`, `scope`, ...) sit beside it. To run one knowledge base across many namespaces, build a * {@link config} once and reuse it, varying only `name` and `scope` per store. */ export interface BedrockKnowledgeBaseStoreConfig extends MemoryStoreConfig { /** Connection to the knowledge base. Reuse one `config` across stores that differ only by `scope`. */ config: BedrockKnowledgeBaseConfig; /** Logical namespace used to isolate documents; applied as a metadata filter on search and stamped on writes. */ scope?: string; /** Explicit retrieval filter; overrides the auto-generated scope filter when provided. */ filter?: RetrievalFilter; /** * Document-level access control entries stamped on every write, required by data sources with ACL * awareness enabled (a write to such a data source fails without it). Applies to writes only; ACL * filtering at search time is supplied separately as retrieval `userContext`. */ accessControlList?: BedrockKnowledgeBaseAccessControlEntry[]; } /** * One document-level access control entry stamped on writes for ACL-aware data sources. * * The fields mirror Bedrock's `IngestKnowledgeBaseDocuments` access control entry. They are * serialized to whatever the target data source requires — as-is for `CUSTOM` (inline), and to the * capitalized `.metadata.json` sidecar keys for `S3` — so callers write one shape regardless of data * source. */ export interface BedrockKnowledgeBaseAccessControlEntry { /** `'ALLOW'` or `'DENY'`. Deny overrides allow. */ access: 'ALLOW' | 'DENY'; /** The principal identifier. Bedrock matches users by email. */ name: string; /** The principal type. `'USER'` is the only value Bedrock accepts today; validated server-side. */ type: string; } /** Result returned by {@link BedrockKnowledgeBaseStore.add}. */ export interface BedrockKnowledgeBaseAddResult { /** `CUSTOM`: the generated document id (UUID). `S3`: the `s3://` URI of the uploaded content object. */ documentId: string; } /** * A {@link MemoryStore} backed by Amazon Bedrock Knowledge Bases. Supports semantic search via * Retrieve and document ingestion via IngestKnowledgeBaseDocuments for CUSTOM and S3 data sources. * * Works with all knowledge base types (MANAGED, VECTOR, KENDRA, SQL); the type is detected via * `GetKnowledgeBase` during {@link initialize} and determines whether Retrieve uses * `managedSearchConfiguration` or `vectorSearchConfiguration`. Detection requires the * `bedrock:GetKnowledgeBase` permission; a failure raises at agent construction (via MemoryManager) * or on first `search()` standalone. To skip detection, provide `knowledgeBaseType` in the config. * * @example * ```typescript * import { BedrockKnowledgeBaseStore } from '@strands-agents/sdk/vended-memory-stores/bedrock-knowledge-base' * * const store = new BedrockKnowledgeBaseStore({ * config: { * knowledgeBaseId: 'KB123', * dataSourceType: 'CUSTOM', * dataSourceId: 'DS456', * }, * scope: 'user-abc', * writable: true, * }) * * const results = await store.search('what are my preferences?') * const { documentId } = await store.add('User prefers dark mode') * ``` */ export declare class BedrockKnowledgeBaseStore implements MemoryStore { readonly name: string; readonly description?: string; readonly maxSearchResults?: number; readonly writable: boolean; readonly extraction?: boolean | ExtractionConfig; private readonly _runtimeClient; private _agentClient; private _s3Client; private readonly _s3Config; private readonly _knowledgeBaseId; private readonly _dataSourceType; private readonly _dataSourceId; /** The knowledge base type, resolved eagerly in {@link initialize} via `GetKnowledgeBase`. */ private _kbType; /** * Logical namespace isolating documents: applied as a metadata filter on {@link search} and stamped * on writes via {@link add}. Unlike {@link name}, it is not a store-identity field, so it never * affects `MemoryManager` routing. For per-tenant isolation, construct one store per scope — cheap, * since they can share a single {@link BedrockKnowledgeBaseConfig}. */ readonly scope: string | undefined; /** Metadata attribute key used for scope-based filtering. */ readonly scopeMetadataKey: string; /** * Explicit retrieval filter. When set, it overrides the scope-derived filter for {@link search}. * Note the asymmetry: an explicit filter affects search only; writes always scope by {@link scope}. */ readonly filter: RetrievalFilter | undefined; /** Document-level access control entries stamped on every write, for ACL-aware data sources. */ readonly accessControlList: BedrockKnowledgeBaseAccessControlEntry[] | undefined; constructor(options: BedrockKnowledgeBaseStoreConfig); /** * Resolves the effective retrieval filter for a search: an explicit {@link filter} wins; otherwise * one is derived from {@link scope} / {@link scopeMetadataKey}. */ private _resolveFilter; /** * Resolve the knowledge base type via `GetKnowledgeBase` and cache the result. * * Idempotent: subsequent calls return immediately. When the store is registered with a * `MemoryManager`, this runs at agent construction so permission or connectivity issues surface * early. Standalone callers get the same check on first `search()`. * * @throws Error if the `GetKnowledgeBase` call fails for any reason. */ initialize(): Promise; /** * Searches the knowledge base for entries matching the query. * * @param query - The search query text * @param options - Optional search configuration * @returns Matching memory entries ordered by relevance. Each entry's `metadata` includes * user-provided attributes plus two reserved synthetic keys: `_relevanceScore` (number) and * `_sourceLocation` (Bedrock retrieval location object). */ search(query: string, options?: SearchOptions): Promise; /** * Ingests `content` (with optional `metadata`) into the knowledge base. * * Only `CUSTOM` and `S3` data sources support this — they are the sole `dataSourceType`s that * accept direct ingestion (`IngestKnowledgeBaseDocuments`). `OTHER` backends sync from an external * store or are query-only, so the store is read-only and `add` is unavailable. Requires * `dataSourceId` (and, for `S3`, an `s3` config); see {@link BedrockKnowledgeBaseStoreConfig}. * * @param content - The text content to ingest * @param metadata - Optional metadata attributes to attach to the document * @returns The document identifier (UUID for CUSTOM, s3:// URI for S3) */ add(content: string, metadata?: Record): Promise; private _isMissingAclError; /** * Uploads the objects that back one S3 ingestion and returns their `s3://` URIs. * * A single `add` produces up to *two* objects — hence the plural name and the multi-URI return: * - `contentUri`: the content itself, uploaded as a `.txt` object. Always written. * - `sidecarUri`: a `.metadata.json` sidecar carrying scope/metadata, written *only* * when there is any to attach (so it's optional in the return). Unlike a `CUSTOM` document, an * S3 document can't carry attributes inline, so the sidecar is Bedrock's out-of-band convention * for attaching them: it sits beside the content object and Bedrock pairs the two by name. * * Bedrock reads and indexes these objects on ingestion. * * Note: uploads are not transactional. If the sidecar upload (or the subsequent ingestion) fails * after the content object lands, the uploaded object(s) remain in the bucket un-ingested. They are * inert — a later data-source sync may pick them up, or they can be cleaned up out of band. */ private _uploadS3Objects; /** Uploads a single object to the configured bucket and returns its `s3://` URI. */ private _putObject; /** * Builds a document for an `S3` data source from the URIs produced by {@link _uploadS3Objects}. * * Takes both URIs because an S3 document references objects by location rather than carrying data * inline: `contentUri` becomes the document's content (the object to index), and `sidecarUri`, * when present, becomes its metadata (an `S3_LOCATION` pointing at the sidecar). With no * scope/metadata there's no sidecar, so `sidecarUri` is omitted and the document carries no * metadata. */ private _buildS3Document; /** * Resolves scope and caller metadata into a flat list of key-value pairs, handling collision * detection and unsupported-type filtering. Shared by both CUSTOM (inline attributes) and S3 * (sidecar) document builders. */ private _resolveAttributes; /** * Builds a document for a `CUSTOM` data source: the text ingested inline, with the scope and any * caller metadata attached as inline attributes for retrieval filtering. The caller supplies * `documentId` (so it can return that same id to its own caller) and it becomes the document's * `customDocumentIdentifier`. */ private _buildCustomDocument; /** * Builds the `metadataAttributes` map for an S3 `.metadata.json` sidecar from the scope and caller * metadata. Returns an empty map when there's nothing to attach — {@link _uploadS3Objects} treats * that as "no sidecar" and skips writing the second object. */ private _buildS3SidecarAttributes; /** * Builds the `accessControlList` array for an S3 `.metadata.json` sidecar. The sidecar uses * capitalized field names (`Name`/`Type`/`Access`), unlike the lowercase keys the `CUSTOM` inline * document takes, so entries are translated here. */ private _buildS3SidecarAcl; private _validateWriteConfig; private _getS3Client; private _getAgentClient; } export {}; //# sourceMappingURL=store.d.ts.map