Bedrock and Bedrock Runtime
LocalEmu answers ListFoundationModels and GetFoundationModel from a curated catalog, and implements bedrock-runtime:InvokeModel. Only InvokeModel exists on the runtime side: Converse, ConverseStream and InvokeModelWithResponseStream return a 501 no handler for operation.
Operation-level coverage: Bedrock and Bedrock Runtime.
Model catalog
The catalog has 21 models: Anthropic Claude 3.x, Amazon Titan, Meta Llama 3, 3.1 and 3.2, Mistral and Mixtral, Cohere, and AI21 Jamba. ListFoundationModels supports byProvider (case-insensitive) and byOutputModality. GetFoundationModel on an unknown id returns ResourceNotFoundException. Newer providers (DeepSeek, Qwen and others) are not listed, because their exact Bedrock model ids were not verified. The other Bedrock operations (tagging, customization jobs) still go to the moto backend.
$ awsemu bedrock list-foundation-models --by-provider Cohere \
--query 'modelSummaries[].modelId'
[ "cohere.command-r-v1:0", "cohere.embed-english-v3", "cohere.embed-multilingual-v3" ] InvokeModel backends
The BEDROCK_BACKEND environment variable picks the backend.
| Value | Behavior |
|---|---|
synthetic (default) | A deterministic placeholder in each model family's real response shape (Anthropic Messages, Titan, Llama, Mistral, Cohere, AI21). The same prompt gives the same output and different prompts give different output. No Docker, no download. Any model id is accepted. |
ollama | Real generation and embeddings from a local model, in a shared ollama/ollama Docker container. Models are pulled on first use. The request is checked against the machine's total RAM first and refused with ServiceQuotaExceededException if the machine is below the model's tier (16, 32 or 64 GB). |
# default: instant, no dependencies
localemu start
# real local inference through Docker + Ollama
BEDROCK_BACKEND=ollama localemu start Which model runs locally
With the ollama backend, each Bedrock model id maps to an Ollama model, labeled by how faithful the substitution is. same family is the real open-weight model. different family is a real model standing in for a closed-weight one. unavailable has no practical local substitute and returns ValidationException (use the synthetic backend for it).
| Bedrock model id | Runs as | RAM tier | Fidelity |
|---|---|---|---|
anthropic.claude-3-haiku-20240307-v1:0 | llama3.1:8b | 16 GB | different family |
anthropic.claude-3-5-sonnet-20240620-v1:0 | llama3.1:8b | 16 GB | different family |
any other anthropic.claude-* id (Sonnet 4.x, Opus, Haiku 4.x, ...) | llama3.1:8b | 16 GB | different family |
amazon.titan-embed-text-v1 | nomic-embed-text | 16 GB | different family |
amazon.titan-embed-text-v2:0 | nomic-embed-text | 16 GB | different family |
amazon.titan-text-express-v1 | llama3.1:8b | 16 GB | different family |
meta.llama3-8b-instruct-v1:0 | llama3:8b | 16 GB | same family |
meta.llama3-1-8b-instruct-v1:0 | llama3.1:8b | 16 GB | same family |
meta.llama3-2-1b-instruct-v1:0 | llama3.2:1b | 16 GB | same family |
meta.llama3-2-3b-instruct-v1:0 | llama3.2:3b | 16 GB | same family |
meta.llama3-2-11b-instruct-v1:0 | llama3.2-vision:11b | 16 GB | same family |
meta.llama3-70b-instruct-v1:0 | llama3:70b | 64 GB | same family |
meta.llama3-1-70b-instruct-v1:0 | llama3.1:70b | 64 GB | same family |
meta.llama3-1-405b-instruct-v1:0 | none | n/a | unavailable |
meta.llama3-2-90b-instruct-v1:0 | none | n/a | unavailable |
mistral.mistral-7b-instruct-v0:2 | mistral:7b | 16 GB | same family |
mistral.mixtral-8x7b-instruct-v0:1 | mixtral:8x7b | 32 GB | same family |
mistral.mistral-large-2402-v1:0 | none | n/a | unavailable |
cohere.command-r-v1:0 | mistral:7b | 16 GB | different family |
cohere.embed-english-v3 | nomic-embed-text | 16 GB | different family |
cohere.embed-multilingual-v3 | nomic-embed-text | 16 GB | different family |
ai21.jamba-1-5-large-v1:0 | none | n/a | unavailable |
This is the complete mapping, from services/bedrock_runtime/local_inference.py. With the ollama backend the answer always comes from the model in the "Runs as" column, never from the model named in the request. The first call to a model pays the Docker pull and the load into RAM. Ollama unloads a model after about five minutes idle, so alternating between two large models on a 16 GB machine reloads each time.
IAM
With IAM enforcement on, InvokeModel is authorized as the real AWS action bedrock:InvokeModel on arn:aws:bedrock:<region>::foundation-model/<model-id>. A policy scoped to one model allows that model and denies the others.
Request validation
A malformed model id (not provider.model-name for a known Bedrock provider), and a request body that is empty, not JSON, or not a JSON object, return ValidationException (HTTP 400). A well-formed model id that is not in the catalog is accepted, including foundation-model ARNs and us., eu. and apac. inference-profile ids. The synthetic backend answers it. The ollama backend uses the mapping above, and for an id that is not in the table it returns ValidationException and tells you to use the synthetic backend, except for anthropic.claude-* ids, which use the Claude stand-in.
Known limitations
- •Only InvokeModel. No Converse, no streaming, no guardrails.
- •The RAM check reads the machine's total RAM, not Docker's allocation. Docker Desktop may be given less than the machine has, so a model can pass the check and still fail to load. Raise Docker's memory limit for the larger models.
- •Models outside the table have no local model. Under the ollama backend, only the ids in the table (and any
anthropic.claude-*id) run a local model. Newer Nova, Llama or Mistral ids are accepted but need the synthetic backend. Mappings are added as ids are verified. - •Closed-weight models are stand-ins. Claude, Titan and Command R run as other models under the ollama backend, so output quality and style differ from the real service.