Agentic AI AcademyAgentic AI Academy

Capstone: A Production-Grade Agent

Memory-backed, tool-using, observable, governed — end to end

Advanced 15 minBuilder
What you'll be able to do
  • Diagram the reference architecture of a production AgentCore agent: Runtime + Gateway tools + Memory + Identity (inbound JWT, outbound token vault) + Observability/Evaluations + Policy/Guardrails
  • Execute the build sequence in order: wrap the agent, deploy to Runtime, attach Memory, expose tools via Gateway, wire inbound and outbound auth, instrument and evaluate, then govern
  • Apply a go-live checklist covering ARM64 builds, least-privilege execution roles, KMS, the >=33-char session-id strategy, quotas/scaling, Transaction Search, PII filtering, cost monitoring, and version/endpoint rollback
  • Operate the agent: monitor in the CloudWatch GenAI Observability dashboard, evaluate quality with built-in evaluators, and manage cost against the consumption dimensions
  • Re-verify volatile facts (pricing, quotas, regions, model IDs, preview-vs-GA status) against live AWS sources before depending on them
At a glance

This is the build that ties the whole platform together: a Runtime-hosted agent that calls Gateway tools, persists with Memory, authenticates inbound and reaches a downstream API outbound via Identity, is instrumented and evaluated through Observability, and is governed by Policy and Guardrails. You will walk the canonical build sequence end to end, then ship it behind a production go-live checklist (ARM64, least-privilege roles, KMS, session-id strategy, quotas, Transaction Search, PII filtering, cost, rollback). One last time, treat every pricing/quota/region/model-ID/preview fact as volatile and re-verify it against the live AWS source before you rely on it.

  1. 1The reference architecture: one diagram, every pillar
  2. 2The build sequence: wrap, deploy, attach, expose, wire, instrument, govern
  3. 3Wiring inbound and outbound auth with Identity
  4. 4Govern, observe, and evaluate
  5. 5The production go-live checklist
  6. 6Operating it, and the volatile-fact discipline

The reference architecture: one diagram, every pillar

Everything you have learned in this course converges on a single shape. A production AgentCore agent is a Runtime-hosted Python service that pulls in the other primitives as it needs them:

text
  Caller (app / another agent)
        |  inbound auth: JWT/OIDC  (or SigV4)
        v
  +-------------------- AgentCore Runtime (per-session microVM) --------------------+
  |  BedrockAgentCoreApp  ->  @app.entrypoint  ->  your framework agent             |
  |                                                                                  |
  |   Memory  <----- short-term events + long-term records (namespaced)             |
  |   Gateway --MCP--> tools (Lambda / OpenAPI / Smithy / MCP server / API GW)       |
  |   Identity ------> token vault (outbound 2LO/3LO to Google/GitHub/internal API)  |
  |   Guardrails ----> content filters / denied topics / PII on the model boundary   |
  +----------------------------------------------------------------------------------+
        |  every tool call intercepted by Policy (Cedar) ENFORCE/LOG
        |  OTEL traces/spans/metrics/logs -> CloudWatch (GenAI dashboard)
        v
  Observability + Evaluations

Map each box to its job:

PillarServiceResponsibility in the architecture
HostRuntimeServerless, session-isolated execution; protocol contract (/invocations, /ping)
ToolsGatewayTurns APIs/Lambda/Smithy/MCP servers into one MCP endpoint; M x N collapse
StateMemoryShort-term events per session + long-term records extracted by strategies
AuthIdentityInbound (who can call) + outbound (token vault for downstream APIs)
SafetyGuardrailsContent filters, denied topics, PII redaction on the model boundary
GovernPolicy (Cedar)Intercepts every tool call in ENFORCE or LOG mode
OperateObservability + EvaluationsOTEL telemetry to CloudWatch; quality scoring on traces

The platform is composable: you do not have to use all of it. The all-in pattern is what we build here, but an a la carte deployment (your agent on EKS using only Gateway, or only Memory) is equally valid. What does not change is the invariant: a wrapped entrypoint, an inbound auth decision, durable state where you need it, governed tool access, and telemetry you can trust.

Key insight

Identity is two halves, do not conflate them

