diff --git a/app/_data/entity_examples/gateway/routes/a2a-kongair-route.yaml b/app/_data/entity_examples/gateway/routes/a2a-kongair-route.yaml new file mode 100644 index 0000000000..8ffc797ff6 --- /dev/null +++ b/app/_data/entity_examples/gateway/routes/a2a-kongair-route.yaml @@ -0,0 +1,9 @@ +name: a2a-kongair-route +paths: + - /a2a +strip_path: true +service: + name: a2a-kongair-agent +protocols: + - http + - https \ No newline at end of file diff --git a/app/_data/entity_examples/gateway/services/a2a-kongair-agent.yaml b/app/_data/entity_examples/gateway/services/a2a-kongair-agent.yaml new file mode 100644 index 0000000000..bd61ab3e40 --- /dev/null +++ b/app/_data/entity_examples/gateway/services/a2a-kongair-agent.yaml @@ -0,0 +1,2 @@ +name: a2a-kongair-agent +url: http://host.docker.internal:10000 \ No newline at end of file diff --git a/app/_how-tos/ai-gateway/limit-a2a-body-size.md b/app/_how-tos/ai-gateway/limit-a2a-body-size.md index d80f8b0e5c..0fada8e6b6 100644 --- a/app/_how-tos/ai-gateway/limit-a2a-body-size.md +++ b/app/_how-tos/ai-gateway/limit-a2a-body-size.md @@ -49,15 +49,15 @@ related_resources: prereqs: entities: services: - - a2a-currency-agent + - a2a-kongair-agent routes: - - a2a-route + - a2a-kongair-route inline: - title: OpenAI API key include_content: prereqs/openai icon_url: /assets/icons/openai.svg - title: A2A agent - include_content: prereqs/a2a-agent + include_content: prereqs/a2a-kongair-agent icon_url: /assets/icons/ai.svg @@ -144,7 +144,7 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "Show me routes from SFO to JFK" {% endvalidation %} diff --git a/app/_how-tos/ai-gateway/proxy-a2a-agents.md b/app/_how-tos/ai-gateway/proxy-a2a-agents.md index 3544829fe5..fe68b20d03 100644 --- a/app/_how-tos/ai-gateway/proxy-a2a-agents.md +++ b/app/_how-tos/ai-gateway/proxy-a2a-agents.md @@ -49,9 +49,9 @@ related_resources: prereqs: entities: services: - - a2a-currency-agent + - a2a-kongair-agent routes: - - a2a-route + - a2a-kongair-route gateway: - name: KONG_TRACING_INSTRUMENTATIONS - name: KONG_TRACING_SAMPLING_RATE @@ -88,7 +88,7 @@ prereqs: ``` icon: assets/icons/opentelemetry.svg - title: A2A agent - include_content: prereqs/a2a-agent + include_content: prereqs/a2a-kongair-agent icon_url: /assets/icons/ai.svg cleanup: @@ -163,7 +163,7 @@ method: GET You should see the following response: ```json -{"capabilities":{"pushNotifications":true,"streaming":true},"defaultInputModes":["text","text/plain"],"defaultOutputModes":["text","text/plain"],"description":"Helps with exchange rates for currencies","name":"Currency Agent","preferredTransport":"JSONRPC","protocolVersion":"0.3.0","skills":[{"description":"Helps with exchange values between various currencies","examples":["What is exchange rate between USD and GBP?"],"id":"convert_currency","name":"Currency Exchange Rates Tool","tags":["currency conversion","currency exchange"]}],"url":"http://0.0.0.0:10000/","version":"1.0.0"}% +{"capabilities":{"pushNotifications":false,"streaming":false},"defaultInputModes":["text","text/plain"],"defaultOutputModes":["text","text/plain"],"description":"An A2A-compatible agent powered by LangGraph and OpenAI that queries KongAir APIs for flights, routes, bookings, and loyalty info.","name":"KongAir OpenAI Agent","preferredTransport":"JSONRPC","protocolVersion":"0.3.0","skills":[{"description":"Find KongAir routes between airports.","examples":["Show me routes from SFO to JFK","Find flights from LHR to SFO"],"id":"search_routes","name":"Search KongAir routes","tags":["kongair","flights","travel","routes"]},{"description":"Get available flights for a specific route.","examples":["What flights are available on route KA-123?"],"id":"get_flights","name":"Get flights","tags":["kongair","flights"]},{"description":"Look up a booking by ID.","examples":["Check booking BK-456"],"id":"check_booking","name":"Check booking","tags":["kongair","bookings"]},{"description":"Get loyalty program information for a customer.","examples":["What's my loyalty status for customer C-789?"],"id":"loyalty_info","name":"Loyalty program info","tags":["kongair","loyalty","rewards"]}],"url":"http://a2a-agent:10000/","version":"1.0.0"} ``` {:.no-copy-code} @@ -178,7 +178,7 @@ entities: config: traces_endpoint: http://${otel-host}:4319/v1/traces metrics: - endpoint: http://${otel.host}:4319/v1/metrics + endpoint: http://${otel-host}:4319/v1/metrics enable_ai_metrics: true resource_attributes: service.name: kong-a2a @@ -211,7 +211,7 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "What flights are available on route KA-123?" {% endvalidation %} @@ -223,24 +223,24 @@ You should see data in your OpenTelemetry Collector terminal. You can also searc ``` ResourceSpans #0 -Resource SchemaURL: +Resource SchemaURL: Resource attributes: -> service.instance.id: Str(9c214152-1621-456a-8b42-6f1309dac551) -> service.name: Str(kong-a2a) -> service.version: Str(3.14.0.0) ScopeSpans #0 -ScopeSpans SchemaURL: +ScopeSpans SchemaURL: InstrumentationScope kong-internal 0.1.0 Span #0 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 - Parent ID : + Parent ID : ID : 779db508077de69f Name : kong Kind : Server Start time : 2026-04-03 06:48:41.446000128 +0000 UTC End time : 2026-04-03 06:48:47.139977728 +0000 UTC Status code : Unset - Status message : + Status message : Attributes: -> http.flavor: Str(1.1) -> http.route: Str(/a2a) @@ -261,7 +261,7 @@ Span #1 Start time : 2026-04-03 06:48:41.446752256 +0000 UTC End time : 2026-04-03 06:48:41.44679424 +0000 UTC Status code : Unset - Status message : + Status message : Span #2 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : 779db508077de69f @@ -271,7 +271,7 @@ Span #2 Start time : 2026-04-03 06:48:41.446919936 +0000 UTC End time : 2026-04-03 06:48:41.447105024 +0000 UTC Status code : Unset - Status message : + Status message : Span #3 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : de4e6ed2c16a2dd3 @@ -281,7 +281,7 @@ Span #3 Start time : 2026-04-03 06:48:41.44707456 +0000 UTC End time : 2026-04-03 06:48:47.140356608 +0000 UTC Status code : Unset - Status message : + Status message : Attributes: -> kong.a2a.protocol.version: Str(unknown) -> rpc.system: Str(jsonrpc) @@ -299,7 +299,7 @@ Span #4 Start time : 2026-04-03 06:48:41.447129088 +0000 UTC End time : 2026-04-03 06:48:41.447464448 +0000 UTC Status code : Unset - Status message : + Status message : Span #5 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : 779db508077de69f @@ -309,11 +309,11 @@ Span #5 Start time : 2026-04-03 06:48:41.44754304 +0000 UTC End time : 2026-04-03 06:48:41.447862272 +0000 UTC Status code : Unset - Status message : + Status message : Attributes: -> dns.record.port: Double(10000) -> dns.record.ip: Str(172.18.0.2) - -> dns.record.domain: Str(a2a-currency-agent) + -> dns.record.domain: Str(a2a-kongair-agent) Span #6 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : 779db508077de69f @@ -323,7 +323,7 @@ Span #6 Start time : 2026-04-03 06:48:47.139697664 +0000 UTC End time : 2026-04-03 06:48:47.139731712 +0000 UTC Status code : Unset - Status message : + Status message : Span #7 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : 779db508077de69f @@ -333,7 +333,7 @@ Span #7 Start time : 2026-04-03 06:48:47.139753728 +0000 UTC End time : 2026-04-03 06:48:47.1397632 +0000 UTC Status code : Unset - Status message : + Status message : Span #8 Trace ID : 1bfc19e17dd9121769882cd9b8bf5de1 Parent ID : 779db508077de69f @@ -343,13 +343,13 @@ Span #8 Start time : 2026-04-03 06:48:41.447897088 +0000 UTC End time : 2026-04-03 06:48:47.139977728 +0000 UTC Status code : Unset - Status message : + Status message : Attributes: -> net.peer.ip: Str(172.18.0.2) -> net.peer.port: Double(10000) - -> net.peer.name: Str(a2a-currency-agent) + -> net.peer.name: Str(a2a-kongair-agent) -> try_count: Double(1) - -> peer.service: Str(a2a-currency-agent) + -> peer.service: Str(a2a-kongair-agent) ``` {:.collapsible} @@ -359,13 +359,13 @@ You should also see metrics data in the OpenTelemetry Collector output. Search f ``` ResourceMetrics #0 -Resource SchemaURL: +Resource SchemaURL: Resource attributes: -> service.instance.id: Str(9c214152-1621-456a-8b42-6f1309dac551) -> service.name: Str(kong-a2a) -> service.version: Str(3.14.0.0) ScopeMetrics #0 -ScopeMetrics SchemaURL: +ScopeMetrics SchemaURL: InstrumentationScope kong-internal 0.1.0 Metric #0 Descriptor: @@ -376,8 +376,8 @@ Descriptor: -> AggregationTemporality: Cumulative HistogramDataPoints #0 Data point attributes: - -> kong.service.name: Str(a2a-currency-agent) - -> kong.route.name: Str(a2a-route) + -> kong.service.name: Str(a2a-kongair-agent) + -> kong.route.name: Str(a2a-kongair-route) -> kong.gen_ai.a2a.method: Str(message/send) -> kong.workspace.name: Str(default) -> kong.gen_ai.a2a.binding: Str(jsonrpc) @@ -396,8 +396,8 @@ Descriptor: -> AggregationTemporality: Cumulative HistogramDataPoints #0 Data point attributes: - -> kong.service.name: Str(a2a-currency-agent) - -> kong.route.name: Str(a2a-route) + -> kong.service.name: Str(a2a-kongair-agent) + -> kong.route.name: Str(a2a-kongair-route) -> kong.gen_ai.a2a.method: Str(message/send) -> kong.workspace.name: Str(default) -> kong.gen_ai.a2a.binding: Str(jsonrpc) @@ -417,8 +417,8 @@ Descriptor: -> AggregationTemporality: Cumulative NumberDataPoints #0 Data point attributes: - -> kong.service.name: Str(a2a-currency-agent) - -> kong.route.name: Str(a2a-route) + -> kong.service.name: Str(a2a-kongair-agent) + -> kong.route.name: Str(a2a-kongair-route) -> kong.gen_ai.a2a.method: Str(message/send) -> kong.workspace.name: Str(default) -> kong.gen_ai.a2a.binding: Str(jsonrpc) @@ -436,8 +436,8 @@ Descriptor: NumberDataPoints #0 Data point attributes: -> kong.workspace.name: Str(default) - -> kong.service.name: Str(a2a-currency-agent) - -> kong.route.name: Str(a2a-route) + -> kong.service.name: Str(a2a-kongair-agent) + -> kong.route.name: Str(a2a-kongair-route) -> kong.gen_ai.a2a.task.state: Str(completed) StartTimestamp: 2026-04-03 06:40:44.824023552 +0000 UTC Timestamp: 2026-04-03 06:48:47.141275648 +0000 UTC diff --git a/app/_how-tos/ai-gateway/rate-limit-a2a-traffic.md b/app/_how-tos/ai-gateway/rate-limit-a2a-traffic.md index f2de9d5e36..9745e4167c 100644 --- a/app/_how-tos/ai-gateway/rate-limit-a2a-traffic.md +++ b/app/_how-tos/ai-gateway/rate-limit-a2a-traffic.md @@ -51,15 +51,15 @@ related_resources: prereqs: entities: services: - - a2a-currency-agent + - a2a-kongair-agent routes: - - a2a-route + - a2a-kongair-route inline: - title: OpenAI API key include_content: prereqs/openai icon_url: /assets/icons/openai.svg - title: A2A agent - include_content: prereqs/a2a-agent + include_content: prereqs/a2a-kongair-agent icon_url: /assets/icons/ai.svg cleanup: @@ -100,15 +100,6 @@ entities: log_payloads: true {% endentity_examples %} -## Enable the Key Auth plugin - -The [Key Auth plugin](/plugins/key-auth/) identifies callers and associates them with a Kong consumer. Rate Limiting Advanced uses this consumer identity to apply per-consumer limits. - -{% entity_examples %} -entities: - plugins: - - name: key-auth -{% endentity_examples %} ## Enable the Rate Limiting Advanced plugin @@ -124,7 +115,7 @@ entities: window_size: - 30 sync_rate: -1 - namespace: a2a-currency-agent + namespace: a2a-kongair-agent strategy: local {% endentity_examples %} @@ -139,6 +130,7 @@ Send an authenticated request to the agent card endpoint and inspect the respons {% validation request-check %} url: /a2a/.well-known/agent-card.json +display_headers: true status_code: 200 method: GET headers: diff --git a/app/_how-tos/ai-gateway/secure-a2a-traffic.md b/app/_how-tos/ai-gateway/secure-a2a-traffic.md index 85828ad22c..3dc3e988de 100644 --- a/app/_how-tos/ai-gateway/secure-a2a-traffic.md +++ b/app/_how-tos/ai-gateway/secure-a2a-traffic.md @@ -50,15 +50,15 @@ related_resources: prereqs: entities: services: - - a2a-currency-agent + - a2a-kongair-agent routes: - - a2a-route + - a2a-kongair-route inline: - title: OpenAI API key include_content: prereqs/openai icon_url: /assets/icons/openai.svg - title: A2A agent - include_content: prereqs/a2a-agent + include_content: prereqs/a2a-kongair-agent icon_url: /assets/icons/ai.svg cleanup: @@ -142,19 +142,10 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "What flights are available on route KA-123?" +message: "401 Unauthorized: No API key found in request" {% endvalidation %} - -The gateway responds with `401 Unauthorized`: - -``` -HTTP/2 401 -... -{ - "message":"No API key found in request" -} -``` {:.no-copy-code} ## Validate authenticated requests succeed @@ -180,7 +171,7 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "What flights are available on route KA-123?" {% endvalidation %} diff --git a/app/_how-tos/ai-gateway/secure-a2a-with-oidc.md b/app/_how-tos/ai-gateway/secure-a2a-with-oidc.md index 2e20f52f28..27051d2837 100644 --- a/app/_how-tos/ai-gateway/secure-a2a-with-oidc.md +++ b/app/_how-tos/ai-gateway/secure-a2a-with-oidc.md @@ -55,15 +55,15 @@ related_resources: prereqs: entities: services: - - a2a-currency-agent + - a2a-kongair-agent routes: - - a2a-route + - a2a-kongair-route inline: - title: OpenAI API key include_content: prereqs/openai icon_url: /assets/icons/openai.svg - title: A2A agent - include_content: prereqs/a2a-agent + include_content: prereqs/a2a-kongair-agent icon_url: /assets/icons/ai.svg - title: Okta include_content: prereqs/auth/oidc/okta-client-credentials @@ -111,7 +111,6 @@ Configure the [OpenID Connect plugin](/plugins/openid-connect/) on the A2A Route entities: plugins: - name: openid-connect - route: a2a-route config: issuer: ${okta_issuer} client_id: @@ -153,7 +152,7 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "What flights are available on route KA-123?" message: 401 Unauthorized {% endvalidation %} @@ -168,7 +167,7 @@ export TOKEN=$(curl -s -X POST \ -d "grant_type=client_credentials" \ -d "client_id=$DECK_OKTA_CLIENT_ID" \ -d "client_secret=$DECK_OKTA_CLIENT_SECRET" \ - -d "scope=api:access" | jq -r '.access_token') + | jq -r '.access_token') ``` Send the A2A request with the token: @@ -192,7 +191,7 @@ body: role: user parts: - kind: text - text: "How much is 100 USD in EUR?" + text: "What flights are available on route KA-123?" {% endvalidation %} diff --git a/app/_includes/prereqs/a2a-kongair-agent.md b/app/_includes/prereqs/a2a-kongair-agent.md new file mode 100644 index 0000000000..ef388c766f --- /dev/null +++ b/app/_includes/prereqs/a2a-kongair-agent.md @@ -0,0 +1,27 @@ +You need a running A2A-compliant agent. This guide uses a sample KongAir travel agent that uses OpenAI and LangGraph to answer flight route queries. + +Create a `docker-compose.yaml` file: + +```sh +cat <<'EOF' > docker-compose.yaml +services: + a2a-agent: + container_name: a2a-kongair-agent + image: ghcr.io/tomek-labuk/a2a-kongair-openai-agent:1.0.0 + environment: + - OPENAI_API_KEY=${DECK_OPENAI_API_KEY} + - OPENAI_MODEL=gpt-5-mini + - KONGAIR_BASE_URL=https://api.kong-air.com + - PUBLIC_AGENT_URL=http://localhost:10000 + ports: + - "10000:10000" +EOF +``` + +Start the agent: + +```sh +docker compose up -d +``` + +The agent listens on port 10000 and uses the A2A JSON-RPC protocol to handle flight route queries. In this guide, the gateway service points to `host.docker.internal:10000` instead of the container name because {{site.base_gateway}} runs in its own container with a separate DNS resolver.