diff --git a/.github/workflows/link_checker.yaml b/.github/workflows/link_checker.yaml
index 308d482ca17..b08757dc628 100644
--- a/.github/workflows/link_checker.yaml
+++ b/.github/workflows/link_checker.yaml
@@ -114,7 +114,7 @@ jobs:
- name: Create PR Comment
if: env.HAS_CHANGES == 'true' && steps.lychee-check.outcome == 'failure'
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
+ uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
diff --git a/docs/en/getting-started/quickstart/js/genkit/package-lock.json b/docs/en/getting-started/quickstart/js/genkit/package-lock.json
index cdb5744245c..436ecf3b6f6 100644
--- a/docs/en/getting-started/quickstart/js/genkit/package-lock.json
+++ b/docs/en/getting-started/quickstart/js/genkit/package-lock.json
@@ -3231,9 +3231,10 @@
}
},
"node_modules/ajv": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
- "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
+ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
+ "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
diff --git a/docs/en/resources/sources/postgres.md b/docs/en/resources/sources/postgres.md
index ed7c77aeee2..c42d8dca644 100644
--- a/docs/en/resources/sources/postgres.md
+++ b/docs/en/resources/sources/postgres.md
@@ -133,3 +133,4 @@ instead of hardcoding your secrets into the configuration file.
| user | string | true | Name of the Postgres user to connect as (e.g. "my-pg-user"). |
| password | string | true | Password of the Postgres user (e.g. "my-password"). |
| queryParams | map[string]string | false | Raw query to be added to the db connection string. |
+| queryExecMode | string | false | pgx query execution mode. Valid values: `cache_statement` (default), `cache_describe`, `describe_exec`, `exec`, `simple_protocol`. Useful with connection poolers that don't support prepared statement caching. |
diff --git a/docs/en/resources/sources/redis.md b/docs/en/resources/sources/redis.md
index 51c8cfde00e..62ca36be704 100644
--- a/docs/en/resources/sources/redis.md
+++ b/docs/en/resources/sources/redis.md
@@ -4,8 +4,8 @@ linkTitle: "Redis"
type: docs
weight: 1
description: >
- Redis is a in-memory data structure store.
-
+ Redis is a in-memory data structure store.
+
---
## About
@@ -44,6 +44,9 @@ password: ${MY_AUTH_STRING} # Omit this field if you don't have a password.
# database: 0
# clusterEnabled: false
# useGCPIAM: false
+# tls:
+# enabled: false
+# insecureSkipVerify: false
```
{{< notice tip >}}
@@ -61,7 +64,7 @@ Here is an example tools.yaml config with [AUTH][auth] enabled:
```yaml
kind: sources
name: my-redis-cluster-instance
-type: memorystore-redis
+type: redis
address:
- 127.0.0.1:6379
password: ${MY_AUTH_STRING}
@@ -78,7 +81,7 @@ using IAM authentication:
```yaml
kind: sources
name: my-redis-cluster-instance
-type: memorystore-redis
+type: redis
address:
- 127.0.0.1:6379
useGCPIAM: true
@@ -89,14 +92,16 @@ clusterEnabled: true
## Reference
-| **field** | **type** | **required** | **description** |
-|----------------|:--------:|:------------:|---------------------------------------------------------------------------------------------------------------------------------|
-| type | string | true | Must be "memorystore-redis". |
-| address | string | true | Primary endpoint for the Memorystore Redis instance to connect to. |
-| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Redis, leave this field blank |
-| password | string | false | If you have [Redis AUTH][auth] enabled, specify the AUTH string here |
-| database | int | false | The Redis database to connect to. Not applicable for cluster enabled instances. The default database is `0`. |
-| clusterEnabled | bool | false | Set it to `true` if using a Redis Cluster instance. Defaults to `false`. |
-| useGCPIAM | string | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. |
+| **field** | **type** | **required** | **description** |
+|------------------------|:--------:|:------------:|-----------------------------------------------------------------------------------------------------------------------------------------------|
+| type | string | true | Must be "redis". |
+| address | string | true | Primary endpoint for the Memorystore Redis instance to connect to. |
+| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Redis, leave this field blank |
+| password | string | false | If you have [Redis AUTH][auth] enabled, specify the AUTH string here |
+| database | int | false | The Redis database to connect to. Not applicable for cluster enabled instances. The default database is `0`. |
+| tls.enabled | bool | false | Set it to `true` to enable TLS for the Redis connection. Defaults to `false`. |
+| tls.insecureSkipVerify | bool | false | Set it to `true` to skip TLS certificate verification. **Warning:** This is insecure and not recommended for production. Defaults to `false`. |
+| clusterEnabled | bool | false | Set it to `true` if using a Redis Cluster instance. Defaults to `false`. |
+| useGCPIAM | bool | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. |
[auth]: https://cloud.google.com/memorystore/docs/redis/about-redis-auth
diff --git a/docs/en/samples/pre_post_processing/js/langchain/package-lock.json b/docs/en/samples/pre_post_processing/js/langchain/package-lock.json
index 8eed2a79ea8..27ed1a7601e 100644
--- a/docs/en/samples/pre_post_processing/js/langchain/package-lock.json
+++ b/docs/en/samples/pre_post_processing/js/langchain/package-lock.json
@@ -217,13 +217,13 @@
"license": "MIT"
},
"node_modules/axios": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz",
- "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==",
+ "version": "1.13.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
+ "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.4",
+ "follow-redirects": "^1.15.11",
+ "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
@@ -1598,17 +1598,6 @@
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
- },
- "node_modules/zod-to-json-schema": {
- "version": "3.25.1",
- "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz",
- "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==",
- "license": "ISC",
- "optional": true,
- "peer": true,
- "peerDependencies": {
- "zod": "^3.25 || ^4"
- }
}
}
}
diff --git a/internal/server/static/css/style.css b/internal/server/static/css/style.css
index 47d8a35974b..b0c1968c1b6 100644
--- a/internal/server/static/css/style.css
+++ b/internal/server/static/css/style.css
@@ -87,8 +87,29 @@ body {
display: flex;
flex-direction: column;
padding: 15px;
- align-items: center;
+ align-items: stretch;
position: relative;
+ min-width: 200px;
+ max-width: 50vw;
+ overflow: visible;
+ box-sizing: border-box;
+}
+
+.resize-handle {
+ position: absolute;
+ right: -2px;
+ top: 0;
+ bottom: 0;
+ width: 4px;
+ cursor: ew-resize;
+ background-color: transparent;
+ z-index: 10;
+ transition: background-color 0.2s ease;
+}
+
+.resize-handle:hover,
+.resize-handle.active {
+ background-color: var(--toolbox-blue);
}
.nav-logo {
@@ -626,10 +647,13 @@ body {
.search-container {
display: flex;
width: 100%;
+ min-width: 0;
margin-bottom: 15px;
+ box-sizing: border-box;
#toolset-search-input {
- flex-grow: 1;
+ flex: 1;
+ min-width: 0;
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 20px 0 0 20px;
@@ -637,6 +661,7 @@ body {
font-family: inherit;
font-size: 0.9em;
color: var(--text-primary-gray);
+ box-sizing: border-box;
&:focus {
outline: none;
diff --git a/internal/server/static/js/resize.js b/internal/server/static/js/resize.js
new file mode 100644
index 00000000000..f2ff490fe33
--- /dev/null
+++ b/internal/server/static/js/resize.js
@@ -0,0 +1,116 @@
+// Copyright 2025 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.
+
+const STORAGE_KEY = 'toolbox-second-nav-width';
+const DEFAULT_WIDTH = 250;
+const MIN_WIDTH = 200;
+const MAX_WIDTH_PERCENT = 50;
+
+/**
+ * Creates and attaches a resize handle to the second navigation panel
+ */
+export function initializeResize() {
+ const secondNav = document.querySelector('.second-nav');
+ if (!secondNav) {
+ return;
+ }
+
+ // Create resize handle
+ const resizeHandle = document.createElement('div');
+ resizeHandle.className = 'resize-handle';
+ resizeHandle.setAttribute('aria-label', 'Resize panel');
+ secondNav.appendChild(resizeHandle);
+
+ // Load saved width or use default
+ let initialWidth = DEFAULT_WIDTH;
+ try {
+ const savedWidth = localStorage.getItem(STORAGE_KEY);
+ if (savedWidth) {
+ const parsed = parseInt(savedWidth, 10);
+ if (!isNaN(parsed) && parsed >= MIN_WIDTH) {
+ initialWidth = parsed;
+ }
+ }
+ } catch (e) {
+ // localStorage may be unavailable in private browsing mode
+ console.warn('Failed to load saved panel width:', e);
+ }
+ setPanelWidth(secondNav, initialWidth);
+
+ // Setup resize functionality
+ let startX = 0;
+ let startWidth = 0;
+
+ const onMouseMove = (e) => {
+ const deltaX = e.clientX - startX;
+ const newWidth = startWidth + deltaX;
+ const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100;
+
+ const clampedWidth = Math.max(MIN_WIDTH, Math.min(newWidth, maxWidth));
+ setPanelWidth(secondNav, clampedWidth);
+ };
+
+ const onMouseUp = () => {
+ document.removeEventListener('mousemove', onMouseMove);
+ document.removeEventListener('mouseup', onMouseUp);
+
+ resizeHandle.classList.remove('active');
+ document.body.style.cursor = '';
+ document.body.style.userSelect = '';
+
+ // Save width to localStorage
+ try {
+ localStorage.setItem(STORAGE_KEY, secondNav.offsetWidth.toString());
+ } catch (e) {
+ // localStorage may be unavailable in private browsing mode
+ console.warn('Failed to save panel width:', e);
+ }
+ };
+
+ resizeHandle.addEventListener('mousedown', (e) => {
+ startX = e.clientX;
+ startWidth = secondNav.offsetWidth;
+ resizeHandle.classList.add('active');
+ document.body.style.cursor = 'ew-resize';
+ document.body.style.userSelect = 'none';
+ e.preventDefault();
+
+ document.addEventListener('mousemove', onMouseMove);
+ document.addEventListener('mouseup', onMouseUp);
+ });
+
+ // Handle window resize to enforce max width
+ window.addEventListener('resize', () => {
+ const currentWidth = secondNav.offsetWidth;
+ const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100;
+
+ if (currentWidth > maxWidth) {
+ setPanelWidth(secondNav, maxWidth);
+ try {
+ localStorage.setItem(STORAGE_KEY, maxWidth.toString());
+ } catch (e) {
+ // localStorage may be unavailable in private browsing mode
+ console.warn('Failed to save panel width:', e);
+ }
+ }
+ });
+}
+
+/**
+ * Sets the width of the panel and updates flex property
+ */
+function setPanelWidth(panel, width) {
+ panel.style.flex = `0 0 ${width}px`;
+}
+
diff --git a/internal/server/static/tools.html b/internal/server/static/tools.html
index c618c5111b4..f461cc80ad5 100644
--- a/internal/server/static/tools.html
+++ b/internal/server/static/tools.html
@@ -22,12 +22,16 @@
-