Inbound auth answers 'who is allowed to call this agent' (JWT/OIDC or SigV4). Outbound auth answers 'how does the agent reach a downstream API on the user's behalf' (the token vault, 2LO/3LO). The bouncer at the door is not the valet who fetches the user's keys. They are configured separately and fail in different ways.

Tip

Identity is free behind Runtime/Gateway

When Identity is consumed through Runtime or Gateway there is no additional Identity charge (as of writing, per the pricing page) — you pay per OAuth-token / API-key request only when calling Identity standalone. Verify on the live pricing page before you model cost.

The build sequence: wrap, deploy, attach, expose, wire, instrument, govern

Build the agent in a deliberate order. Each step depends on the one before it, and getting the order wrong is how people end up with a tool-using agent that has no auth or an observable agent with no governance.

1. Wrap the agent. The bedrock-agentcore SDK turns any framework function into the Runtime HTTP contract. This is the 'four lines to deploy' core:

python
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent

app = BedrockAgentCoreApp()
agent = Agent()  # model-agnostic; default model is configurable

@app.entrypoint
def invoke(payload, context):          # optional 2nd arg = RequestContext
    session_id = context.session_id     # echo this; >=33 chars
    result = agent(payload.get("prompt", ""))
    return {"result": result.message}

if __name__ == "__main__":
    app.run()   # local: http://localhost:8080 ; in container binds 0.0.0.0:8080

Test the exact cloud contract locally before you deploy anything:

bash
curl -X POST http://localhost:8080/invocations \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"What is the weather?"}'

2. Deploy to Runtime. Use the new AgentCore CLI (@aws/agentcore, CDK -> CloudFormation) or the starter toolkit (bedrock-agentcore-starter-toolkit, CodeBuild). They expose the same agentcore binary with different verbs — pin which one your runbook assumes.

bash
agentcore create --name SupportAgent --framework Strands \
  --protocol HTTP --model-provider Bedrock --memory none
cd SupportAgent
agentcore dev          # hot-reload + inspector on :8080
agentcore deploy       # package -> CDK synth -> CloudFormation; builds ARM64; pushes to ECR
agentcore status       # agent ARN, endpoint, log group

3. Attach Memory. Add short-term events plus the long-term strategies you actually need:

bash
agentcore add memory --name SupportMem --strategies SUMMARIZATION,USER_PREFERENCE
agentcore deploy

4. Expose tools via Gateway. Aggregate your backends into one MCP endpoint:

bash
agentcore add gateway --name SupportGW --authorizer-type NONE --runtimes SupportAgent
agentcore add gateway-target --name OrdersTarget --type lambda-function-arn \
  --lambda-arn <ARN> --tool-schema-file tools.json --gateway SupportGW
agentcore deploy

5. Wire inbound + outbound auth. Inbound: switch the runtime to JWT. Outbound: register a credential provider and decorate the function that touches the downstream API (Step covered in detail in the auth section below).

6. Instrument + evaluate. Runtime-hosted agents are auto-instrumented with OTEL; enable Transaction Search once, then read traces in the GenAI dashboard and turn on online Evaluations.

7. Govern. Attach a Cedar policy engine to the gateway and a Bedrock Guardrail to the model boundary — last, so you are governing a system that already works end to end.

Watch out

Two CLIs, one binary, different verbs

The starter toolkit uses configure/launch/invoke; the new AgentCore CLI uses create/dev/deploy/invoke. Both ship an agentcore binary and both deploy to the same Runtime with the same bedrock-agentcore SDK, but copy-pasting commands across them fails. Note also launch vs deploy: the devguide and the Python Runtime API use .launch(), while the current starter-toolkit CLI renamed the verb to deploy (with destroy for teardown) — same operation.

Watch out

No strategies = no long-term memory

agentcore add memory with no --strategies gives you short-term events only — raw turns scoped by actorId+sessionId, nothing extracted. Long-term records (preferences, summaries, semantic facts, episodes) only exist if you attach a strategy. Extraction is async (~20-40s as of writing), so a retrieve_memories immediately after create_event may return nothing — design for eventual consistency.

Wiring inbound and outbound auth with Identity

Auth is where capstone builds most often go wrong, because the two halves are configured in completely different places.

Inbound (JWT/OIDC). A runtime supports either SigV4 or JWT, not both — they are mutually exclusive per version. To require a bearer token, attach a customJWTAuthorizer:

python
client.create_agent_runtime(
    agentRuntimeName='SupportAgent',
    agentRuntimeArtifact={'containerConfiguration': {'containerUri': '...ecr.../support:latest'}},
    authorizerConfiguration={"customJWTAuthorizer": {
        "discoveryUrl": 'https://cognito-idp.us-west-2.amazonaws.com/<pool>/.well-known/openid-configuration',
        "allowedClients": ['<COGNITO_CLIENT_ID>']}},
    networkConfiguration={"networkMode": "PUBLIC"},
    roleArn='arn:aws:iam::111122223333:role/AgentRuntimeRole',
    lifecycleConfiguration={'idleRuntimeSessionTimeout': 300, 'maxLifetime': 1800})

Once a runtime is JWT-protected, boto3 cannot invoke itinvoke_agent_runtime signs with SigV4. You must make a raw HTTPS request with Authorization: Bearer <token> (the ARN URL-encoded into the path). Cognito has no Dynamic Client Registration, so pre-register the OAuth client.

Outbound (token vault). To call a downstream API on the user's behalf, register a credential provider once, then decorate the function. The @requires_access_token decorator runs the full workload-identity -> vault -> consent flow and injects the credential as a kwarg — the raw token never touches your business logic or the LLM context:

python
from bedrock_agentcore.identity.auth import requires_access_token

@requires_access_token(
    provider_name="google-provider",
    scopes=["https://www.googleapis.com/auth/drive.metadata.readonly"],
    auth_flow="USER_FEDERATION",                  # 3LO; "M2M" for client-credentials
    on_auth_url=lambda url: print("Authorize:\n" + url),  # in prod, stream URL to the caller
    force_authentication=False)
async def read_from_google_drive(*, access_token: str):
    ...  # use access_token to call the Google Drive API

Under the hood the runtime exchanges the inbound token for a Workload Access Token (GetWorkloadAccessTokenForJWT), then the agent calls the vault (GetResourceOauth2Token) which mints the provider authorization URL for 3LO. The vault stores downstream tokens with strict per-(agent identity + user id) isolation — zero token sharing — encrypted at rest and in transit via KMS, and auto-refreshes them. For Google specifically, you need "access_type":"offline" in customParameters to get a refresh token (the gotchas differ per provider; verify the live resource-providers page).

Register the provider and its callback URL — forgetting the callback registration is the classic 3LO break:

bash
aws bedrock-agentcore-control create-oauth2-credential-provider --region us-east-1 \
  --name "google-provider" --credential-provider-vendor "GoogleOauth2" \
  --oauth2-provider-config-input '{"googleOauth2ProviderConfig":{"clientId":"...","clientSecret":"..."}}'
# Register the returned callbackUrl in the provider's "Authorized redirect URIs"

Watch out

The user-id header is opaque and unverified

X-Amzn-Bedrock-AgentCore-Runtime-User-Id lets you delegate by user id without a JWT, but the value is an opaque, unverified identifier and needs the extra bedrock-agentcore:InvokeAgentRuntimeForUser IAM action. Restrict that action to trusted principals and specific runtimes, derive the user id from the authenticated principal (never raw client input), audit it via CloudTrail (runtimeUserId), and explicitly Deny it where delegation isn't needed. Prefer JWT in production.

Note

Workload-token IAM changed at GA

Agents created before Oct 13 2025 (as of writing — verify) need execution-role permissions for bedrock-agentcore:GetWorkloadAccessToken, GetWorkloadAccessTokenForJWT, and GetWorkloadAccessTokenForUserId. Agents created on/after that date rely on the service-linked role AWSServiceRoleForBedrockAgentCoreRuntimeIdentity instead; the control-API caller needs iam:CreateServiceLinkedRole.

Govern, observe, and evaluate

A working agent is not a production agent until you can govern its actions and see what it did.

Govern with Policy (Cedar). The Cedar policy engine intercepts every tool call through the gateway. Attach it in ENFORCE (block) or LOG (observe-only) mode — start in LOG, watch what would be denied, then flip to ENFORCE:

python
client.create_gateway(
    name="SupportGW", roleArn="...", protocolType="MCP", authorizerType="CUSTOM_JWT",
    authorizerConfiguration={"customJWTAuthorizer": {"discoveryUrl": "...", "allowedClients": ["..."]}},
    policyEngineConfiguration={"mode": "LOG", "arn": "arn:aws:bedrock-agentcore:...:policy-engine/..."})

