1. Configure Amazon Bedrock
This section prepares the notebook runtime. It installs the small Python stack, reads Bedrock-specific environment variables, creates both a raw HTTPS session and an OpenAI SDK client, discovers model metadata when the endpoint provides it, and defines shared helpers used by later examples.
Set these environment variables before running the notebook. The default pairing is us-west-2 with openai.gpt-5.4.
export AWS_BEARER_TOKEN_BEDROCK="YOUR_BEDROCK_BEARER_TOKEN"
export AWS_REGION="us-west-2"
export BEDROCK_MODEL="openai.gpt-5.4"
export BEDROCK_BASE_URL="https://bedrock-mantle.${AWS_REGION}.api.aws/openai/v1"The bearer token is read from AWS_BEARER_TOKEN_BEDROCK. If it is missing, the setup cell asks for it with a password-style prompt and does not print it.
1.1 Install Dependencies
Install the packages used by the notebook. The OpenAI SDK is used for the application examples, requests is used for raw HTTPS calls to the Responses endpoint, and pandas plus IPython display helpers keep request and response summaries readable in the Cookbook renderer. Inspect the cell output only to confirm the packages installed or were already present.
%pip install -U "openai>=2.28.0" requests pandas ipython --quiet
print("Dependencies installed or already available: openai, requests, pandas, ipython")
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m A new release of pip is available: [0m[31;49m24.0[0m[39;49m -> [0m[32;49m26.1.1[0m
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m To update, run: [0m[32;49mpip install --upgrade pip[0m
Note: you may need to restart the kernel to use updated packages.
Dependencies installed or already available: openai, requests, pandas, ipython1.2 Import Libraries and Defaults
Import the standard libraries, SDK, HTTP client, and display utilities used throughout the notebook. This cell also sets the default Bedrock region and model used when environment variables are not already set. Inspect the printed defaults to confirm the notebook will start from us-west-2 and openai.gpt-5.4 unless you override them.
from __future__ import annotations
import base64
import builtins
import html
import json
import os
import shlex
import textwrap
import time
from datetime import date, timedelta
from getpass import getpass
from typing import Any, Callable, Iterable
import pandas as pd
import requests
from IPython.display import HTML, Markdown, display
from openai import OpenAI
DEFAULT_REGION = "us-west-2"
DEFAULT_MODEL = "openai.gpt-5.4"
PREFERRED_MODELS = [DEFAULT_MODEL]
def gpt_version_tuple(model_id: str) -> tuple[int, int] | None:
normalized = model_id.lower().removeprefix("openai.")
if not normalized.startswith("gpt-"):
return None
version = normalized.removeprefix("gpt-").split("-")[0]
parts = version.split(".")
try:
major = builtins.int(parts[0])
minor = builtins.int(parts[1]) if len(parts) > 1 else 0
except ValueError:
return None
return major, minor
def prompt_cache_retention_for_model(model_id: str) -> str:
version = gpt_version_tuple(model_id)
if version and version >= (5, 5):
return "24h"
return "in_memory"
pd.set_option("display.max_columns", None)
pd.set_option("display.max_rows", 200)
pd.set_option("display.max_colwidth", None)
pd.set_option("display.width", 160)
def display_wrapped_table(df: pd.DataFrame, *, max_col_width_px: int = 520, index: bool = False) -> None:
if df.empty:
display(Markdown("_No rows to display._"))
return
table_html = df.to_html(index=index, escape=True, border=0)
table_html = table_html.replace('<table border="0" class="dataframe">', '<table class="dataframe wrapped-output-table">')
display(HTML(f"""
{table_html}
"""))
print("Imports loaded.")
print("Default region:", DEFAULT_REGION)
print("Default model:", DEFAULT_MODEL)Imports loaded.
Default region: us-west-2
Default model: openai.gpt-5.41.3 Configure Bedrock Credentials and Clients
Read Bedrock configuration from the environment and construct clients. BEDROCK_BASE_URL is normalized once, the raw requests.Session gets the bearer token in its headers, and the OpenAI SDK client is created explicitly with the same token and base URL. Inspect the rendered table to confirm the selected region, model, endpoint, SDK client configuration, and stored-response cleanup behavior before making live calls.
from __future__ import annotations
def env_value(*names: str) -> str | None:
for name in names:
value = os.environ.get(name)
if value:
return value
return None
def env_flag(name: str, default: bool = False) -> bool:
value = env_value(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "on"}
def normalize_base_url(url: str) -> str:
url = url.strip().rstrip("/")
if url.endswith("/responses"):
return url[: -len("/responses")]
return url
def endpoint(path: str) -> str:
return f"{BEDROCK_BASE_URL}/{path.lstrip('/')}"
def responses_url(base_url: str) -> str:
return f"{normalize_base_url(base_url)}/responses"
API_TIMEOUT_SECONDS = float(env_value("BEDROCK_REQUEST_TIMEOUT_SECONDS") or "60")
MAX_RETRIES = builtins.int(env_value("BEDROCK_MAX_RETRIES") or "0")
CLEAN_UP_STORED_RESPONSES = env_flag("BEDROCK_CLEANUP_STORED_RESPONSES", True)
FAIL_ON_CHECK_FAILURE = env_flag("BEDROCK_FAIL_ON_CHECK_FAILURE", False)
RUN_RESPONSIVENESS_CHECK = env_flag("BEDROCK_RESPONSIVENESS_CHECK", True)
TRANSIENT_STATUS_CODES = {408, 409, 429, 500, 502, 503, 504}
AWS_REGION = (env_value("AWS_REGION") or DEFAULT_REGION).strip() or DEFAULT_REGION
BEDROCK_MODEL = (env_value("BEDROCK_MODEL") or DEFAULT_MODEL).strip() or DEFAULT_MODEL
BEDROCK_BASE_URL = normalize_base_url(
env_value("BEDROCK_BASE_URL") or f"https://bedrock-mantle.{AWS_REGION}.api.aws/openai/v1"
)
RESPONSES_URL = responses_url(BEDROCK_BASE_URL)
AWS_BEARER_TOKEN_BEDROCK = env_value("AWS_BEARER_TOKEN_BEDROCK")
if not AWS_BEARER_TOKEN_BEDROCK:
AWS_BEARER_TOKEN_BEDROCK = getpass("Paste your AWS Bedrock bearer token for this kernel session: ").strip()
if AWS_BEARER_TOKEN_BEDROCK:
os.environ["AWS_BEARER_TOKEN_BEDROCK"] = AWS_BEARER_TOKEN_BEDROCK
if not AWS_BEARER_TOKEN_BEDROCK:
raise RuntimeError("AWS_BEARER_TOKEN_BEDROCK is required to run the live examples.")
http = requests.Session()
http.headers.update({
"Authorization": f"Bearer {AWS_BEARER_TOKEN_BEDROCK}",
"Content-Type": "application/json",
})
client = OpenAI(api_key=AWS_BEARER_TOKEN_BEDROCK, base_url=BEDROCK_BASE_URL, max_retries=0)
BASE_URL = BEDROCK_BASE_URL
config_rows = [
{"setting": "AWS_REGION", "value": AWS_REGION},
{"setting": "BEDROCK_MODEL", "value": BEDROCK_MODEL},
{"setting": "BEDROCK_BASE_URL", "value": BEDROCK_BASE_URL},
{"setting": "SDK client", "value": "OpenAI(api_key=AWS_BEARER_TOKEN_BEDROCK, base_url=BEDROCK_BASE_URL)"},
{"setting": "cleanup stored responses", "value": CLEAN_UP_STORED_RESPONSES},
]
display_wrapped_table(pd.DataFrame(config_rows), max_col_width_px=680)| setting | value |
|---|---|
| AWS_REGION | us-west-2 |
| BEDROCK_MODEL | openai.gpt-5.4 |
| BEDROCK_BASE_URL | https://bedrock-mantle.us-west-2.api.aws/openai/v1 |
| SDK client | OpenAI(api_key=AWS_BEARER_TOKEN_BEDROCK, base_url=BEDROCK_BASE_URL) |
| cleanup stored responses | True |
1.4 Discover Available Models
Discover available models when the selected endpoint exposes model-list metadata, then choose the model for the rest of the notebook. If BEDROCK_MODEL is set, the notebook uses that value; otherwise it prefers openai.gpt-5.4. The model-list call is optional because some compatible endpoints may allow inference even when model metadata is unavailable. Inspect the selected model and any returned catalog rows.
from __future__ import annotations
def list_openai_models(client: OpenAI) -> list[str]:
return sorted(model.id for model in client.models.list(timeout=API_TIMEOUT_SECONDS).data)
def resolve_model_id(client: OpenAI | None) -> tuple[str, list[str], str | None]:
configured_model = env_value("BEDROCK_MODEL")
available_models: list[str] = []
model_discovery_note: str | None = None
if client is not None:
try:
available_models = list_openai_models(client)
except Exception as exc:
status_code = getattr(exc, "status_code", None)
if status_code == 404:
model_discovery_note = "This endpoint did not expose model-list metadata. The guide will continue with the configured model."
else:
model_discovery_note = f"Model-list metadata could not be listed. The guide will continue with the configured model. Details: {builtins.str(exc)[:240]}"
if configured_model:
return configured_model, available_models, model_discovery_note
for candidate in PREFERRED_MODELS:
if candidate in available_models:
return candidate, available_models, model_discovery_note
for candidate in available_models:
if candidate.startswith("openai."):
return candidate, available_models, model_discovery_note
if available_models:
return available_models[0], available_models, model_discovery_note
return PREFERRED_MODELS[0], available_models, model_discovery_note
EXPLICIT_MODEL = env_value("BEDROCK_MODEL")
MODEL_ID, AVAILABLE_MODELS, MODEL_DISCOVERY_NOTE = resolve_model_id(client)
os.environ["BEDROCK_MODEL"] = MODEL_ID
PROMPT_CACHE_RETENTION = prompt_cache_retention_for_model(MODEL_ID)
PROMPT_CACHE_RETENTION_NOTE = (
"GPT-5.5 and later use 24h extended prompt caching; earlier GPT-5 models can use in_memory."
)
config_rows = [{
"selected_model": MODEL_ID,
"model_was_explicit": bool(EXPLICIT_MODEL),
"model_catalog_status": "listed" if AVAILABLE_MODELS else "using configured model",
"discovered_model_count": len(AVAILABLE_MODELS),
"prompt_cache_retention": PROMPT_CACHE_RETENTION,
"prompt_cache_retention_note": PROMPT_CACHE_RETENTION_NOTE,
"note": MODEL_DISCOVERY_NOTE or "Model selection is ready.",
}]
display_wrapped_table(pd.DataFrame(config_rows), max_col_width_px=620)
if AVAILABLE_MODELS:
display_wrapped_table(pd.DataFrame({"available_models": AVAILABLE_MODELS[:25]}), max_col_width_px=520)
else:
print("Continuing with:", MODEL_ID)| selected_model | model_was_explicit | model_catalog_status | discovered_model_count | prompt_cache_retention | prompt_cache_retention_note | note |
|---|---|---|---|---|---|---|
| openai.gpt-5.4 | False | using configured model | 0 | in_memory | GPT-5.5 and later use 24h extended prompt caching; earlier GPT-5 models can use in_memory. | This endpoint did not expose model-list metadata. The guide will continue with the configured model. |
Continuing with: openai.gpt-5.41.5 Helper Functions Setup
Define shared helpers for the workflow. These helpers render request shapes, normalize API errors, send raw HTTPS requests, wrap SDK calls with optional retries, extract output_text, summarize token usage, track stored response IDs, and display compact tables. The examples below stay focused on each API concept while the helpers handle repeated mechanics. Inspect this cell if you want to understand how response text, usage, errors, and cleanup are processed.
from __future__ import annotations
RESULTS_SUMMARY: list[dict[str, Any]] = []
EXAMPLE_RESPONSES: list[dict[str, str]] = []
STORED_RESPONSE_IDS: list[str] = []
OUTPUT_WIDTH = 100
MAX_DISPLAY_TEXT_CHARS = builtins.int(env_value("BEDROCK_MAX_DISPLAY_CHARS") or "1200")
def truncate_display_text(text: Any, *, limit: int = MAX_DISPLAY_TEXT_CHARS) -> str:
rendered = builtins.str(text).strip()
if len(rendered) <= limit:
return rendered
return rendered[:limit].rstrip() + "\n[Display truncated for readability. Inspect the Python variable for the full value.]"
def compact_text(text: Any, limit: int = 220) -> str:
rendered = " ".join(builtins.str(text).split())
if len(rendered) <= limit:
return rendered
return rendered[:limit].rstrip() + "..."
def require(condition: Any, message: str) -> None:
if not condition:
raise ValueError(message)
def warn_or_raise(condition: bool, message: str) -> bool:
if condition:
return True
display(HTML(f"<div style=\"border-left:4px solid #d29922; padding:6px 10px; background:#fff8c5;\"><strong>Warning:</strong> {html.escape(message)}</div>"))
if FAIL_ON_CHECK_FAILURE:
raise AssertionError(message)
return False
def display_text_block(label: str, text: Any, *, limit: int = MAX_DISPLAY_TEXT_CHARS) -> None:
safe_label = html.escape(label)
safe_text = html.escape(truncate_display_text(text, limit=limit))
display(HTML(f"""
<div style="border:1px solid #d0d7de; border-radius:6px; margin:8px 0; overflow:hidden; font-size:13px;">
<div style="background:#f6f8fa; padding:6px 8px; font-weight:600;">{safe_label}</div>
<div style="padding:8px; white-space:pre-wrap; overflow-wrap:anywhere; line-height:1.45;">{safe_text}</div>
</div>
"""))
def print_wrapped(text: Any, *, width: int = OUTPUT_WIDTH) -> None:
print(textwrap.fill(builtins.str(text), width=width, break_long_words=True, break_on_hyphens=False))
def print_json(value: Any, *, width: int = OUTPUT_WIDTH) -> None:
display_json_block("JSON", value)
def print_label(label: str) -> None:
display(HTML(f"<div style=\"font-weight:600; margin:8px 0 4px;\">{html.escape(label)}</div>"))
def print_labeled_text(label: str, text: Any) -> None:
display_text_block(label, text)
def print_labeled_json(label: str, value: Any) -> None:
display_json_block(label, value)
def display_json_block(label: str, value: Any, *, limit: int = MAX_DISPLAY_TEXT_CHARS) -> None:
rendered = json.dumps(value, indent=2, default=builtins.str)
display_text_block(label, rendered, limit=limit)
def summarize_content(content: Any) -> str:
if isinstance(content, builtins.str):
return compact_text(content)
if isinstance(content, builtins.list):
parts: list[str] = []
for item in content:
if not isinstance(item, builtins.dict):
parts.append(compact_text(item, 80))
continue
item_type = item.get("type", "item")
if item_type == "input_text":
parts.append(f"input_text: {compact_text(item.get('text', ''), 120)}")
elif item_type == "input_file":
parts.append(f"input_file: {item.get('filename', '<inline file>')}")
else:
parts.append(item_type)
return "; ".join(parts)
return compact_text(content)
def summarize_input(input_value: Any) -> str:
if isinstance(input_value, builtins.str):
return compact_text(input_value, 260)
if isinstance(input_value, builtins.list):
messages: list[str] = []
for item in input_value[:4]:
if isinstance(item, builtins.dict):
role = item.get("role", item.get("type", "item"))
messages.append(f"{role}: {summarize_content(item.get('content', item))}")
else:
messages.append(compact_text(item, 120))
suffix = f"; +{len(input_value) - 4} more" if len(input_value) > 4 else ""
return f"{len(input_value)} item(s): " + "; ".join(messages) + suffix
return compact_text(input_value, 260)
def summarize_text_format(text_config: Any) -> str:
if not isinstance(text_config, builtins.dict):
return compact_text(text_config)
fmt = text_config.get("format")
if isinstance(fmt, builtins.dict):
fmt_type = fmt.get("type")
if fmt_type == "json_schema":
schema = fmt.get("schema") or {}
required = schema.get("required") or []
return f"json_schema: {fmt.get('name')} strict={fmt.get('strict')} required={len(required)} fields"
if fmt_type:
return builtins.str(fmt_type)
return compact_text(text_config)
def request_summary_rows(payload: dict[str, Any]) -> list[dict[str, str]]:
rows: list[dict[str, str]] = []
ordered_keys = [
"model", "max_output_tokens", "store", "background", "service_tier", "previous_response_id",
"parallel_tool_calls", "prompt_cache_key", "prompt_cache_retention",
]
for key in ordered_keys:
if key in payload:
rows.append({"field": key, "value": compact_text(payload[key], 180)})
if "reasoning" in payload:
rows.append({"field": "reasoning", "value": compact_text(payload["reasoning"], 180)})
if "text" in payload:
rows.append({"field": "text format", "value": summarize_text_format(payload["text"])})
if "include" in payload:
rows.append({"field": "include", "value": compact_text(payload["include"], 180)})
if "tools" in payload:
tool_names = [tool.get("name", tool.get("type", "tool")) for tool in payload.get("tools", [])]
rows.append({"field": "tools", "value": ", ".join(tool_names)})
if "tool_choice" in payload:
rows.append({"field": "tool_choice", "value": compact_text(payload["tool_choice"], 180)})
if "input" in payload:
rows.append({"field": "input", "value": summarize_input(payload["input"])})
return rows
def print_request_shape(payload: dict[str, Any]) -> None:
rows = request_summary_rows(redact_payload(payload))
print_label("Request shape")
display_wrapped_table(pd.DataFrame(rows), max_col_width_px=520)
def print_response_summary(response_or_summary: Any) -> None:
summary = response_or_summary if isinstance(response_or_summary, builtins.dict) and "output" not in response_or_summary else summarize_response(response_or_summary)
preferred = [
"id", "model", "status", "output_item_types", "input_tokens", "cached_input_tokens",
"output_tokens", "total_tokens", "reasoning_output_tokens", "service_tier",
]
rows = [{"field": key, "value": compact_text(summary.get(key), 220)} for key in preferred if key in summary]
print_label("Response summary")
display_wrapped_table(pd.DataFrame(rows), max_col_width_px=420)
def print_key_takeaway(text: str) -> None:
display(HTML(f"<div style=\"border-left:4px solid #1f6feb; padding:6px 10px; background:#f6f8fa; margin:8px 0;\"><strong>Key takeaway:</strong> {html.escape(text)}</div>"))
def redact_payload(payload: dict[str, Any]) -> dict[str, Any]:
def redact(value: Any) -> Any:
if isinstance(value, builtins.dict):
return {
key: ("<inline file data redacted for display>" if key == "file_data" else redact(item))
for key, item in value.items()
}
if isinstance(value, builtins.list):
return [redact(item) for item in value]
return value
return json.loads(json.dumps(redact(payload), default=builtins.str))
def compact_detail(detail: Any) -> str:
if isinstance(detail, (builtins.dict, builtins.list)):
return compact_text(json.dumps(detail, default=builtins.str), 500)
return compact_text(detail, 500)
def record_check(name: str, status: str, detail: Any = "") -> None:
RESULTS_SUMMARY.append({"name": name, "status": status, "detail": compact_detail(detail)})
def record_response(example: str, response_type: str, content: Any, limit: int = 900) -> None:
if isinstance(content, pd.DataFrame):
rendered = content.to_json(orient="records", indent=2)
elif isinstance(content, (builtins.dict, builtins.list)):
rendered = json.dumps(content, indent=2, default=builtins.str)
else:
rendered = builtins.str(content)
rendered = rendered.strip()
if len(rendered) > limit:
rendered = rendered[:limit].rstrip() + chr(10) + "..."
EXAMPLE_RESPONSES.append({
"example": example,
"response_type": response_type,
"response": rendered,
})
def print_response_gallery() -> pd.DataFrame:
gallery = pd.DataFrame(EXAMPLE_RESPONSES)
if gallery.empty:
gallery = pd.DataFrame(columns=["example", "response_type", "response"])
display_wrapped_table(gallery, max_col_width_px=620)
return gallery
def normalize_error(response: requests.Response, body: Any) -> dict[str, Any]:
return {
"exception_class": "HTTPError",
"status_code": response.status_code,
"retryable": response.status_code in TRANSIENT_STATUS_CODES,
"request_id": response.headers.get("x-request-id"),
"body": body,
}
def describe_api_error(exc: Exception) -> dict[str, Any]:
try:
parsed = json.loads(builtins.str(exc))
if isinstance(parsed, builtins.dict) and "status_code" in parsed:
return {
"exception_class": type(exc).__name__,
"status_code": parsed.get("status_code"),
"retryable": parsed.get("retryable"),
"request_id": parsed.get("request_id"),
"message": compact_text(parsed.get("body", parsed), 500),
}
except Exception:
pass
status_code = getattr(exc, "status_code", None)
response = getattr(exc, "response", None)
request_id = None
if response is not None:
headers = getattr(response, "headers", {})
request_id = headers.get("x-request-id") if hasattr(headers, "get") else None
return {
"exception_class": type(exc).__name__,
"status_code": status_code,
"retryable": status_code in TRANSIENT_STATUS_CODES,
"request_id": request_id,
"message": builtins.str(exc)[:500],
}
def request_json(method: str, path: str, *, payload: dict[str, Any] | None = None) -> dict[str, Any]:
response = http.request(
method,
endpoint(path),
json=payload,
timeout=API_TIMEOUT_SECONDS,
)
try:
body = response.json() if response.text else {}
except json.JSONDecodeError:
body = {"raw_text": response.text}
if response.status_code >= 400:
raise RuntimeError(json.dumps(normalize_error(response, body), indent=2, default=builtins.str))
return body
def to_dict(value: Any) -> Any:
if hasattr(value, "model_dump"):
return value.model_dump(mode="json")
if isinstance(value, builtins.list):
return [to_dict(item) for item in value]
if isinstance(value, builtins.dict):
return {key: to_dict(item) for key, item in value.items()}
return value
def output_text(response: Any) -> str:
direct = getattr(response, "output_text", None)
if direct:
return direct
data = to_dict(response)
pieces: list[str] = []
for item in data.get("output", []) or []:
for content in item.get("content", []) or []:
if content.get("type") == "output_text":
pieces.append(content.get("text", ""))
return "".join(pieces)
def response_items(response: Any) -> list[dict[str, Any]]:
data = to_dict(response)
return builtins.list(data.get("output", []) or [])
def first_output_item(response: Any, item_type: str) -> dict[str, Any] | None:
for item in response_items(response):
if item.get("type") == item_type:
return item
return None
def summarize_response(response: Any) -> dict[str, Any]:
data = to_dict(response)
usage = data.get("usage") or {}
input_details = usage.get("input_tokens_details") or {}
output_details = usage.get("output_tokens_details") or {}
return {
"id": data.get("id"),
"model": data.get("model"),
"status": data.get("status"),
"output_item_types": [item.get("type") for item in data.get("output", []) or []],
"input_tokens": usage.get("input_tokens"),
"output_tokens": usage.get("output_tokens"),
"total_tokens": usage.get("total_tokens"),
"cached_input_tokens": input_details.get("cached_tokens"),
"reasoning_output_tokens": output_details.get("reasoning_tokens"),
"service_tier": data.get("service_tier"),
}
def call_with_retries(label: str, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
kwargs.setdefault("timeout", API_TIMEOUT_SECONDS)
last_exc: Exception | None = None
for attempt in range(1, MAX_RETRIES + 2):
try:
return func(*args, **kwargs)
except Exception as exc:
last_exc = exc
error = describe_api_error(exc)
should_retry = bool(error["retryable"] and attempt <= MAX_RETRIES)
if not should_retry:
raise
time.sleep(min(2 ** (attempt - 1), 8))
raise RuntimeError(f"{label} failed after retries") from last_exc
def create_response(**kwargs: Any) -> Any:
kwargs.setdefault("model", MODEL_ID)
return call_with_retries("responses.create", client.responses.create, **kwargs)
def retrieve_response(response_id: str) -> Any:
return call_with_retries("responses.retrieve", client.responses.retrieve, response_id)
def delete_response(response_id: str) -> Any:
return call_with_retries("responses.delete", client.responses.delete, response_id)
def remember_stored_response(response: Any) -> None:
response_id = getattr(response, "id", None) or to_dict(response).get("id")
if response_id:
STORED_RESPONSE_IDS.append(response_id)
def handle_example_error(features: str | list[str], exc: Exception) -> None:
feature_list = [features] if isinstance(features, builtins.str) else features
error = describe_api_error(exc)
for feature in feature_list:
record_check(feature, "warn", error)
print_labeled_text("Result", "This live call did not complete in this environment.")
print_labeled_json("Response summary", error)
def build_curl_command(payload: dict[str, Any]) -> str:
body = json.dumps(payload)
return " ".join([
"curl", "-sS", shlex.quote(RESPONSES_URL),
"-H", shlex.quote("Content-Type: application/json"),
"-H", shlex.quote("Authorization: Bearer $AWS_BEARER_TOKEN_BEDROCK"),
"-d", shlex.quote(body),
])
def run_raw_http_request(payload: dict[str, Any]) -> dict[str, Any]:
return request_json("POST", "/responses", payload=payload)
print("Helpers ready.")Helpers ready.1.6 Verify the Endpoint
The first live call is intentionally tiny. It sends a minimal Responses request with store=false and a short text instruction so you can catch setup issues before running richer examples. Inspect the request shape, returned text, status, model, output item types, and token usage.
from __future__ import annotations
preflight_payload = {
"model": MODEL_ID,
"input": "Reply with exactly: ok",
"max_output_tokens": 1024,
"store": False,
}
print_request_shape(preflight_payload)
try:
preflight_response = create_response(**preflight_payload)
require(output_text(preflight_response).strip(), "Preflight response did not return output text.")
record_check("Endpoint shape", "pass", RESPONSES_URL)
model_selection_detail = f"{len(AVAILABLE_MODELS)} models discovered" if AVAILABLE_MODELS else "Using configured model; model-list metadata is not required for requests."
record_check("Model selection", "pass", model_selection_detail)
preflight_text = output_text(preflight_response).strip()
record_response("Endpoint verification", "text", preflight_text)
print_labeled_text("Result", preflight_text)
print_response_summary(preflight_response)
print_key_takeaway('A tiny response confirms that the endpoint, key, model, and request shape are working.')
except Exception as exc:
handle_example_error(["Endpoint shape", "Model selection"], exc)| field | value |
|---|---|
| model | openai.gpt-5.4 |
| max_output_tokens | 1024 |
| store | False |
| input | Reply with exactly: ok |
| field | value |
|---|---|
| id | resp_gnt2qiavimim2lvfrtosh472mmsodtphk4glbiiefj7joxb4k4ra |
| model | openai.gpt-5.4 |
| status | completed |
| output_item_types | ['message'] |
| input_tokens | 162 |
| cached_input_tokens | 0 |
| output_tokens | 5 |
| total_tokens | 167 |
| reasoning_output_tokens | 0 |
| service_tier | default |
1.7 Normalize API Errors
Production integrations need consistent error logging for status codes, retry decisions, request IDs, and response bodies. This cell documents the normalized error shape used by the notebook without intentionally making a failing request. Later cells use the same shape when a live call fails or returns a non-2xx status.
from __future__ import annotations
error_taxonomy_example = {
"normalized_fields": ["exception_class", "status_code", "retryable", "request_id", "message"],
"retryable_status_codes": sorted(TRANSIENT_STATUS_CODES),
"notes": "call_with_retries(...) uses this taxonomy for transient retry handling.",
}
record_check("Error handling", "pass", error_taxonomy_example)
print_json(error_taxonomy_example) <div style="background:#f6f8fa; padding:6px 8px; font-weight:600;">JSON</div>
<div style="padding:8px; white-space:pre-wrap; overflow-wrap:anywhere; line-height:1.45;">\{
"normalized_fields": [ "exception_class", "status_code", "retryable", "request_id", "message" ], "retryable_status_codes": [ 408, 409, 429, 500, 502, 503, 504 ], "notes": "call_with_retries(...) uses this taxonomy for transient retry handling." }</div>