Compare commits

...

65 Commits

Author SHA1 Message Date
Twisha Bansal
79d34a0ca9 Merge branch 'main' into processing-adk-go 2026-02-12 11:47:02 +05:30
Twisha Bansal
2f3b69da7a gemini comments fix 2026-02-11 14:29:33 +05:30
Twisha Bansal
a0ef006898 fix print statement 2026-02-11 14:15:07 +05:30
Twisha Bansal
efdd10c2a3 fix image 2026-02-11 14:03:31 +05:30
Twisha Bansal
b21f4c3b5a go mod and sum files 2026-02-11 13:57:11 +05:30
Twisha Bansal
b108d7e251 add test file 2026-02-11 13:55:55 +05:30
Twisha Bansal
2502e1b862 add go files 2026-02-11 13:55:55 +05:30
Twisha Bansal
a6a24b5672 Merge branch 'main' into processing-adk-go 2026-02-11 13:42:01 +05:30
Twisha Bansal
bb3755aa23 Add working adk code 2026-02-10 21:40:00 +05:30
Twisha Bansal
79b5f22231 Merge branch 'main' into processing-docs 2026-02-10 21:38:54 +05:30
Twisha Bansal
9a24e13a32 Merge branch 'main' into processing-docs 2026-02-10 11:06:45 +05:30
Twisha Bansal
d49335ced5 Update python.md 2026-02-09 12:27:57 +05:30
Twisha Bansal
22657c9dad fix link checker issue 2026-02-09 11:42:44 +05:30
Twisha Bansal
d829ee7bdf Merge branch 'main' into processing-docs 2026-02-09 11:30:29 +05:30
Twisha Bansal
f598543ea4 remove extra print 2026-02-09 11:10:19 +05:30
Twisha Bansal
4885f6ebfb Merge branch 'main' into processing-docs 2026-02-09 11:07:37 +05:30
Twisha Bansal
77af793066 clarify description for pre and post processing. 2026-02-09 10:29:35 +05:30
Twisha Bansal
fe01519f61 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Averi Kitsch <akitsch@google.com>
2026-02-09 10:28:27 +05:30
Twisha Bansal
4d0a2ce038 Update docs/en/samples/pre_post_processing/python.md
Co-authored-by: Averi Kitsch <akitsch@google.com>
2026-02-09 10:25:10 +05:30
Twisha Bansal
126dbe0d90 Update docs/en/samples/pre_post_processing/python.md
Co-authored-by: Averi Kitsch <akitsch@google.com>
2026-02-09 10:24:42 +05:30
Twisha Bansal
1f79754866 use hyphens everywhere 2026-02-06 17:15:52 +05:30
Twisha Bansal
2ec6dac8bd address comments 2026-02-06 17:10:15 +05:30
Twisha Bansal
fad11de9ff use hugo notice 2026-02-06 16:52:39 +05:30
Twisha Bansal
35d5bd67e8 add license header 2026-02-06 16:40:52 +05:30
Twisha Bansal
eb8a46c175 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:39:03 +05:30
Twisha Bansal
c4f924e6f8 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:38:33 +05:30
Twisha Bansal
0fcf690d42 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:38:23 +05:30
Twisha Bansal
2564058fd9 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:37:58 +05:30
Twisha Bansal
2a8d6af4d1 Update docs/en/samples/pre_post_processing/_index.md
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:37:38 +05:30
Twisha Bansal
4dad163803 updated weight 2026-02-06 16:36:25 +05:30
Twisha Bansal
b5c55020c9 Apply suggestion from @Yuan325
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
2026-02-06 16:36:03 +05:30
Twisha Bansal
1dc3417557 Update golden.txt 2026-02-05 21:37:30 +05:30
Twisha Bansal
8ea10c2caf remove init file 2026-02-05 12:28:07 +05:30
Twisha Bansal
632dd10180 remove license header from docs 2026-02-05 12:14:23 +05:30
Twisha Bansal
9771aa47df Update python.md 2026-02-04 14:58:53 +05:30
Twisha Bansal
a212aedd19 more reliable tests 2026-02-03 18:30:33 +05:30
Twisha Bansal
9210e5555c unnecessary file change removal 2026-02-03 18:15:05 +05:30
Twisha Bansal
b43af71793 fix merge issues 2026-02-03 18:13:49 +05:30
Twisha Bansal
da1f463dd1 more reliable agent queries 2026-02-03 18:08:59 +05:30
Twisha Bansal
3265f7e3a6 better tests 2026-02-03 18:08:59 +05:30
Twisha Bansal
336743f747 add more test case + remove flaky test 2026-02-03 18:08:59 +05:30
Twisha Bansal
911069ae8d Fix tests 2026-02-03 18:08:58 +05:30
Twisha Bansal
cee59d52c3 update requirements file 2026-02-03 18:08:58 +05:30
Twisha Bansal
9517daba09 license fix 2026-02-03 18:08:57 +05:30
Twisha Bansal
3c61ee0597 add sample tests 2026-02-03 18:08:09 +05:30
Twisha Bansal
19271eb9ee docs: clarify that pre/post processing is an orchestration feature
Explicitly document that these capabilities are typically provided by orchestration frameworks (like LangChain, LangGraph) rather than the Toolbox SDK itself, but that Toolbox tools are designed to leverage them.
2026-02-03 18:08:09 +05:30
Twisha Bansal
3a150c77ca Highlight tool level processing 2026-02-03 18:08:09 +05:30
Twisha Bansal
ca6f31a192 fix import 2026-02-03 18:08:09 +05:30
Twisha Bansal
d7faf7700f logic fix 2026-02-03 18:08:09 +05:30
Twisha Bansal
37a60ea2a6 Update docs/en/samples/pre_post_processing/python/langchain/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 18:08:09 +05:30
Twisha Bansal
8de16976ae license header 2026-02-03 18:08:08 +05:30
Twisha Bansal
49cb2f39f7 lint 2026-02-03 18:08:08 +05:30
Twisha Bansal
f169874e53 gemini code review 2026-02-03 18:08:08 +05:30
Twisha Bansal
db8c3a3c77 remove not needed files 2026-02-03 18:08:08 +05:30
Twisha Bansal
8b33b0c67f docs: add pre/post processing docs for langchain python 2026-02-03 18:08:08 +05:30
Twisha Bansal
35fa73516b rename file 2026-02-03 15:45:03 +05:30
Twisha Bansal
66df3bfd21 move file around fix 2026-02-03 15:40:49 +05:30
Twisha Bansal
73e0edc3cd move files around 2026-02-03 15:36:56 +05:30
Twisha Bansal
3f32a9aab6 fix paths 2026-02-03 15:29:18 +05:30
Twisha Bansal
28006fc9b2 move files around 2026-02-03 15:27:43 +05:30
Twisha Bansal
56c69131b4 Update run_tests.sh 2026-02-03 15:09:07 +05:30
Twisha Bansal
ad4a509340 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:16:47 +05:30
Twisha Bansal
d39acac96c Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:16:36 +05:30
Twisha Bansal
6df2ad28a9 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:15:54 +05:30
Twisha Bansal
8416378613 refactor: consolidate quickstart tests into universal runner 2026-02-03 14:11:54 +05:30
6 changed files with 525 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
steps:
- name: "${_IMAGE}"
id: "go-pre-post-processing-test"
entrypoint: "bash"
args:
- -c
- |
set -ex
chmod +x .ci/sample_tests/run_tests.sh
.ci/sample_tests/run_tests.sh
env:
- "CLOUD_SQL_INSTANCE=${_CLOUD_SQL_INSTANCE}"
- "GCP_PROJECT=${_GCP_PROJECT}"
- "DATABASE_NAME=${_DATABASE_NAME}"
- "DB_USER=${_DB_USER}"
- "TARGET_ROOT=${_TARGET_ROOT}"
- "TARGET_LANG=${_TARGET_LANG}"
- "TABLE_NAME=${_TABLE_NAME}"
- "SQL_FILE=${_SQL_FILE}"
- "AGENT_FILE_PATTERN=${_AGENT_FILE_PATTERN}"
secretEnv: ["TOOLS_YAML_CONTENT", "GOOGLE_API_KEY", "DB_PASSWORD"]
availableSecrets:
secretManager:
- versionName: projects/${_GCP_PROJECT}/secrets/${_TOOLS_YAML_SECRET}/versions/5
env: "TOOLS_YAML_CONTENT"
- versionName: projects/${_GCP_PROJECT_NUMBER}/secrets/${_API_KEY_SECRET}/versions/latest
env: "GOOGLE_API_KEY"
- versionName: projects/${_GCP_PROJECT}/secrets/${_DB_PASS_SECRET}/versions/latest
env: "DB_PASSWORD"
timeout: 1200s
substitutions:
_TARGET_LANG: "go"
_IMAGE: "golang:1.25.1"
_TARGET_ROOT: "docs/en/samples/pre_post_processing/go"
_TABLE_NAME: "hotels_go_pre_post_processing"
_SQL_FILE: ".ci/sample_tests/setup_hotels.sql"
_AGENT_FILE_PATTERN: "agent.go"
options:
logging: CLOUD_LOGGING_ONLY

View File

@@ -0,0 +1,38 @@
---
title: "Go"
type: docs
weight: 3
description: >
How to add pre- and post- processing to your Agents using Go.
---
## Prerequisites
This tutorial assumes that you have set up Toolbox with a basic agent as described in the [local quickstart](../../getting-started/local_quickstart_go.md).
This guide demonstrates how to implement these patterns in your Toolbox applications.
## Implementation
{{< tabpane persist=header >}}
{{% tab header="ADK" text=true %}}
The following example demonstrates how to use the `beforeToolCallback` and `afterToolCallback` hooks in the ADK `LlmAgent` to implement pre and post processing logic.
```go
{{< include "go/adk/agent.go" >}}
```
You can also add model-level (`beforeModelCallback`, `afterModelCallback`) and agent-level (`beforeAgentCallback`, `afterAgentCallback`) hooks to intercept messages at different stages of the execution loop.
For more information, see the [ADK Callbacks documentation](https://google.github.io/adk-docs/callbacks/types-of-callbacks/).{{% /tab %}}
{{< /tabpane >}}
## Results
The output should look similar to the following. Note that exact responses may vary due to the non-deterministic nature of LLMs and differences between orchestration frameworks.
```
AI: Booking Confirmed! You earned 500 Loyalty Points with this stay.
AI: Error: Maximum stay duration is 14 days.
```

View File

@@ -0,0 +1,176 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/googleapis/mcp-toolbox-sdk-go/tbadk"
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/model/gemini"
"google.golang.org/adk/runner"
"google.golang.org/adk/session"
"google.golang.org/adk/tool"
"google.golang.org/genai"
)
const systemPrompt = `
You're a helpful hotel assistant. You handle hotel searching, booking and
cancellations. When the user searches for a hotel, mention it's name, id,
location and price tier. Always mention hotel ids while performing any
searches. This is very important for any operations. For any bookings or
cancellations, please provide the appropriate confirmation. Be sure to
update checkin or checkout dates if mentioned by the user.
Don't ask for confirmations from the user.
`
var queries = []string{
"Book hotel with id 3.",
"Update my hotel with id 3 with checkin date 2025-01-04 and checkout date 2025-01-20",
}
// Pre-processing
func beforeToolCallback(ctx tool.Context, tool tool.Tool, args map[string]any) (map[string]any, error) {
fmt.Printf("POLICY CHECK: Intercepting '%s'\n", tool.Name())
if tool.Name() == "update-hotel" {
checkinStr, okCheckin := args["checkin_date"].(string)
checkoutStr, okCheckout := args["checkout_date"].(string)
if okCheckin && okCheckout {
startDate, errStart := time.Parse("2006-01-02", checkinStr)
endDate, errEnd := time.Parse("2006-01-02", checkoutStr)
if errStart != nil || errEnd != nil {
return nil, nil
}
duration := endDate.Sub(startDate).Hours() / 24
if duration > 14 {
fmt.Println("BLOCKED: Stay too long")
return map[string]any{"Error": "Maximum stay duration is 14 days."}, nil
}
}
}
return nil, nil
}
// Post-processing
func afterToolCallback(ctx tool.Context, tool tool.Tool, args, result map[string]any, err error) (map[string]any, error) {
resultStr := fmt.Sprintf("%v", result)
if tool.Name() == "book-hotel" {
if err != nil {
return nil, err
}
if _, ok := result["Error"]; !ok && !strings.Contains(resultStr, "Error") {
const loyaltyBonus = 500
enrichedResult := fmt.Sprintf("Booking Confirmed!\n You earned %d Loyalty Points with this stay.\n\nSystem Details: %s", loyaltyBonus, resultStr)
return map[string]any{"confirmation": enrichedResult}, nil
}
}
return result, nil
}
func main() {
genaiKey := os.Getenv("GOOGLE_API_KEY")
toolboxURL := "http://localhost:5000"
ctx := context.Background()
toolboxClient, err := tbadk.NewToolboxClient(toolboxURL)
if err != nil {
log.Fatalf("Failed to create MCP Toolbox client: %v", err)
}
toolsetName := "my-toolset"
mcpTools, err := toolboxClient.LoadToolset(toolsetName, ctx)
if err != nil {
log.Fatalf("Failed to load MCP toolset '%s': %v\nMake sure your Toolbox server is running.", toolsetName, err)
}
model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
APIKey: genaiKey,
})
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
tools := make([]tool.Tool, len(mcpTools))
for i := range mcpTools {
tools[i] = &mcpTools[i]
}
llmagent, err := llmagent.New(llmagent.Config{
Name: "hotel_assistant",
Model: model,
Description: "Agent to answer questions about hotels.",
Instruction: systemPrompt,
Tools: tools,
// Add pre- and post- processing hooks
BeforeToolCallbacks: []llmagent.BeforeToolCallback{beforeToolCallback},
AfterToolCallbacks: []llmagent.AfterToolCallback{afterToolCallback},
})
if err != nil {
log.Fatalf("Failed to create agent: %v", err)
}
appName := "hotel_assistant"
userID := "user-123"
sessionService := session.InMemoryService()
respSess, err := sessionService.Create(ctx, &session.CreateRequest{
AppName: appName,
UserID: userID,
})
if err != nil {
log.Fatalf("Failed to create the session service: %v", err)
}
sess := respSess.Session
r, err := runner.New(runner.Config{
AppName: appName,
Agent: llmagent,
SessionService: sessionService,
})
if err != nil {
log.Fatalf("Failed to create runner: %v", err)
}
for i, query := range queries {
fmt.Printf("\n=== Query %d: %s ===\n", i+1, query)
userMsg := genai.NewContentFromText(query, genai.RoleUser)
streamingMode := agent.StreamingModeSSE
runIter := r.Run(ctx, userID, sess.ID(), userMsg, agent.RunConfig{
StreamingMode: streamingMode,
})
fmt.Print("AI: ")
for event := range runIter {
if event != nil && event.LLMResponse.Content != nil {
for _, p := range event.LLMResponse.Content.Parts {
fmt.Print(p.Text)
}
}
}
fmt.Println("\n" + strings.Repeat("-", 80) + "\n")
}
}