Govern the model boundary with Guardrails. Two ways: native (attach guardrail_id/guardrail_version to a Strands BedrockModel, detect firing via response.stop_reason == "guardrail_intervened") or the model-agnostic ApplyGuardrail API for OpenAI/Gemini/self-hosted models. Both cover content filters, denied topics, word filters, PII detection/redaction, and contextual grounding. Use shadow mode (log would-be blocks before enforcing) to tune thresholds without breaking users.

Observe. Runtime-hosted agents are auto-instrumented with OpenTelemetry — no extra libs for baseline traces/sessions/metrics (add aws-opentelemetry-distro to requirements.txt for completeness). The one mandatory one-time step is enabling CloudWatch Transaction Search before spans are searchable (~10 min to take effect; 1% indexing is free as of writing):

bash
aws xray update-trace-segment-destination --destination CloudWatchLogs
aws xray update-indexing-rule ...

Then view everything in the GenAI Observability dashboard: CloudWatch -> #gen-ai-observability -> Bedrock AgentCore tab -> Agents View / Sessions View / Trace View. Pass the runtimeSessionId on every invoke so the Sessions view stitches a conversation together.

Evaluate. Evaluations ride the same OTEL traces. Online evaluation samples a configurable % of traces and scores them in the dashboard with no code changes, using built-in evaluators across three levels — Session (Goal Success Rate), Trace (Helpfulness, Correctness, Faithfulness, Harmfulness, Instruction Following, ...), and Tool (Tool Selection Accuracy, Tool Parameter Accuracy). The framing to keep straight: Observability = what happened / how fast / what cost / where it failed; Evaluation = was it correct / helpful / safe.

Watch out

The GenAI dashboard only shows Runtime (and Policy under Gateway)

Only the Agent (Runtime) resource — and Policy, which appears under the Gateway tab — surfaces in the GenAI Observability dashboard. Memory, Gateway, and Tools emit metrics to plain CloudWatch only, and their spans/logs require explicit enablement via vended-log delivery (Runtime auto-creates its log group; the others do not). Don't expect to find your Memory traces in the dashboard by default.

Watch out

APPLICATION_LOGS capture full payloads

APPLICATION_LOGS capture the full request and response payloads plus trace/span/session IDs — durable to CloudWatch Logs, S3, or Data Firehose. That is exactly where PII and secrets leak. Filter sensitive data before emission; this is a non-negotiable go-live item, not an afterthought.

The production go-live checklist

Run this list before you point real traffic at the agent. Each item maps to a failure you have already seen in this course.

