Run a Box shipment agent on AgentCore Runtime
Amazon Bedrock AgentCore Runtime runs this shipment agent with Box around its process. The agent reads a synthetic order, checks eligibility, and requests one replacement. Box refuses dispatch before eligibility and further shipment or refund requests after either resolution. Use Strands for the first run. The same sample also includes a LangChain variant.
Before you start
Section titled “Before you start”Prepare the package on Linux ARM64 with Python 3.12, pip, Git, and Rust through rustup. ARM64 is the 64-bit Arm processor architecture. The Box checkout selects its Rust toolchain. Install its native build dependencies. On Amazon Linux 2023, the build requires GCC, G++, Make, CMake, OpenSSL development files, pkg-config, and Perl. Python 3.12 also needs the pip and virtual-environment packages.
Use a development AWS account and an existing Amazon S3 bucket in us-west-2 owned by that account.
Authenticate a profile with permissions to deploy CloudFormation, create the execution role, upload the package, and invoke Runtime.
The execution role receives model permissions from the generated template.
Model and cloud-resource usage can incur charges.
The sample README records the tested source revision, framework versions, and platform limits. The deployment uses managed Runtime V2 with Python 3.12 and a non-root operator. The model profile and endpoint are fixed to the tested commercial AWS configuration.
Prepare the package
Section titled “Prepare the package”Clone the repository and enter the sample directory:
git clone https://github.com/strands-agents/box.gitcd box/examples/cloud-deployments/agentcore-runtimepython3.12 -m venv .venv. .venv/bin/activatepython -m pip install -r requirements-deploy.txtpython prepare.py --framework strandspython deploy-runtime.py package --with-strands --output-dir ./deployment-strandsPreparation builds the pinned Box source and installs locked dependencies for Linux ARM64 and Python 3.12.
It writes local manifests with file hashes. Packaging checks those hashes before producing runtime.zip.
If a dependency download fails, rerun preparation from the same checkout to reuse the existing Box build.
The output directory also contains runtime.cloudformation.json and package-receipt.json.
Inspect the generated template before deployment.
It creates one Runtime and an execution role with package-read, logging, and selected model permissions.
The role includes bedrock:CallWithBearerToken, which requires a wildcard resource.
Deploy and invoke
Section titled “Deploy and invoke”Set the account, profile, bucket, and a new stack name:
export ACCOUNT_ID='YOUR_12_DIGIT_ACCOUNT'export AWS_PROFILE='YOUR_DEVELOPMENT_PROFILE'export PACKAGE_BUCKET='YOUR_EXISTING_BUCKET'export STACK_NAME='BoxShipmentDemoStrandsExample'python deploy-runtime.py deploy --with-strands \ --account "$ACCOUNT_ID" --profile "$AWS_PROFILE" --region us-west-2 \ --bucket "$PACKAGE_BUCKET" --stack-name "$STACK_NAME" \ --output-dir ./deployment-strandspython deploy-runtime.py invoke --example shipment-strands \ --account "$ACCOUNT_ID" --profile "$AWS_PROFILE" --region us-west-2 \ --stack-name "$STACK_NAME" --output-dir ./deployment-strandsThe helper checks the account and bucket Region, uploads the package, and creates or updates the example’s stack. It refuses to update a stack without its example ownership tag. Each invocation writes a unique receipt before it sends the request. The wrapper starts fresh Box state and a synthetic service for that invocation. The checked-in policies use port 0. Each runner binds that field to its synthetic service’s allocated port.
Read the result
Section titled “Read the result”The five fixed prompts exercise the following sequence:
| Request | Expected result |
|---|---|
| Read the order, then dispatch before eligibility | The read succeeds. Box refuses dispatch. |
| Check eligibility, then dispatch | The service confirms one replacement. |
| Dispatch again | Box refuses the duplicate. |
| Request a refund | Box refuses the competing resolution. |
| Produce the customer response | The verifier checks confirmed shipment fields. |
Check the receipt:
python - <<'PYTHON'import jsonfrom pathlib import Pathreceipt = json.loads(Path("deployment-strands/invocation-shipment-strands-receipt.json").read_text())result = receipt["result"]["result"]assert receipt["result"]["status"] == result["status"] == "PASS"assert result["checks"] and all(value is True for value in result["checks"].values())print("Shipment PASS", len(result["checks"]), "checks")PYTHONThe Strands result contains 24 assertions about this fixed conversation. Read the agent’s report with the service effects and Box decisions. Intermediate model prose remains ungraded. Model responses can vary and can fail verification.
The policy uses five minutes of recent response history for one order and sequential requests. It does not establish permanent exclusivity, concurrent correctness, or recovery after a lost response or process restart. A production service must enforce those properties when it commits a shipment or refund.
Use LangChain
Section titled “Use LangChain”Use a fresh example checkout and prepare it with python prepare.py --framework langchain.
Install requirements-deploy.txt in its virtual environment as above.
The variant uses langchain.agents.create_agent and ChatBedrockConverse, with LangGraph underneath.
Follow the same package, deploy, and invoke steps with these substitutions:
| Strands setting | LangChain setting |
|---|---|
--with-strands | --with-langchain |
--example shipment-strands | --example shipment-langchain |
./deployment-strands | ./deployment-langchain |
BoxShipmentDemoStrandsExample | BoxShipmentDemoLangchainExample |
The expected result contains 36 successful assertions.
The verifier checks structured shipment facts before a trusted template creates the final customer response.
Use deployment-langchain/invocation-shipment-langchain-receipt.json for its result.
Run the scripted controls
Section titled “Run the scripted controls”Both framework packages include fixed shipment and research controls.
Invoke them with --example shipment or --example research using the same deployment arguments.
These controls make no model calls.
The shipment control also tests refund before dispatch and failed refund responses.
The research control compares a request budget with a static policy against a synthetic local receiver.
Stop and remove the deployment
Section titled “Stop and remove the deployment”Stop each invocation with the exact unique receipt path printed by the helper. Use the corresponding output directory and stack for the variant you deployed.
python deploy-runtime.py stop --receipt ./deployment-strands/invocations/SESSION_UUID.json \ --account "$ACCOUNT_ID" --profile "$AWS_PROFILE" --region us-west-2 \ --stack-name "$STACK_NAME" --output-dir ./deployment-strandsThe stop request retains the Runtime, stack, and package. To remove the example stack, disable its termination protection and delete it:
aws cloudformation update-termination-protection --no-enable-termination-protection \ --stack-name "$STACK_NAME" --region us-west-2 --profile "$AWS_PROFILE"aws cloudformation delete-stack --stack-name "$STACK_NAME" --region us-west-2 --profile "$AWS_PROFILE"aws cloudformation wait stack-delete-complete --stack-name "$STACK_NAME" --region us-west-2 --profile "$AWS_PROFILE"Delete only this example’s package object from S3 after the stack deletion completes.
Its key is box-shipment-example/PACKAGE_SHA256/runtime.zip, using the hash in package-receipt.json.
Retain the shared bucket. CloudWatch log groups can remain after stack deletion. Apply your account’s log-retention policy.