View File

@@ -0,0 +1,44 @@
module example.com/adk-agent
go 1.24.4
require (
github.com/googleapis/mcp-toolbox-sdk-go v0.5.1
google.golang.org/adk v0.3.0
google.golang.org/genai v1.43.0
)
require (
cloud.google.com/go v0.123.0 // indirect
cloud.google.com/go/auth v0.18.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/safehtml v0.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect
github.com/googleapis/gax-go/v2 v2.16.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/api v0.263.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d // indirect
google.golang.org/grpc v1.78.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
rsc.io/omap v1.2.0 // indirect
rsc.io/ordered v1.1.1 // indirect
)

View File

@@ -0,0 +1,132 @@
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs=
cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=
cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=
cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=
cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=
cloud.google.com/go/secretmanager v1.16.0 h1:19QT7ZsLJ8FSP1k+4esQvuCD7npMJml6hYzilxVyT+k=
cloud.google.com/go/secretmanager v1.16.0/go.mod h1://C/e4I8D26SDTz1f3TQcddhcmiC3rMEl0S1Cakvs3Q=
cloud.google.com/go/storage v1.59.2 h1:gmOAuG1opU8YvycMNpP+DvHfT9BfzzK5Cy+arP+Nocw=
cloud.google.com/go/storage v1.59.2/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM=
github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo=
github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8=
github.com/google/safehtml v0.1.0/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao=
github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8=
github.com/googleapis/gax-go/v2 v2.16.0 h1:iHbQmKLLZrexmb0OSsNGTeSTS0HO4YvFOG8g5E4Zd0Y=
github.com/googleapis/gax-go/v2 v2.16.0/go.mod h1:o1vfQjjNZn4+dPnRdl/4ZD7S9414Y4xA+a/6Icj6l14=
github.com/googleapis/mcp-toolbox-sdk-go v0.5.1 h1:Jc7IUlVoitpkWK+21ccmzg+213Nv9lyN0tHXv16JPsQ=
github.com/googleapis/mcp-toolbox-sdk-go v0.5.1/go.mod h1:wjOHkYUVD8TwLcAaSbubKj6kY8pfMVCEIxy2OzL4Fu0=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/adk v0.3.0 h1:gitgAKnET1F1+fFZc7VSAEo7cjK+D39mnRyqIRTzyzY=
google.golang.org/adk v0.3.0/go.mod h1:iE1Kgc8JtYHiNxfdLa9dxcV4DqTn0D8q4eqhBi012Ak=
google.golang.org/api v0.263.0 h1:UFs7qn8gInIdtk1ZA6eXRXp5JDAnS4x9VRsRVCeKdbk=
google.golang.org/api v0.263.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8=
google.golang.org/genai v1.43.0 h1:8vhqhzJNZu1U94e2m+KvDq/TUUjSmDrs1aKkvTa8SoM=
google.golang.org/genai v1.43.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217 h1:GvESR9BIyHUahIb0NcTum6itIWtdoglGX+rnGxm2934=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:yJ2HH4EHEDTd3JiLmhds6NkJ17ITVYOdV3m3VKOnws0=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d h1:xXzuihhT3gL/ntduUZwHECzAn57E8dA6l8SOtYWdD8Q=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/omap v1.2.0 h1:c1M8jchnHbzmJALzGLclfH3xDWXrPxSUHXzH5C+8Kdw=
rsc.io/omap v1.2.0/go.mod h1:C8pkI0AWexHopQtZX+qiUeJGzvc8HkdgnsWK4/mAa00=
rsc.io/ordered v1.1.1 h1:1kZM6RkTmceJgsFH/8DLQvkCVEYomVDJfBRLT595Uak=
rsc.io/ordered v1.1.1/go.mod h1:evAi8739bWVBRG9aaufsjVc202+6okf8u2QeVL84BCM=

View File

@@ -0,0 +1,78 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestQuickstartSample(t *testing.T) {
framework := os.Getenv("ORCH_NAME")
if framework == "" {
t.Skip("Skipping test: ORCH_NAME environment variable is not set.")
}
t.Logf("--- Testing: %s ---", framework)
if os.Getenv("GOOGLE_API_KEY") == "" {
t.Skipf("Skipping test for %s: GOOGLE_API_KEY environment variable is not set.", framework)
}
sampleDir := filepath.Join(".", framework)
if _, err := os.Stat(sampleDir); os.IsNotExist(err) {
t.Fatalf("Test setup failed: directory for framework '%s' not found.", framework)
}
cmd := exec.Command("go", "run", ".")
cmd.Dir = sampleDir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
actualOutput := stdout.String()
if err != nil {
t.Fatalf("Script execution failed with error: %v\n--- STDERR ---\n%s", err, stderr.String())
}
if len(actualOutput) == 0 {
t.Fatal("Script ran successfully but produced no output.")
}
goldenKeywords := []string{
"AI:",
"Loyalty Points",
"POLICY CHECK: Intercepting 'update-hotel'",
}
var missingKeywords []string
outputLower := strings.ToLower(actualOutput)
for _, keyword := range goldenKeywords {
kw := strings.TrimSpace(keyword)
if kw != "" && !strings.Contains(outputLower, strings.ToLower(kw)) {
missingKeywords = append(missingKeywords, kw)
}
}
if len(missingKeywords) > 0 {
t.Fatalf("FAIL: The following keywords were missing from the output: [%s]", strings.Join(missingKeywords, ", "))
}
}