#CheckWhy it bites
1ARM64 buildRuntime runs on Graviton (ARM64). A wrong-arch (amd64) container silently fails. Hand-built images need docker buildx build --platform linux/arm64; the CLIs handle arch automatically.
2Least-privilege execution roleAuto-generated dev policies are broad and not production-grade (AWS says so). Scope logs to /aws/bedrock-agentcore/runtimes/*, workload tokens to your agent's workload-identity/<agentName>-*, model access to the specific models, and ECR actions only for container deploys.
3KMSMemory and the Identity token vault encrypt at rest; pass a customer-managed CMK (encryptionKeyArn) instead of the service-managed key where compliance requires it.
4Session-id strategyGenerate a unique id per conversation, >=33 chars (a UUID is 36), and reuse it for related invocations for both context and microVM affinity. Echo back the id the response returns. Your backend owns the user->session mapping; AWS does not.
5Quotas / scalingConfirm InvokeAgentRuntime throughput (25 TPS, adjustable as of writing) and the active-session-workloads quota fit your load. Per-session ceiling is 2 vCPU / 8 GB (not adjustable). Verify all numbers on the live quotas page.
6Transaction Search ONOne-time, required, and ~10 min to take effect — spans are not searchable without it. Forgetting this is the #1 'where are my traces' bug.
7PII filteringFilter sensitive data out of APPLICATION_LOGS before emission and enable Guardrails PII redaction on the model boundary.
8Cost monitoringAgentCore billing is consumption-based across ~12 components. Watch the dimensions that apply (active vCPU/GB-hours; per Gateway invocation; per Memory event/record/retrieval; per Policy authorization). Resource-usage metrics are not billing and lag ~60 min.
9Rollback via versions/endpointsEach deploy creates a new runtime version; endpoints (qualifiers) point at a version. Roll back by repointing an endpoint at a known-good version rather than redeploying under fire.

Don't block the entrypoint. A blocking call inside @app.entrypoint starves the /ping thread and your session gets killed at the idle timeout during long work. Offload to threads/async and, for background work, use app.add_async_task(...) so /ping reports HealthyBusy. If you implement a custom /ping, time_of_last_update (Unix seconds) is required — omit it and the idle timeout fires even while busy.

python
@app.ping
def ping():
    return {"status": "Healthy", "time_of_last_update": int(time.time())}

Example

Least-privilege execution-role actions (abbreviated)

Logs: CreateLogGroup/CreateLogStream/PutLogEvents on /aws/bedrock-agentcore/runtimes/. X-Ray: PutTraceSegments/PutTelemetryRecords. CloudWatch: cloudwatch:PutMetricData scoped to namespace bedrock-agentcore. Workload tokens: bedrock-agentcore:GetWorkloadAccessToken scoped to workload-identity-directory/default/workload-identity/<agentName>-*. Model: bedrock:InvokeModel / InvokeModelWithResponseStream. ECR actions only for container (not direct-code) deploys.

Operating it, and the volatile-fact discipline

Once live, operating the agent is a steady loop across three lenses you have already built:

  • Monitor in the GenAI Observability dashboard. Watch the Runtime metrics by their exact names — Invocations, Throttles, System Errors, User Errors, Latency, Session Count — and drill into the Trace View when a session misbehaves. Resource-usage metrics (CPUUsed-vCPUHours, MemoryUsed-GBHours) can lag up to ~60 min and are not your bill.
  • Evaluate quality continuously with online evaluation sampling a % of production traces. A drop in Goal Success Rate or a spike in Refusal is your early-warning signal — long before users complain.
  • Manage cost against the consumption dimensions. The cheap-looking line items hide cost elsewhere: Observability and Payments are pass-through (you pay CloudWatch / the wallet provider), and Memory has several sub-dimensions (events, records-per-month, retrievals). Overrides and self-managed memory strategies also incur Bedrock model charges billed to your account.

The volatile-fact discipline, one last time. This course has tagged dozens of facts [VOLATILE] for a reason: AgentCore moves fast. Before you rely on any of the following, open the live AWS source and re-verify:

Volatile factWhere to verify
All pricing numbers + free tieraws.amazon.com/bedrock/agentcore/pricing/
All quotas/limits (Runtime, Memory, Gateway, ...)the AgentCore service quotas/limits page
Region availabilitythe AgentCore regions page
Bedrock model IDs / default Strands modelthe Bedrock supported-models page
Preview-vs-GA status (Policy, Evaluations, Registry, Payments)the AgentCore overview / What's New
SDK / toolkit / CLI versionsPyPI / npm

Never assert a price, a quota, a region count, a model ID, or a GA date as a timeless fact — frame it as 'as of writing, verify the live page.' Anything the docs leave ambiguous (for example the OTEL log-group suffix, or any number marked UNVERIFIED), hedge explicitly or leave it out. That habit is the difference between a runbook that ages gracefully and one that quietly becomes wrong.

Key insight

Composability is your exit ramp

If the all-in build is more than you need, peel pillars off. Run the agent on EKS/Lambda and use only Gateway for governed tools, or only Memory for state, or only Code Interpreter. You can also publish your tools via Gateway + Registry so other teams' agents consume them — the 'tool provider' pattern. The architecture degrades gracefully to exactly the pieces you use.

Try it: Capstone: ship a memory-backed, tool-using, governed, observable agent

Goal: build the full reference architecture end to end, then walk it through the go-live checklist. Use a region from the live regions page (examples use us-east-1 / us-west-2).

  1. Wrap & deploy. Scaffold with agentcore create --name SupportAgent --framework Strands --protocol HTTP --model-provider Bedrock --memory none. Implement an @app.entrypoint that reads payload['prompt'] and context.session_id. Test the contract locally with the curl -X POST http://localhost:8080/invocations call, then agentcore deploy and agentcore status to capture the agent ARN, endpoint, and log group.

  2. Attach Memory. agentcore add memory --name SupportMem --strategies SUMMARIZATION,USER_PREFERENCE and redeploy. Write one event, then retrieve — observe that the long-term record is not there immediately (async extraction, ~20-40s as of writing). Note in your runbook how you handle eventual consistency.

  3. Expose a tool via Gateway. Add a Lambda gateway target with a tools.json schema. Confirm the tool name is namespaced ${target_name}___${tool_name} and that your Lambda strips the prefix before dispatching.

  4. Wire auth. Switch inbound to a customJWTAuthorizer (Cognito discovery URL + allowedClients). Register an outbound OAuth2 credential provider, register its returned callbackUrl in the provider, and decorate the downstream-calling function with @requires_access_token(auth_flow="USER_FEDERATION", ...). Verify you can no longer invoke with plain boto3 (you now need a Bearer token over raw HTTPS).

  5. Observe & evaluate. Enable CloudWatch Transaction Search (wait ~10 min). Invoke a few times passing a >=33-char runtimeSessionId. Open the GenAI dashboard (#gen-ai-observability -> Bedrock AgentCore -> Sessions/Trace View) and find your traces. Turn on online Evaluations to score a sample of traces.

  6. Govern. Attach a Cedar policy engine to the gateway in LOG mode, run traffic, inspect what would be denied, then flip to ENFORCE. Attach a Bedrock Guardrail (or ApplyGuardrail) on the model boundary and confirm PII redaction.

  7. Go-live review. Walk the 9-item checklist: ARM64, least-privilege role, KMS, session-id strategy, quotas, Transaction Search, PII filtering, cost monitoring, rollback via versions/endpoints. For three of the items, open the relevant live AWS page and confirm the current value (a quota, a price, a region) — practicing the volatile-fact discipline. Write a short paragraph: which numbers had changed (or might change) since this lesson was written, and how you verified them.

Key takeaways

  1. 1The reference architecture is a Runtime-hosted agent that composes Gateway (tools), Memory (state), Identity (inbound + outbound auth), Guardrails + Policy (governance), and Observability + Evaluations (operations) — and it is composable, so you can use any subset.
  2. 2Build in order: wrap the agent (BedrockAgentCoreApp/@app.entrypoint) -> deploy to Runtime -> attach Memory -> expose tools via Gateway -> wire inbound (JWT) + outbound (token vault) auth -> instrument + evaluate -> govern with Policy/Guardrails last.
  3. 3Inbound and outbound Identity are separate concerns: a runtime is JWT *or* SigV4 (not both), boto3 cannot call a JWT-protected runtime, and outbound credentials live in a per-(agent+user) KMS-encrypted vault injected via @requires_access_token — never in code or LLM context.
  4. 4Go-live checklist: ARM64 build, least-privilege execution role, KMS/CMK, >=33-char reused session ids, quotas/scaling fit, Transaction Search ON, PII filtered out of APPLICATION_LOGS, cost monitored against consumption dimensions, rollback via versions/endpoints.
  5. 5Don't block the entrypoint (it starves /ping and kills the session); offload long work to async tasks and include time_of_last_update in custom /ping responses.
  6. 6Operate via the GenAI dashboard (only Runtime + Policy appear there; Memory/Gateway/Tools are plain CloudWatch), evaluate quality continuously with built-in evaluators on the same OTEL traces, and watch the pass-through and multi-dimension cost traps.
  7. 7Re-verify every volatile fact (pricing, quotas, regions, model IDs, preview-vs-GA, SDK versions) against the live AWS source before relying on it; never state a fast-moving number as timeless.

Quiz

Lock in what you learned

Check your understanding

0 / 4 answered

1.You protect your Runtime agent with a JWT customJWTAuthorizer for inbound auth, then your integration test that calls boto3 invoke_agent_runtime starts failing with an auth error. What is the correct fix?

2.Your agent deploys cleanly and serves traffic, but in the CloudWatch GenAI Observability dashboard you cannot find any spans for your Memory or Gateway activity. What is most likely going on?

3.During a long-running task, your agent's sessions keep getting killed around the 15-minute mark even though work is still in progress. Which root cause and fix fit the AgentCore Runtime contract?

4.You are writing the cost section of the agent's runbook. Which statement should you put in it, given AgentCore's billing model?

Go deeper

Hand-picked sources to keep learning