Bedrock Action Groups: OpenAPI Tools That Typecheck Against Handlers

Bedrock Action Groups: OpenAPI Tools That Typecheck Against Handlers

Action groups with hand-written OpenAPI that drifts from Lambda handlers create phantom tools — agents “succeed” at calling operations that 500 in production. The unfair advantage is schema-from-code (or code-from-schema) plus a deploy gate that fails when handler signatures and OpenAPI disagree.

⚡ TL;DR: Generate OpenAPI from Zod/TypeBox handler contracts (or vice versa); CI diffs schema vs last release; Bedrock action group publishes only on match. Reject manually edited YAML that isn’t in the codegen path. Pair with Bedrock Agents idempotent tools and Spec-First AI Development.

One contract, two projections

// tools/createBooking.ts
import { z } from "zod";

export const CreateBookingInput = z.object({
  idempotencyKey: z.string().uuid(),
  listingId: z.string().min(1),
  nights: z.number().int().min(1).max(30),
});
export type CreateBookingInput = z.infer<typeof CreateBookingInput>;

export async function handler(event: unknown) {
  const input = CreateBookingInput.parse(event); // ✅ runtime == schema
  return createBooking(input);
}
# ✅ Generate OpenAPI fragment for the action group
pnpm tsx scripts/zod-to-openapi.ts tools/*.ts > action-groups/bookings.openapi.json

❌ Hand-maintaining bookings.openapi.json in the console while handlers evolve in git.

Deploy gate: schema ↔ handler

// ci/assert-action-group-sync.ts
import { CreateBookingInput } from "../tools/createBooking";
import openapi from "../action-groups/bookings.openapi.json";

function schemasEqual(a: unknown, b: unknown) {
  return JSON.stringify(a) === JSON.stringify(b);
}

const fromZod = zodToJsonSchema(CreateBookingInput);
const fromOas = openapi.paths["/createBooking"].post.requestBody.content["application/json"].schema;

if (!schemasEqual(fromZod, fromOas)) {
  throw new Error("action_group_schema_drift"); // ✅ fail deploy
}

Wire Bedrock without phantom ops

{
  "actionGroupName": "bookings",
  "apiSchema": { "payload": "<openapi>" },
  "actionGroupExecutor": { "lambda": "arn:aws:lambda:...:function:createBooking" },
  "functionSchema": null
}
Check Fail means
Zod parse in Lambda Bad agent args
CI schema sync Drift before agents see it
Idempotency key required Duplicate bookings
Auth context forwarded Confused deputy

Reuse DynamoDB conditional writes from Bedrock Agents idempotent tool calls. For GraphQL edges, same idea as AppSync With Bedrock.

Closing checklist

✅ Dos
– ✅ Single source of truth (Zod/TypeBox or OpenAPI)
– ✅ Codegen the other artifact
– ✅ Fail deploy on drift
– ✅ Require idempotency on writes
– ✅ Version action groups with agent aliases

❌ Don’ts
– ❌ Don’t edit OpenAPI only in the Bedrock console
– ❌ Don’t expose debug/admin ops to agents
– ❌ Don’t skip runtime parse in the Lambda
– ❌ Don’t share one fat Lambda for unrelated tools without contracts
– ❌ Don’t omit auth context propagation

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply