mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-02-05 04:35:14 -05:00
add test and doc page
This commit is contained in:
@@ -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: "js-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: "js"
|
||||
_IMAGE: "node:22"
|
||||
_TARGET_ROOT: "docs/en/samples/pre_post_processing/js"
|
||||
_TABLE_NAME: "hotels_js_pre_post_processing"
|
||||
_SQL_FILE: ".ci/sample_tests/setup_hotels.sql"
|
||||
_AGENT_FILE_PATTERN: "agent.js"
|
||||
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
31
docs/en/samples/pre_post_processing/js.md
Normal file
31
docs/en/samples/pre_post_processing/js.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "(JS) Pre and post processing"
|
||||
type: docs
|
||||
weight: 5
|
||||
description: >
|
||||
How to add pre and post processing to your JS toolbox applications.
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This tutorial assumes that you have set up a basic toolbox application as described in the [local quickstart](../../getting-started/local_quickstart_js).
|
||||
|
||||
This guide demonstrates how to implement these patterns in your Toolbox applications.
|
||||
|
||||
## Implementation
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{% tab header="ADK" text=true %}}
|
||||
Coming soon.
|
||||
{{% /tab %}}
|
||||
{{% tab header="Langchain" text=true %}}
|
||||
The following example demonstrates how to use `ToolboxClient` with LangChain's middleware to implement pre and post processing for tool calls.
|
||||
|
||||
```js
|
||||
{{< include "js/langchain/agent.js" >}}
|
||||
```
|
||||
|
||||
For more information, see the [LangChain Middleware documentation](https://js.langchain.com/docs/introduction/middleware).
|
||||
You can also add model-level (`wrap_model`) and agent-level (`before_agent`, `after_agent`) hooks to intercept messages at different stages of the execution loop. See the [LangChain Middleware documentation](https://js.langchain.com/docs/introduction/middleware) for details on these additional hook types.
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
92
docs/en/samples/pre_post_processing/js/agent.test.js
Normal file
92
docs/en/samples/pre_post_processing/js/agent.test.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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.
|
||||
|
||||
import { describe, test, before, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const ORCH_NAME = process.env.ORCH_NAME;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const orchDir = path.join(__dirname, ORCH_NAME);
|
||||
const agentPath = path.join(orchDir, "agent.js");
|
||||
|
||||
const { main: runAgent } = await import(agentPath);
|
||||
|
||||
const GOLDEN_FILE_PATH = path.resolve(__dirname, "../golden.txt");
|
||||
|
||||
describe(`${ORCH_NAME} Pre/Post Processing Agent`, () => {
|
||||
let capturedOutput = [];
|
||||
let capturedErrors = [];
|
||||
let originalLog;
|
||||
let originalError;
|
||||
|
||||
before(() => {
|
||||
originalLog = console.log;
|
||||
originalError = console.error;
|
||||
|
||||
console.log = (...args) => {
|
||||
const msg = args.map(a => (typeof a === 'object' ? JSON.stringify(a, null, 2) : String(a))).join(' ');
|
||||
capturedOutput.push(msg);
|
||||
};
|
||||
|
||||
console.error = (...args) => {
|
||||
const msg = args.map(a => (typeof a === 'object' ? JSON.stringify(a, null, 2) : String(a))).join(' ');
|
||||
capturedErrors.push(msg);
|
||||
};
|
||||
});
|
||||
|
||||
after(() => {
|
||||
console.log = originalLog;
|
||||
console.error = originalError;
|
||||
});
|
||||
|
||||
test("runs without errors and outputContainsRequiredKeywords", async () => {
|
||||
capturedOutput = [];
|
||||
capturedErrors = [];
|
||||
|
||||
await runAgent();
|
||||
if (capturedErrors.length > 0) {
|
||||
console.error("Captured Stderr:", capturedErrors.join("\n"));
|
||||
}
|
||||
assert.equal(
|
||||
capturedErrors.length,
|
||||
0,
|
||||
`Script produced stderr: ${capturedErrors.join("\n")}`
|
||||
);
|
||||
|
||||
const actualOutput = capturedOutput.join("\n");
|
||||
|
||||
assert.ok(
|
||||
actualOutput.length > 0,
|
||||
"Assertion Failed: Script ran successfully but produced no output."
|
||||
);
|
||||
|
||||
const goldenFile = fs.readFileSync(GOLDEN_FILE_PATH, "utf8");
|
||||
const keywords = goldenFile.split("\n").filter((kw) => kw.trim() !== "");
|
||||
const missingKeywords = [];
|
||||
|
||||
for (const keyword of keywords) {
|
||||
if (!actualOutput.includes(keyword)) {
|
||||
missingKeywords.push(keyword);
|
||||
}
|
||||
}
|
||||
|
||||
assert.ok(
|
||||
missingKeywords.length === 0,
|
||||
`Assertion Failed: The following keywords were missing from the output: [${missingKeywords.join(", ")}]`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -159,4 +159,6 @@ async function main() {
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
main();
|
||||
}
|
||||
}
|
||||
|
||||
export { main };
|
||||
Reference in New Issue
Block a user