diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 7a20596e2a..53b1ddd1f2 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -46,6 +46,13 @@ reviews: # Default: true review_status: false # current: true path_instructions: + - path: "fern/docs.yml" + instructions: | + Redirect destinations for documentation pages must use the rendered Fern route from docs/index.yml, not the source file path. + In docs/index.yml, the rendered URL comes from the section/page `slug` hierarchy; the `path` field only points to the source MDX file. + For example, the source path docs/configure-rails/colang/colang-2/language-reference/introduction.mdx renders under /configure-guardrails/colang/colang-2/language-reference/introduction because the top-level Configure Guardrails section has slug `configure-guardrails`. + Do not suggest replacing valid rendered routes such as /configure-guardrails/... with source-path-derived routes such as /configure-rails/.... + Before flagging a redirect destination as wrong, verify the route by tracing the relevant entries in docs/index.yml. - path: "docs/**/*.mdx" instructions: | Internal absolute documentation links in Fern MDX pages must use the rendered Fern route, not the source file path. @@ -54,7 +61,7 @@ reviews: - docs/configure-rails/colang/index.mdx renders at /configure-guardrails/colang, not /configure-rails/colang. - docs/run-rails/index.mdx renders at /run-guardrailed-inference/run-rails, not /run-rails. - docs/getting-started/installation-guide.mdx renders at /get-started/installation-guide, not /getting-started/installation-guide. - Before flagging or suggesting fixes for internal docs links, verify them with scripts/check-docs-links.sh or docs/index.yml. + Before flagging or suggesting fixes for internal docs links, verify them with docs/index.yml. Do not suggest changing valid Fern routes back to source-path-style links. - path: "docs/**/*.ipynb" instructions: | diff --git a/.github/workflows/docs-links-pr.yaml b/.github/workflows/docs-links-pr.yaml deleted file mode 100644 index 0c67ca07d4..0000000000 --- a/.github/workflows/docs-links-pr.yaml +++ /dev/null @@ -1,146 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -name: Docs / Link Check - -on: - pull_request: - branches: [develop] - types: [opened, reopened, synchronize] - paths: - - "**/*.md" - - "**/*.mdx" - - "docs/index.yml" - - ".github/workflows/docs-links-pr.yaml" - - "scripts/check-docs-links.sh" - -permissions: - contents: read - -jobs: - markdown-links: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - - - name: Determine changed documentation files - id: changed - shell: bash - run: | - set -euo pipefail - base="${{ github.event.pull_request.base.sha }}" - head="${{ github.event.pull_request.head.sha }}" - mapfile -t doc_files < <( - # Fern validates MDX routes during the docs build. This raw - # Markdown job only checks repository-local .md links. - git diff --name-only --diff-filter=ACMR "$base" "$head" -- \ - '*.md' \ - ':(exclude)node_modules/**' \ - ':(exclude)dist/**' \ - ':(exclude)vendor/**' \ - ':(exclude)build/**' \ - | LC_ALL=C sort -u - ) - - if [[ "${#doc_files[@]}" -eq 0 ]]; then - echo "has_files=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "has_files=true" >> "$GITHUB_OUTPUT" - { - echo "files<> "$GITHUB_OUTPUT" - - - name: Run markdown link checker - if: steps.changed.outputs.has_files == 'true' - shell: bash - run: | - set -euo pipefail - mapfile -t doc_files <<< "${{ steps.changed.outputs.files }}" - bash scripts/check-docs-links.sh --local-only "${doc_files[@]}" - - fern-links: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - - - name: Determine changed Fern documentation files - id: changed - shell: bash - run: | - set -euo pipefail - base="${{ github.event.pull_request.base.sha }}" - head="${{ github.event.pull_request.head.sha }}" - mapfile -t changed_files < <( - git diff --name-only --diff-filter=ACMR "$base" "$head" -- \ - '*.mdx' \ - 'docs/index.yml' \ - 'scripts/check-docs-links.sh' \ - ':(exclude)docs/_static/python-sdk-reference/**' \ - ':(exclude)node_modules/**' \ - ':(exclude)dist/**' \ - ':(exclude)vendor/**' \ - ':(exclude)build/**' \ - | LC_ALL=C sort -u - ) - - full_scan=false - fern_files=() - for file in "${changed_files[@]}"; do - case "$file" in - docs/index.yml | scripts/check-docs-links.sh) - full_scan=true - ;; - *.mdx) - fern_files+=("$file") - ;; - esac - done - - if [[ "$full_scan" == "false" && "${#fern_files[@]}" -eq 0 ]]; then - echo "has_files=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "has_files=true" >> "$GITHUB_OUTPUT" - echo "full_scan=$full_scan" >> "$GITHUB_OUTPUT" - { - echo "files<> "$GITHUB_OUTPUT" - - - name: Run Fern route link checker - if: steps.changed.outputs.has_files == 'true' - shell: bash - run: | - set -euo pipefail - if [[ "${{ steps.changed.outputs.full_scan }}" == "true" ]]; then - bash scripts/check-docs-links.sh --local-only - else - mapfile -t fern_files <<< "${{ steps.changed.outputs.files }}" - bash scripts/check-docs-links.sh --local-only "${fern_files[@]}" - fi diff --git a/Makefile b/Makefile index 82349f1f1b..2e2621ea2d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: help .PHONY: test test-parallel test-serial test-benchmark test-watch test-coverage test-profile warm-fastembed-cache -.PHONY: docs-fern docs-fern-strict docs-fern-live docs-fern-preview-watch docs-fern-generate-sdk docs-fern-fix-empty-links docs-check-links docs-check-redirects docs-fern-publish-staging docs-fern-publish-public +.PHONY: docs-fern docs-fern-strict docs-fern-live docs-fern-preview-watch docs-fern-generate-sdk docs-fern-fix-empty-links docs-check-redirects docs-fern-publish-staging docs-fern-publish-public .PHONY: pre-commit .DEFAULT_GOAL := help @@ -70,9 +70,6 @@ docs-fern-generate-sdk: docs-fern-fix-empty-links: node scripts/fix-empty-fern-links.mjs -docs-check-links: - bash scripts/check-docs-links.sh --local-only - docs-check-redirects: cd docs && poetry run python scripts/validate_redirects.py @@ -109,7 +106,6 @@ help: ' docs-fern-preview-watch Watch and publish Fern preview for the current branch' \ ' docs-fern-generate-sdk Regenerate Python SDK reference pages with Fern' \ ' docs-fern-fix-empty-links Replace empty Markdown links with titles from Fern navigation' \ - ' docs-check-links Validate Markdown and MDX links locally' \ ' docs-check-redirects Validate docs redirects' \ '' \ 'Maintenance:' \ diff --git a/docs/about/release-notes.mdx b/docs/about/release-notes.mdx index a169842316..bdf4c6f46f 100644 --- a/docs/about/release-notes.mdx +++ b/docs/about/release-notes.mdx @@ -6,8 +6,9 @@ sidebar-title: "Release Notes" description: "Review new features, breaking changes, and fixed issues for each release." keywords: ["nemo guardrails changelog", "release notes", "version history"] content: - type: "reference" + type: "reference" --- + The following sections summarize and highlight the changes for each release. For a complete record of changes in a release, refer to the [CHANGELOG.md](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/CHANGELOG.md) in the GitHub repository. @@ -118,14 +119,13 @@ For a complete record of changes in a release, refer to the --- -## Previous Release Notes - -- [0.21.0](https://docs.nvidia.com/nemo/guardrails/0.21.0/release-notes.html) -- [0.20.0](https://docs.nvidia.com/nemo/guardrails/0.20.0/release-notes.html) -- [0.19.0](https://docs.nvidia.com/nemo/guardrails/0.19.0/release-notes.html) -- [0.18.0](https://docs.nvidia.com/nemo/guardrails/0.18.0/release-notes.html) -- [0.17.0](https://docs.nvidia.com/nemo/guardrails/0.17.0/release-notes.html) -- [0.16.0](https://docs.nvidia.com/nemo/guardrails/0.16.0/release-notes.html) -- [0.15.0](https://docs.nvidia.com/nemo/guardrails/0.15.0/release-notes.html) -- [0.14.1](https://docs.nvidia.com/nemo/guardrails/0.14.1/release-notes.html) -- [0.14.0](https://docs.nvidia.com/nemo/guardrails/0.14.0/release-notes.html) +## Previous Releases + +- [0.21.0](https://archive.docs.nvidia.com/nemo/guardrails/0.21.0/index.html) +- [0.20.0](https://archive.docs.nvidia.com/nemo/guardrails/0.20.0/index.html) +- [0.19.0](https://archive.docs.nvidia.com/nemo/guardrails/0.19.0/index.html) +- [0.18.0](https://archive.docs.nvidia.com/nemo/guardrails/0.18.0/index.html) +- [0.17.0](https://archive.docs.nvidia.com/nemo/guardrails/0.17.0/index.html) +- [0.16.0](https://archive.docs.nvidia.com/nemo/guardrails/0.16.0/index.html) +- [0.15.0](https://archive.docs.nvidia.com/nemo/guardrails/0.15.0/index.html) +- [0.14.1](https://archive.docs.nvidia.com/nemo/guardrails/0.14.1/index.html) diff --git a/docs/configure-rails/colang/colang-2/getting-started/dialog-rails.mdx b/docs/configure-rails/colang/colang-2/getting-started/dialog-rails.mdx index 8ff43a77f5..75df1d95fd 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/dialog-rails.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/dialog-rails.mdx @@ -42,14 +42,14 @@ flow bot express greeting ``` -The recommended practice is to use past tense for matching external actions, like the user saying something, and present for bot actions that must be executed. See [Defining Flows](../language-reference/defining-flows#flow-naming-conventions) for more details. +The recommended practice is to use past tense for matching external actions, like the user saying something, and present for bot actions that must be executed. See [Defining Flows](/configure-guardrails/colang/colang-2/language-reference/defining-flows#flow-naming-conventions) for more details. ## LLM Integration While the example above has more structure, it is still rigid in the sense that it only works with the exact inputs "hi" and "hello". -To enable the use of the LLM to drive the interaction for inputs that are not matched exactly by flows, you have to *activate* the `llm continuation` flow, which is part of the `llm` module in the [Colang Standard Library (CSL)](../language-reference/the-standard-library#the-standard-library). +To enable the use of the LLM to drive the interaction for inputs that are not matched exactly by flows, you have to *activate* the `llm continuation` flow, which is part of the `llm` module in the [Colang Standard Library (CSL)](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library). **examples/v2_x/tutorial/hello_world_3/main.co** diff --git a/docs/configure-rails/colang/colang-2/getting-started/hello-world.mdx b/docs/configure-rails/colang/colang-2/getting-started/hello-world.mdx index c3065cb0cd..991feaea9e 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/hello-world.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/hello-world.mdx @@ -27,7 +27,7 @@ flow main ``` -You can find the full example from this guide [here](../../../../../examples/v2_x/tutorial/hello_world_1). +You can find the full example from this guide [here](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/examples/v2_x/tutorial/hello_world_1). The achieve this, the `main` flow uses two pre-defined flows: @@ -39,7 +39,7 @@ The two flows are located in the `core` module, included in the Colang Standard -For more details, check out the [Colang Standard Library (CSL)](../language-reference/the-standard-library#the-standard-library). +For more details, check out the [Colang Standard Library (CSL)](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library). ## Testing diff --git a/docs/configure-rails/colang/colang-2/getting-started/index.mdx b/docs/configure-rails/colang/colang-2/getting-started/index.mdx index 8cb966bc03..c93bb39df1 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/index.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/index.mdx @@ -26,11 +26,11 @@ models: engine: openai model: gpt-4-turbo ``` -The above config sets the Colang version to "2.x" (this is needed since "1.0" is currently the default) and the LLM engine to OpenAI's `gpt-4-turbo`. Make sure to set the required API access key as an environment variable (e.g. OPENAI_API_KEY for OpenAI API). See section [Supported Models](../language-reference/make-use-of-llms#make-use-of-llms-supported-models) for all supported models. +The above config sets the Colang version to "2.x" (this is needed since "1.0" is currently the default) and the LLM engine to OpenAI's `gpt-4-turbo`. Make sure to set the required API access key as an environment variable (e.g. OPENAI_API_KEY for OpenAI API). See section [Supported Models](/configure-guardrails/colang/colang-2/language-reference/make-use-of-llms#make-use-of-llms-supported-models) for all supported models. -Check the section [Development and Debugging](../language-reference/development-and-debugging#development-and-debugging) for how you can install Colang syntax highlighting to make editing Colang scripts easier. +Check the section [Development and Debugging](/configure-guardrails/colang/colang-2/language-reference/development-and-debugging#development-and-debugging) for how you can install Colang syntax highlighting to make editing Colang scripts easier. ## Terminology @@ -40,43 +40,43 @@ At a high level, Colang adopts as much as possible from the Python terminology. ## Guides - + Create the first Colang 2.0 flow. - + Add dialog rails with LLM integration. - + Use multimodal events and actions. - + Add input rails to inspect and block user input. - + Build a simple interaction loop. - + Let the LLM generate flow continuations. - + Choose what to learn after the getting started guide. diff --git a/docs/configure-rails/colang/colang-2/getting-started/input-rails.mdx b/docs/configure-rails/colang/colang-2/getting-started/input-rails.mdx index de8dbc99da..a56778fdbd 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/input-rails.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/input-rails.mdx @@ -19,7 +19,7 @@ This section explains how to create *input rails* in Colang 2.0. To activate input rails in Colang 2.0, you must: -1. Import the `guardrails` module from the [Colang Standard Library (CSL)](../language-reference/the-standard-library#the-standard-library). +1. Import the `guardrails` module from the [Colang Standard Library (CSL)](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library). 2. Define a flow called `input rails`, which takes a single parameter called `$input_text`. In the example below, the `input rails` flow calls another flow named `check user message` which prompts the LLM to check the input. diff --git a/docs/configure-rails/colang/colang-2/getting-started/multimodal-rails.mdx b/docs/configure-rails/colang/colang-2/getting-started/multimodal-rails.mdx index ceccb059da..1cbc37e0c1 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/multimodal-rails.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/multimodal-rails.mdx @@ -19,7 +19,7 @@ The example below shows how you can control the greeting behavior of an interact -The [Colang Standard Library (CSL)](../language-reference/the-standard-library#the-standard-library) includes an `avatars` module with flows for multimodal events and actions to implement interactive avatars use cases. +The [Colang Standard Library (CSL)](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library) includes an `avatars` module with flows for multimodal events and actions to implement interactive avatars use cases. **examples/v2_x/tutorial/multi_modal/main.co** diff --git a/docs/configure-rails/colang/colang-2/getting-started/recommended-next-steps.mdx b/docs/configure-rails/colang/colang-2/getting-started/recommended-next-steps.mdx index a868545b10..0f7c2061f3 100644 --- a/docs/configure-rails/colang/colang-2/getting-started/recommended-next-steps.mdx +++ b/docs/configure-rails/colang/colang-2/getting-started/recommended-next-steps.mdx @@ -12,6 +12,6 @@ The Colang 2.0 getting started guide introduces you to a basic [Hello World](hel This only scratches the surface of what can be achieved with Colang 2.0. -If you are an experienced developer and want to learn about the syntax and various features in details, we recommend going through the [Language Reference](../language-reference/index#colang_2_language_reference) documentation. +If you are an experienced developer and want to learn about the syntax and various features in details, we recommend going through the [Language Reference](/configure-guardrails/colang/colang-2/language-reference#colang_2_language_reference) documentation. Version `0.10.0` of NeMo Guardrails will add more examples including RAG and agents. Also it will bring support for the Guardrails Library, which will enable you to use any of the existing guardrails similar to Colang 1.0. diff --git a/docs/configure-rails/colang/colang-2/index.mdx b/docs/configure-rails/colang/colang-2/index.mdx index c89963bee0..c04e3c62b8 100644 --- a/docs/configure-rails/colang/colang-2/index.mdx +++ b/docs/configure-rails/colang/colang-2/index.mdx @@ -12,25 +12,25 @@ Use this guide to review what changed from Colang 1.0, migrate existing configur - + Review the main language and runtime changes in Colang 2.0. - + Convert Colang 1.0 configurations to Colang 2.x. - + Work through the Colang 2.0 tutorial sequence. - + Explore syntax and standard library reference material. diff --git a/docs/configure-rails/colang/colang-2/language-reference/index.mdx b/docs/configure-rails/colang/colang-2/language-reference/index.mdx index 5528e127e6..9130c90dc4 100644 --- a/docs/configure-rails/colang/colang-2/language-reference/index.mdx +++ b/docs/configure-rails/colang/colang-2/language-reference/index.mdx @@ -10,67 +10,67 @@ description: "Reference documentation for Colang 2.0 syntax, events, actions, fl - + Understand Colang 2.0 concepts and basic syntax. - + Learn how Colang generates and matches events. - + Use actions and action events in Colang. - + Define, start, await, and compose flows. - + Use variables and expressions in Colang. - + Use branching, loops, and return or abort statements. - + Use the Colang Standard Library modules. - + Configure and use LLM-related features. - + Explore advanced flow behavior and conflict resolution. - + Call custom Python actions from Colang. - + Debug Colang flows and inspect runtime state. @@ -80,14 +80,14 @@ Debug Colang flows and inspect runtime state. This chapter is a comprehensive introduction to Colang, explaining all important concepts in a bottom up approach. -* [Introduction](introduction#reference_introduction) -* [Event Generation & Matching](event-generation-and-matching#event-generation-and-matching) -* [Working with Actions](working-with-actions#working-with-actions) -* [Defining Flows](defining-flows#defining-flows) -* [Working with Variables & Expressions](working-with-variables-and-expressions#working-with-variables-and-expressions) -* [Flow control](flow-control#flow-control) -* [Colang Standard Library (CSL)](the-standard-library#the-standard-library) -* [Make use of Large Language Models (LLM)](make-use-of-llms#make-use-of-llms) -* [More on Flows](more-on-flows#more-on-flows) -* [Python Actions](python-actions#python-actions) -* [Development and Debugging](development-and-debugging#development-and-debugging) +* [Introduction](/configure-guardrails/colang/colang-2/language-reference/introduction#reference_introduction) +* [Event Generation & Matching](/configure-guardrails/colang/colang-2/language-reference/event-generation-and-matching#event-generation-and-matching) +* [Working with Actions](/configure-guardrails/colang/colang-2/language-reference/working-with-actions#working-with-actions) +* [Defining Flows](/configure-guardrails/colang/colang-2/language-reference/defining-flows#defining-flows) +* [Working with Variables & Expressions](/configure-guardrails/colang/colang-2/language-reference/working-with-variables-and-expressions#working-with-variables-and-expressions) +* [Flow control](/configure-guardrails/colang/colang-2/language-reference/flow-control#flow-control) +* [Colang Standard Library (CSL)](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library) +* [Make use of Large Language Models (LLM)](/configure-guardrails/colang/colang-2/language-reference/make-use-of-llms#make-use-of-llms) +* [More on Flows](/configure-guardrails/colang/colang-2/language-reference/more-on-flows#more-on-flows) +* [Python Actions](/configure-guardrails/colang/colang-2/language-reference/python-actions#python-actions) +* [Development and Debugging](/configure-guardrails/colang/colang-2/language-reference/development-and-debugging#development-and-debugging) diff --git a/docs/configure-rails/colang/colang-2/language-reference/make-use-of-llms.mdx b/docs/configure-rails/colang/colang-2/language-reference/make-use-of-llms.mdx index 0a6d53dafa..94c21b46f5 100644 --- a/docs/configure-rails/colang/colang-2/language-reference/make-use-of-llms.mdx +++ b/docs/configure-rails/colang/colang-2/language-reference/make-use-of-llms.mdx @@ -10,7 +10,7 @@ description: "At its core, Colang does not require a Large Language Model (LLM) ## Introduction -At its core, Colang does not require a Large Language Model (LLM) as backend. However, many of the more advanced mechanisms in the [Colang Standard Library](the-standard-library#the-standard-library) (CSL) depend on one. +At its core, Colang does not require a Large Language Model (LLM) as backend. However, many of the more advanced mechanisms in the [Colang Standard Library](/configure-guardrails/colang/colang-2/language-reference/the-standard-library#the-standard-library) (CSL) depend on one. To enable the LLM backend, you first have to configure the LLM access in the `config.yml` by adding a `models` section like this: @@ -22,7 +22,7 @@ models: ``` Make sure to also define the required API access key. For example, for OpenAI you will have to set the `OPENAI_API_KEY` environment variable. -Every LLM prompt contains a default context that can be modified if needed to adapt to the use case. See this [example configuration](../../../../../tests/test_configs/multi_modal_demo_v2_x/demo.yml) to get started. This will heavily influence all the LLM invocations. +Every LLM prompt contains a default context that can be modified if needed to adapt to the use case. See this [example configuration](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/tests/test_configs/multi_modal_demo_v2_x/demo.yml) to get started. This will heavily influence all the LLM invocations. @@ -47,7 +47,7 @@ model: meta/llama3-70b-instruct model: meta/llama-3.1-8b-instruct model: meta/llama-3.1-70b-instruct ``` -To support other models, you would need to create a set of new [template prompts](../../../../../nemoguardrails/llm/prompts) that consider the specific capabilities and the API of the model and add them to your bot configuration. +To support other models, you would need to create a set of new [template prompts](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/nemoguardrails/llm/prompts) that consider the specific capabilities and the API of the model and add them to your bot configuration. ## Natural Language Description (NLD) @@ -88,7 +88,7 @@ flow main $question = await user said something ... ``` -See the example in [LLM Flows](../getting-started/llm-flows#colang_2_getting_started_llm_flows) for more details on how this works. +See the example in [LLM Flows](/configure-guardrails/colang/colang-2/getting-started/llm-flows#colang_2_getting_started_llm_flows) for more details on how this works. Note that there is no explicit control over the NLD response format and sometimes it will fail to generate the expected result. Usually you can improve it by providing more explicit instructions in the NLD, e.g. "Welcome the user with a short sentence that is wrapped in quotation marks like this: 'Hi there!'". Another way is to check the returned value by using for example the `is_str()` function to make sure that it is of the expected format. @@ -97,7 +97,7 @@ Note that there is no explicit control over the NLD response format and sometime ## User Intent Matching -In section [Defining Flows](defining-flows#action-like-and-intent-like-flows), we have already seen how we can define user intent flows. The limitation was that they did not generalize to variations of the given user intent examples. With the help of an LLM, we can overcome this issue and use its reasoning power by importing the `llm` standard library module and activating the flows `automating intent detection` and `generating user intent for unhandled user utterance` ([GitHub link](../../../../../nemoguardrails/colang/v2_x/library/llm.co)) to match unexpected user utterances to currently active user intent flows. +In section [Defining Flows](/configure-guardrails/colang/colang-2/language-reference/defining-flows#action-like-and-intent-like-flows), we have already seen how we can define user intent flows. The limitation was that they did not generalize to variations of the given user intent examples. With the help of an LLM, we can overcome this issue and use its reasoning power by importing the `llm` standard library module and activating the flows `automating intent detection` and `generating user intent for unhandled user utterance` ([GitHub link](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/colang/v2_x/library/llm.co)) to match unexpected user utterances to currently active user intent flows. **llm/user_intent_match_example/main.co** @@ -237,4 +237,4 @@ This loop will take care of matching user utterances to predefined user intents ## Guardrailing -Checkout the examples in the [Getting Started](../getting-started/index#getting_started) section or refer to the [NeMo Guardrails documentation](https://github.com/NVIDIA-NeMo/Guardrails) to learn more about how Colang can be used to guardrail LLM responses and user inputs. +Checkout the examples in the [Getting Started](/configure-guardrails/colang/colang-2/getting-started#getting_started) section or refer to the [NeMo Guardrails documentation](https://github.com/NVIDIA-NeMo/Guardrails) to learn more about how Colang can be used to guardrail LLM responses and user inputs. diff --git a/docs/configure-rails/colang/colang-2/language-reference/the-standard-library.mdx b/docs/configure-rails/colang/colang-2/language-reference/the-standard-library.mdx index 7361a28bf1..6e2bbbf626 100644 --- a/docs/configure-rails/colang/colang-2/language-reference/the-standard-library.mdx +++ b/docs/configure-rails/colang/colang-2/language-reference/the-standard-library.mdx @@ -8,41 +8,41 @@ description: "The Colang Standard Library (CSL) provides an abstraction from the -The Colang Standard Library (CSL) provides an abstraction from the underlying event and action layer and offers a semantic interface to design interaction patterns between the bot and the user. Currently, there are the following library files available under `nemoguardrails/colang/v2_x/library/` ([GitHub link](../../../../../nemoguardrails/colang/v2_x/library)): +The Colang Standard Library (CSL) provides an abstraction from the underlying event and action layer and offers a semantic interface to design interaction patterns between the bot and the user. Currently, there are the following library files available under `nemoguardrails/colang/v2_x/library/` ([GitHub link](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/nemoguardrails/colang/v2_x/library)): - + Core user, bot, wait, and notification flows. - + Wait, timer, and silence detection flows. - + LLM continuation and utility flows. - + Gesture, posture, and avatar-related flows. - + Standard guardrail flow definitions. - + User attention tracking and checks. diff --git a/docs/configure-rails/colang/index.mdx b/docs/configure-rails/colang/index.mdx index 59bd592f4d..45a2d8da3f 100644 --- a/docs/configure-rails/colang/index.mdx +++ b/docs/configure-rails/colang/index.mdx @@ -147,5 +147,5 @@ This event-driven interaction model is part of what makes Colang a powerful mode ## Getting Started -If you've used Colang 1.0 before, check out the [What's Changed with Colang 2.0](colang-2/whats-changed) page. -If not, you can get started with the Colang 2.0 [Hello World](colang-2/getting-started/hello-world) example. +If you've used Colang 1.0 before, check out the [What's Changed with Colang 2.0](/configure-guardrails/colang/colang-2/whats-changed) page. +If not, you can get started with the Colang 2.0 [Hello World](/configure-guardrails/colang/colang-2/getting-started/hello-world) example. diff --git a/docs/configure-rails/guardrail-catalog/community/ai-defense.mdx b/docs/configure-rails/guardrail-catalog/community/ai-defense.mdx index cad007bb12..eefe605df0 100644 --- a/docs/configure-rails/guardrail-catalog/community/ai-defense.mdx +++ b/docs/configure-rails/guardrail-catalog/community/ai-defense.mdx @@ -108,4 +108,4 @@ This allows you to choose between security (fail closed) and availability (fail ## Notes -For more information on Cisco AI Defense capabilities and configuration, please refer to the [Cisco AI Defense documentation](https://securitydocs.cisco.com/docs/scc/admin/108321.dita?utm_medium=github&utm_campaign=nemo-guardrails). +For more information on Cisco AI Defense capabilities and configuration, please refer to the [Cisco AI Defense documentation](https://developer.cisco.com/docs/ai-defense-inspection/). diff --git a/docs/configure-rails/guardrail-catalog/community/clavata.mdx b/docs/configure-rails/guardrail-catalog/community/clavata.mdx index f6cc1fd958..caded22467 100644 --- a/docs/configure-rails/guardrail-catalog/community/clavata.mdx +++ b/docs/configure-rails/guardrail-catalog/community/clavata.mdx @@ -105,7 +105,7 @@ flow input rails $input_text clavata check for ($input_text, Toxicity, ["Hate Speech","Harassment"]) ``` -> The same is true for `output` flows, of course. See [our example](../../../../examples/configs/clavata_v2/rails.co) for more. +> The same is true for `output` flows, of course. See [our example](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/examples/configs/clavata_v2/rails.co) for more. ### 2. Programmatic Usage @@ -141,4 +141,4 @@ If the Clavata API request fails, the system will raise a `ClavataPluginAPIError - You can configure different policies and label requirements for input and output flows - If no labels are specified for a policy, any label match will be considered a hit -For more information on Clavata and its capabilities, please refer to the [Clavata documentation](https://clavata.helpscoutdocs.com). +For more information on Clavata and its capabilities, please refer to the [Clavata documentation](https://docs.clavata.ai/). diff --git a/docs/configure-rails/guardrail-catalog/community/cleanlab.mdx b/docs/configure-rails/guardrail-catalog/community/cleanlab.mdx index 247c263302..b073230cc4 100644 --- a/docs/configure-rails/guardrail-catalog/community/cleanlab.mdx +++ b/docs/configure-rails/guardrail-catalog/community/cleanlab.mdx @@ -32,6 +32,6 @@ Install the Python client to use Cleanlab's trustworthiness score: pip install --upgrade cleanlab-tlm ``` -You can get an API key for free by [creating a Cleanlab account](https://tlm.cleanlab.ai/) or experiment with the trustworthiness scores in the [playground](https://chat.cleanlab.ai/chat). Feel free to [email Cleanlab](mailto:support@cleanlab.ai) with any questions. +You can get an API key for free by [creating a Cleanlab account](https://tlm.cleanlab.ai/) or experiment with the trustworthiness scores in the [playground](https://tlm.cleanlab.ai/). Feel free to [email Cleanlab](mailto:support@cleanlab.ai) with any questions. Lastly, set the `CLEANLAB_API_KEY` environment variable with the API key. diff --git a/docs/configure-rails/guardrail-catalog/community/fiddler.mdx b/docs/configure-rails/guardrail-catalog/community/fiddler.mdx index 242c08123d..b902b7d67e 100644 --- a/docs/configure-rails/guardrail-catalog/community/fiddler.mdx +++ b/docs/configure-rails/guardrail-catalog/community/fiddler.mdx @@ -3,15 +3,15 @@ # SPDX-License-Identifier: Apache-2.0 title: "Fiddler Guardrails Integration" --- -Fiddler Guardrails utilizes [Fiddler Trust Models](https://docs.fiddler.ai/product-guide/llm-monitoring/llm-based-metrics#fiddler-fast-trust-metrics) in a specialized low-latency, high-throughput configuration. Guardrails can be used to guard Large Language Model (LLM) applications against user threats, such as prompt injection or harmful and inappropriate content, and LLM hallucinations. +Fiddler Guardrails utilizes [Fiddler Trust Models](https://docs.fiddler.ai/reference/glossary/centor-models) in a specialized low-latency, high-throughput configuration. Guardrails can be used to guard Large Language Model (LLM) applications against user threats, such as prompt injection or harmful and inappropriate content, and LLM hallucinations. -Currently, only Fiddler Trust Models ([Faithfulness](https://docs.fiddler.ai/product-guide/llm-monitoring/enrichments-private-preview#fast-faithfulness-private-preview) and [Safety](https://docs.fiddler.ai/product-guide/llm-monitoring/enrichments-private-preview#fast-safety-private-preview)) - Fiddler's in-house, purpose-built SLMs - are available for guardrail use. Future model releases and model updates/improvements will also be available for guardrail use. +Currently, only Fiddler Trust Models ([Faithfulness](https://docs.fiddler.ai/protection/guardrails) and [Safety](https://docs.fiddler.ai/protection/guardrails)) - Fiddler's in-house, purpose-built SLMs - are available for guardrail use. Future model releases and model updates/improvements will also be available for guardrail use. ## Setup 1. Ensure that you have access to a valid Fiddler environment. To obtain one, please [contact us](https://www.fiddler.ai/contact-sales). -2. Create a new [Fiddler environment key](https://docs.fiddler.ai/ui-guide/administration-ui/settings#credentials) and set the `FIDDLER_API_KEY` environment variable to this key to authenticate into the Fiddler service. +2. Create a new [Fiddler environment key](https://docs.fiddler.ai/protection/guardrails) and set the `FIDDLER_API_KEY` environment variable to this key to authenticate into the Fiddler service. Update your `config.yml` file to include the following settings: @@ -49,4 +49,4 @@ Fiddler Guardrails will not block inputs in the event of any API failure. ## Notes -For more information about Fiddler Guardrails, please visit the Fiddler Guardrails [documentation](https://docs.fiddler.ai/product-guide/llm-monitoring/guardrails). +For more information about Fiddler Guardrails, please visit the Fiddler Guardrails [documentation](https://docs.fiddler.ai/protection/guardrails). diff --git a/docs/configure-rails/guardrail-catalog/community/llama-guard.mdx b/docs/configure-rails/guardrail-catalog/community/llama-guard.mdx index 3fb1affacb..8ac8502bb0 100644 --- a/docs/configure-rails/guardrail-catalog/community/llama-guard.mdx +++ b/docs/configure-rails/guardrail-catalog/community/llama-guard.mdx @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 title: "Llama-Guard Integration" --- -NeMo Guardrails provides out-of-the-box support for content moderation using Meta's [Llama Guard](https://ai.meta.com/research/publications/llama-guard-llm-based-input-output-safeguard-for-human-ai-conversations/) model. +NeMo Guardrails provides out-of-the-box support for content moderation using Meta's [Llama Guard](https://arxiv.org/abs/2312.06674) model. In our testing, we observe significantly improved input and output content moderation performance compared to the [self-check method](/configure-guardrails/guardrail-catalog/self-check). Please see the [performance evaluation](/evaluation/evaluate-guardrails#llamaguard-based-moderation-rails-performance) for benchmark numbers. diff --git a/docs/configure-rails/guardrail-catalog/community/patronus-evaluate-api.mdx b/docs/configure-rails/guardrail-catalog/community/patronus-evaluate-api.mdx index 8fc44d6a6e..0795d96cb0 100644 --- a/docs/configure-rails/guardrail-catalog/community/patronus-evaluate-api.mdx +++ b/docs/configure-rails/guardrail-catalog/community/patronus-evaluate-api.mdx @@ -11,7 +11,7 @@ Patronus also has Managed configurations of the Judge evaluator, which you can u ## Setup 1. Sign up for an account on [app.patronus.ai](https://app.patronus.ai). -2. You can follow the Quick Start guide [here](https://docs.patronus.ai/docs/quickstart-guide) to get onboarded. +2. You can follow the Quick Start guide [here](https://docs.patronus.ai/docs/quickstart_eval) to get onboarded. 3. Create an API Key and save it somewhere safe. ## Usage diff --git a/docs/configure-rails/guardrail-catalog/content-safety.mdx b/docs/configure-rails/guardrail-catalog/content-safety.mdx index 6d4dd83531..27d90536bf 100644 --- a/docs/configure-rails/guardrail-catalog/content-safety.mdx +++ b/docs/configure-rails/guardrail-catalog/content-safety.mdx @@ -8,7 +8,7 @@ content: type: "Reference" --- -The content safety checks inside Guardrails act as a robust set of guardrails designed to ensure the integrity and safety of both input and output text. This feature allows users to utilize a variety of advanced content safety models such as Nvidia's [Nemotron Content Safety](https://docs.nvidia.com/nim/#nemoguard) model, Meta's [Llama Guard 3](https://www.llama.com/docs/model-cards-and-prompt-formats/llama-guard-3/), and Google's [ShieldGemma](https://ai.google.dev/gemma/docs/shieldgemma). +The content safety checks inside Guardrails act as a robust set of guardrails designed to ensure the integrity and safety of both input and output text. This feature allows users to utilize a variety of advanced content safety models such as Nvidia's [Nemotron Content Safety](https://docs.nvidia.com/nim/#nemoguard) model, Meta's [Llama Guard 3](https://github.com/meta-llama/PurpleLlama/blob/main/Llama-Guard3/8B/MODEL_CARD.md), and Google's [ShieldGemma](https://ai.google.dev/gemma/docs/shieldgemma). To use the content safety check, you should: @@ -115,7 +115,7 @@ To use the content safety check, you should: The above is an example prompt that you can use with the *content safety check input $model=shieldgemma*. The prompt has one input variable: `{{ user_input }}`, which includes user input that should be moderated. The completion must be "yes" if the response is not safe and "no" otherwise. Optionally, some models may return a set of policy violations. -The `content safety check input` and `content safety check output` rails executes the [`content_safety_check_input`](../../../nemoguardrails/library/content_safety/actions.py) and [`content_safety_check_output`](../../../nemoguardrails/library/content_safety/actions.py) actions respectively. +The `content safety check input` and `content safety check output` rails executes the [`content_safety_check_input`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/library/content_safety/actions.py) and [`content_safety_check_output`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/library/content_safety/actions.py) actions respectively. ## Reasoning Models as Content Safety Guards @@ -260,7 +260,7 @@ Language detection accuracy was benchmarked on two datasets: TODO: is this covered by the general content safety abstraction? -The NeMo Guardrails library provides out-of-the-box support for content moderation using Meta's [Llama Guard](https://ai.meta.com/research/publications/llama-guard-llm-based-input-output-safeguard-for-human-ai-conversations/) model. +The NeMo Guardrails library provides out-of-the-box support for content moderation using Meta's [Llama Guard](https://arxiv.org/abs/2312.06674) model. ### Example usage diff --git a/docs/configure-rails/guardrail-catalog/third-party.mdx b/docs/configure-rails/guardrail-catalog/third-party.mdx index 7df4867eb9..33b8a9f822 100644 --- a/docs/configure-rails/guardrail-catalog/third-party.mdx +++ b/docs/configure-rails/guardrail-catalog/third-party.mdx @@ -69,7 +69,7 @@ For more details, check out the [AutoAlign Integration](/configure-guardrails/gu ## Clavata -The NeMo Guardrails library supports using [Clavata AI](https://www.clavata.ai/blogs/partner-nvidia) as an input and output rail out-of-the-box (you need to have the CLAVATA_API_KEY environment variable set). +The NeMo Guardrails library supports using [Clavata AI](https://docs.clavata.ai/) as an input and output rail out-of-the-box (you need to have the CLAVATA_API_KEY environment variable set). ### Example usage @@ -145,9 +145,9 @@ For more details, check out the [GuardrailsAI Integration](/configure-guardrails ## Fiddler Guardrails for Safety and Hallucination Detection -The NeMo Guardrails library supports using [Fiddler Guardrails](https://docs.fiddler.ai/product-guide/llm-monitoring/guardrails) for safety and hallucination detection in input and output flows. +The NeMo Guardrails library supports using [Fiddler Guardrails](https://docs.fiddler.ai/protection/guardrails) for safety and hallucination detection in input and output flows. -In order to access Fiddler guardrails, you need access to a valid Fiddler environment, and a [Fiddler environment key](https://docs.fiddler.ai/ui-guide/administration-ui/settings#credentials). You'll need to set the `FIDDLER_API_KEY` environment variable to authenticate into the Fiddler service. +In order to access Fiddler guardrails, you need access to a valid Fiddler environment, and a [Fiddler environment key](https://docs.fiddler.ai/protection/guardrails). You'll need to set the `FIDDLER_API_KEY` environment variable to authenticate into the Fiddler service. ```yaml rails: diff --git a/docs/configure-rails/guardrail-catalog/topic-control.mdx b/docs/configure-rails/guardrail-catalog/topic-control.mdx index 02cfe3941e..6972d7d10c 100644 --- a/docs/configure-rails/guardrail-catalog/topic-control.mdx +++ b/docs/configure-rails/guardrail-catalog/topic-control.mdx @@ -48,7 +48,7 @@ To use the topic safety check, you should: - Do not answer enquiries unrelated to the company policies. ``` -The system prompt must end with the topic safety output restriction - `If any of the above conditions are violated, please respond with "off-topic". Otherwise, respond with "on-topic". You must respond with "on-topic" or "off-topic".` This condition is automatically added to the system prompt by the topic safety check input flow. If you want to customize the output restriction, you can do so by modifying the `TOPIC_SAFETY_OUTPUT_RESTRICTION` variable in the [`topic_safety_check_input`](../../../nemoguardrails/library/topic_safety/actions.py) action. +The system prompt must end with the topic safety output restriction - `If any of the above conditions are violated, please respond with "off-topic". Otherwise, respond with "on-topic". You must respond with "on-topic" or "off-topic".` This condition is automatically added to the system prompt by the topic safety check input flow. If you want to customize the output restriction, you can do so by modifying the `TOPIC_SAFETY_OUTPUT_RESTRICTION` variable in the [`topic_safety_check_input`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/library/topic_safety/actions.py) action. ## Customizing Topic Rules @@ -72,4 +72,4 @@ prompts: ## Implementation Details -The 'topic safety check input' flow uses the [`topic_safety_check_input`](../../../nemoguardrails/library/topic_safety/actions.py) action. The model returns a boolean value indicating whether the user input is on-topic or not. Please refer to the [topic safety example](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/examples/configs/topic_safety/README.md) for more details. +The 'topic safety check input' flow uses the [`topic_safety_check_input`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/library/topic_safety/actions.py) action. The model returns a boolean value indicating whether the user input is on-topic or not. Please refer to the [topic safety example](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/examples/configs/topic_safety/README.md) for more details. diff --git a/docs/evaluation/evaluate-guardrails.mdx b/docs/evaluation/evaluate-guardrails.mdx index 903f2bd318..c8267f932b 100644 --- a/docs/evaluation/evaluate-guardrails.mdx +++ b/docs/evaluation/evaluate-guardrails.mdx @@ -78,7 +78,7 @@ Important lessons to be learned from the evaluation results: - Each step in the three-step approach (user intent, next step/bot intent, bot message) used by Guardrails offers an improvement in performance. - It is important to have at least k=3 samples in the vector database for each user intent (canonical form) to achieve good performance. - Some models (e.g., gpt-3.5-turbo) produce a wider variety of canonical forms, even with the few-shot prompting used by Guardrails. In these cases, it is useful to add a similarity match instead of exact match for user intents. In this case, the similarity threshold becomes an important inference parameter. -- Initial results show that even small models, e.g. [dolly-v2-3b](https://huggingface.co/databricks/dolly-v2-3b), [vicuna-7b-v1.3](https://huggingface.co/lmsys/vicuna-7b-v1.3), [mpt-7b-instruct](https://huggingface.co/mosaicml/mpt-7b-instruct), [falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct) have good performance for topical rails. +- Initial results show that even small models, e.g. dolly-v2-3b, [vicuna-7b-v1.3](https://huggingface.co/lmsys/vicuna-7b-v1.3), mpt-7b-instruct, [falcon-7b-instruct](https://huggingface.co/tiiuae/falcon-7b-instruct) have good performance for topical rails. - Using a single call for topical rails shows similar results to the default method (which uses up to 3 LLM calls for generating the final bot message) in most cases for `text-davinci-003` model. - Initial experiments show that using compact prompts has similar or even better performance on these two datasets compared to using the longer prompts. @@ -189,7 +189,7 @@ More details on how to set up the data in the right format and run the evaluatio Evaluation Date - Nov 23, 2023 (Mar 7 2024 for `gemini-1.0-pro`). -We evaluate the performance of the fact-checking rail on the [MSMARCO](https://huggingface.co/datasets/ms_marco) dataset using the Self-Check and the AlignScore approaches. To build the dataset, we randomly sample 100 (question, correct answer, evidence) triples, and then, for each triple, build a non-factual or incorrect answer to yield 100 (question, incorrect answer, evidence) triples. +We evaluate the performance of the fact-checking rail on the [MSMARCO](https://huggingface.co/datasets/microsoft/ms_marco) dataset using the Self-Check and the AlignScore approaches. To build the dataset, we randomly sample 100 (question, correct answer, evidence) triples, and then, for each triple, build a non-factual or incorrect answer to yield 100 (question, incorrect answer, evidence) triples. We breakdown the performance into positive entailment accuracy and negative entailment accuracy. Positive entailment accuracy is the accuracy of the model in correctly identifying answers that are grounded in the evidence passage. Negative entailment accuracy is the accuracy of the model in correctly identifying answers that are **not** supported in the evidence. Details on how to create synthetic negative examples can be found [here](https://github.com/NVIDIA-NeMo/Guardrails/tree/develop/nemoguardrails/evaluate/data/factchecking/README.md). @@ -343,7 +343,7 @@ To evaluate the hallucination rail on your own dataset, you can follow the creat #### Evaluation Results -To evaluate the hallucination rail, we manually curate a set of [questions](../../nemoguardrails/evaluate/data/hallucination/sample.txt) which mainly consists of questions with a false premise, i.e., questions that cannot have a correct answer. +To evaluate the hallucination rail, we manually curate a set of [questions](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/evaluate/data/hallucination/sample.txt) which mainly consists of questions with a false premise, i.e., questions that cannot have a correct answer. For example, the question "What is the capital of the moon?" has a false premise since the moon does not have a capital. Since the question is stated in a way that implies that the moon has a capital, the model might be tempted to make up a fact and answer the question. diff --git a/docs/evaluation/llm-vulnerability-scanning.mdx b/docs/evaluation/llm-vulnerability-scanning.mdx index 01c18e5107..fef0b9bc43 100644 --- a/docs/evaluation/llm-vulnerability-scanning.mdx +++ b/docs/evaluation/llm-vulnerability-scanning.mdx @@ -22,10 +22,10 @@ Think of Garak as an LLM alternative to network security scanners such as [nmap] The sample ABC guardrails configuration has been scanned using Garak against vulnerabilities, using four different configurations, offering increasing protection against LLM vulnerabilities: -1. **`bare_llm`**: no protection (full Garak results [here](./../_static/html/abc_bare_llm.report.html)). -2. **`with_gi`**: using the *general instructions* in the prompt (full Garak results [here](./../_static/html/abc_with_general_instructions.report.html)). -3. **`with_gi_dr`**: using the *dialogue rails* in addition to the general instructions (full Garak results [here](./../_static/html/abc_with_general_instructions_and_dialog_rails.report.html)). -4. **`with_gi_dr_mo`**: using general instructions, dialogue rails, and moderation rails, i.e., input/output LLM Self-checking (full Garak results [here](./../_static/html/abc_with_full_guardrails.report.html)). +1. **`bare_llm`**: no protection (full Garak results [here](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/docs/_static/html/abc_bare_llm.report.html)). +2. **`with_gi`**: using the *general instructions* in the prompt (full Garak results [here](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/docs/_static/html/abc_with_general_instructions.report.html)). +3. **`with_gi_dr`**: using the *dialogue rails* in addition to the general instructions (full Garak results [here](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/docs/_static/html/abc_with_general_instructions_and_dialog_rails.report.html)). +4. **`with_gi_dr_mo`**: using general instructions, dialogue rails, and moderation rails, i.e., input/output LLM Self-checking (full Garak results [here](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/docs/_static/html/abc_with_full_guardrails.report.html)). The table below summarizes what is included in each configuration: diff --git a/docs/getting-started/tutorials/jailbreak-detection-heuristics.mdx b/docs/getting-started/tutorials/jailbreak-detection-heuristics.mdx index 134a487b41..590dfe419d 100644 --- a/docs/getting-started/tutorials/jailbreak-detection-heuristics.mdx +++ b/docs/getting-started/tutorials/jailbreak-detection-heuristics.mdx @@ -63,7 +63,7 @@ rails: - self check input ``` -The `self check input` rail [prompts](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/docs/configure-rails/colang/colang-1/tutorials/6-topical-rails/config/prompts.yml) an LLM model to check if the input is safe for the bot to process. +The `self check input` rail [prompts](/configure-guardrails/guardrail-catalog/self-check#self-check-input) an LLM model to check if the input is safe for the bot to process. The `self check input` rail can be expensive to run for all input prompts, so you can use jailbreak detection heuristics as a low-latency and low-cost alternative to filter out malicious prompts. ## Jailbreak Detection Heuristics diff --git a/docs/integration/langchain/agent-middleware.mdx b/docs/integration/langchain/agent-middleware.mdx index 21cf136c12..e482f71aeb 100644 --- a/docs/integration/langchain/agent-middleware.mdx +++ b/docs/integration/langchain/agent-middleware.mdx @@ -305,7 +305,7 @@ guardrails = GuardrailsMiddleware( ) ``` -For more details, see [Security Considerations](https://docs.nvidia.com/nemo/guardrails/latest/integration/tools-integration.html#security-considerations) in the tools integration guide. +For more details, see [Security Considerations](/integration-with-third-party-libraries/tools-integration#security-considerations) in the tools integration guide. ### MODIFIED Status Replaces Message Content diff --git a/docs/resources/research.mdx b/docs/resources/research.mdx index fd66af364c..b189d674f9 100644 --- a/docs/resources/research.mdx +++ b/docs/resources/research.mdx @@ -17,7 +17,7 @@ For each category we present a list of relevant surveys, existing research paper Relevant surveys on hallucination detection and checking factuality for large language models. -- Ji, Z., Lee, N., Frieske, R., Yu, T., Su, D., Xu, Y., ... & Fung, P. (2023). Survey of hallucination in natural language generation. ACM Computing Surveys, 55(12), 1-38. [paper](https://dl.acm.org/doi/pdf/10.1145/3571730) +- Ji, Z., Lee, N., Frieske, R., Yu, T., Su, D., Xu, Y., ... & Fung, P. (2023). Survey of hallucination in natural language generation. ACM Computing Surveys, 55(12), 1-38. [paper](https://arxiv.org/abs/2202.03629) - Zhang, Y., Li, Y., Cui, L., Cai, D., Liu, L., Fu, T., ... & Shi, S. (2023). Siren's song in the AI ocean: a survey on hallucination in large language models. arXiv preprint arXiv:2309.01219. [paper](https://arxiv.org/pdf/2309.01219.pdf) - Huang, L., Yu, W., Ma, W., Zhong, W., Feng, Z., Wang, H., ... & Liu, T. (2023). A survey on hallucination in large language models: Principles, taxonomy, challenges, and open questions. arXiv preprint arXiv:2311.05232. [paper](https://arxiv.org/pdf/2311.05232.pdf) - Wang, C., Liu, X., Yue, Y., Tang, X., Zhang, T., Jiayang, C., ... & Zhang, Y. (2023). Survey on factuality in large language models: Knowledge, retrieval and domain-specificity. arXiv preprint arXiv:2310.07521. [paper](https://arxiv.org/pdf/2310.07521.pdf) | [repo](https://github.com/wangcunxiang/LLM-Factuality-Survey) diff --git a/docs/telemetry.mdx b/docs/telemetry.mdx index 651796662d..a268147feb 100644 --- a/docs/telemetry.mdx +++ b/docs/telemetry.mdx @@ -158,4 +158,4 @@ This behavior keeps adoption metrics focused on real deployments, not synthetic ## Schema and Source Code -The Python source for the event lives in [`nemoguardrails/telemetry.py`](../nemoguardrails/telemetry.py). The wire contract is validated against a vendored snapshot of the shared NVIDIA telemetry schema at [`schemas/anonymous_events.snapshot.json`](../schemas/anonymous_events.snapshot.json). The conformance test in [`tests/telemetry/test_usage_reporting.py`](../tests/telemetry/test_usage_reporting.py) validates emitted payloads against that snapshot with `jsonschema`. +The Python source for the event lives in [`nemoguardrails/telemetry.py`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/nemoguardrails/telemetry.py). The wire contract is validated against a vendored snapshot of the shared NVIDIA telemetry schema at [`schemas/anonymous_events.snapshot.json`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/schemas/anonymous_events.snapshot.json). The conformance test in [`tests/telemetry/test_usage_reporting.py`](https://github.com/NVIDIA-NeMo/Guardrails/blob/develop/tests/telemetry/test_usage_reporting.py) validates emitted payloads against that snapshot with `jsonschema`. diff --git a/fern/docs.yml b/fern/docs.yml index 204bbe0d72..bd951d0e6d 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -57,6 +57,79 @@ redirects: destination: "/nemo/guardrails/latest" - source: "/nemo/guardrails/latest/index" destination: "/nemo/guardrails/latest" + # Previous About section slug. + - source: "/nemo/guardrails/latest/about" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about/overview" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about/overview" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about/overview.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about/overview.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about/overview/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/about/overview/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/overview" + - source: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/latest/about/how-it-works.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/about/how-it-works.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/latest/about/how-it-works/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/about/how-it-works/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" + - source: "/nemo/guardrails/latest/about/rail-types" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/about/rail-types" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/latest/about/rail-types.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/about/rail-types.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/latest/about/rail-types/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/about/rail-types/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/rail-types" + - source: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/latest/about/supported-llms.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/about/supported-llms.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/latest/about/supported-llms/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/about/supported-llms/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" + - source: "/nemo/guardrails/latest/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" + - source: "/nemo/guardrails/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" + - source: "/nemo/guardrails/latest/about/release-notes.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" + - source: "/nemo/guardrails/about/release-notes.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" + - source: "/nemo/guardrails/latest/about/release-notes/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" + - source: "/nemo/guardrails/about/release-notes/index.html" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" # Legacy Sphinx redirects from docs/conf.py. - source: "/nemo/guardrails/latest/introduction" destination: "/nemo/guardrails/latest" @@ -99,13 +172,13 @@ redirects: - source: "/nemo/guardrails/user-guides/advanced/nemoguard-contentsafety-deployment.html" destination: "/nemo/guardrails/latest/getting-started/tutorials/nemotron-safety-guard-deployment" - source: "/nemo/guardrails/latest/architecture" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/architecture" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/latest/architecture.html" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/architecture.html" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/latest/architecture/readme" destination: "/nemo/guardrails/latest/reference/colang-architecture-guide" - source: "/nemo/guardrails/architecture/readme" @@ -131,13 +204,13 @@ redirects: - source: "/nemo/guardrails/glossary.html" destination: "/nemo/guardrails/latest" - source: "/nemo/guardrails/latest/release-notes" - destination: "/nemo/guardrails/latest/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" - source: "/nemo/guardrails/release-notes" - destination: "/nemo/guardrails/latest/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" - source: "/nemo/guardrails/latest/release-notes.html" - destination: "/nemo/guardrails/latest/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" - source: "/nemo/guardrails/release-notes.html" - destination: "/nemo/guardrails/latest/about/release-notes" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/release-notes" - source: "/nemo/guardrails/latest/security/guidelines" destination: "/nemo/guardrails/latest/resources/security/guidelines" - source: "/nemo/guardrails/security/guidelines" @@ -891,13 +964,13 @@ redirects: - source: "/nemo/guardrails/user-guides/advanced/using-docker.html" destination: "/nemo/guardrails/latest/deployment/using-docker" - source: "/nemo/guardrails/latest/user-guides/advanced/vertexai-setup" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/advanced/vertexai-setup" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/advanced/vertexai-setup.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/advanced/vertexai-setup.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/cli" destination: "/nemo/guardrails/latest/reference/cli" - source: "/nemo/guardrails/user-guides/cli" @@ -923,61 +996,61 @@ redirects: - source: "/nemo/guardrails/user-guides/guardrails-library.html" destination: "/nemo/guardrails/latest/configure-rails/guardrail-catalog" - source: "/nemo/guardrails/latest/user-guides/guardrails-process" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/user-guides/guardrails-process" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/latest/user-guides/guardrails-process.html" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/user-guides/guardrails-process.html" - destination: "/nemo/guardrails/latest/about/how-it-works" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/how-it-works" - source: "/nemo/guardrails/latest/user-guides/llm-support" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm-support" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm-support.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm-support.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/nvidia-ai-endpoints" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/nvidia-ai-endpoints" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/nvidia-ai-endpoints.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/nvidia-ai-endpoints.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/nvidia-ai-endpoints/readme" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/nvidia-ai-endpoints/readme" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/nvidia-ai-endpoints/readme.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/nvidia-ai-endpoints/readme.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/vertexai" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/vertexai" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/vertexai.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/vertexai.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/vertexai/readme" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/vertexai/readme" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/llm/vertexai/readme.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/user-guides/llm/vertexai/readme.html" - destination: "/nemo/guardrails/latest/about/supported-llms" + destination: "/nemo/guardrails/latest/about-nemo-guardrails-library/supported-llms" - source: "/nemo/guardrails/latest/user-guides/migration-guide" destination: "/nemo/guardrails/latest/configure-rails/colang/colang-2/migration-guide" - source: "/nemo/guardrails/user-guides/migration-guide" @@ -1010,6 +1083,51 @@ redirects: destination: "/nemo/guardrails/latest/getting-started/tutorials/multimodal" - source: "/nemo/guardrails/user-guides/multimodal.html" destination: "/nemo/guardrails/latest/getting-started/tutorials/multimodal" + # Colang 2.0 language-reference pages previously rendered one level higher. + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/introduction" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/introduction" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/introduction" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/introduction" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/working-with-actions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/working-with-actions" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/working-with-actions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/working-with-actions" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/event-generation-and-matching" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/event-generation-and-matching" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/event-generation-and-matching" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/event-generation-and-matching" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/defining-flows" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/defining-flows" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/defining-flows" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/defining-flows" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/working-with-variables-and-expressions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/working-with-variables-and-expressions" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/working-with-variables-and-expressions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/working-with-variables-and-expressions" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/the-standard-library" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/the-standard-library" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/the-standard-library" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/the-standard-library" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/flow-control" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/flow-control" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/flow-control" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/flow-control" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/make-use-of-llms" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/make-use-of-llms" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/make-use-of-llms" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/make-use-of-llms" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/development-and-debugging" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/development-and-debugging" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/development-and-debugging" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/development-and-debugging" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/python-actions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/python-actions" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/python-actions" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/python-actions" + - source: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/more-on-flows" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/more-on-flows" + - source: "/nemo/guardrails/configure-guardrails/colang/colang-2/more-on-flows" + destination: "/nemo/guardrails/latest/configure-guardrails/colang/colang-2/language-reference/more-on-flows" - source: "/nemo/guardrails/latest/user-guides/python-api" destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" - source: "/nemo/guardrails/user-guides/python-api" @@ -1050,6 +1168,52 @@ redirects: destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/streaming" - source: "/nemo/guardrails/api/nemoguardrails.streaming.html" destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/streaming" + # Generated SDK pages can emit links to private helper modules that Fern does + # not publish as standalone pages. Route them to the nearest public SDK page. + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/_compat" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/_compat" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/embeddings" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/embeddings" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/__main__" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/__main__" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/deal__status" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/comd_parser" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/deal__status" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/comd_parser" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/user=CURRENT" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/comd_parser" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/user=CURRENT" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/colang/v1_0/lang/comd_parser" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/guardrails/_http" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/guardrails" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/guardrails/_http" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/guardrails" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/helpers" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/llm/helpers" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients/_errors" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/llm/clients/_errors" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients/_sse" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/llm/clients/_sse" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/clients" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers/huggingface" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/llm/providers/huggingface" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers" + - source: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers/trtllm" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers" + - source: "/nemo/guardrails/guardrails-python-sdk/nemoguardrails/llm/providers/trtllm" + destination: "/nemo/guardrails/latest/guardrails-python-sdk/nemoguardrails/llm/providers" - source: "/nemo/guardrails/:path*/index.html" destination: "/nemo/guardrails/:path*" - source: "/nemo/guardrails/:path*.html" diff --git a/nemoguardrails/colang/v1_0/lang/comd_parser.py b/nemoguardrails/colang/v1_0/lang/comd_parser.py index cb086e4ace..a611894adc 100644 --- a/nemoguardrails/colang/v1_0/lang/comd_parser.py +++ b/nemoguardrails/colang/v1_0/lang/comd_parser.py @@ -26,15 +26,11 @@ def parse_pattern(pattern): """ Parses a pattern from the Markdown-friendly format to an internal format. - E.g. parse_pattern("show [me](user=CURRENT) the deals I've [won](deal__status)") = - (show me the deals I've {deal__status}, {'user': 'CURRENT'}). - - For patters with "assignment patterns" like "show [me](user=CURRENT) the deals" we - transform it into: - "show {user=CURRENT} the deals" with the mapping: - { - "user=CURRENT": "me" - } + For example, a pattern with an implicit user assignment and a captured deal + status returns `("show me the deals I've {deal__status}", {"user": "CURRENT"})`. + + Assignment patterns are transformed into capture placeholders and record + an implicit mapping such as `{"user=CURRENT": "me"}`. :param pattern: The pattern in Markdown-friendly format. :return: A tuple (pattern, params) where pattern is a pattern containing only diff --git a/nemoguardrails/tracing/constants.py b/nemoguardrails/tracing/constants.py index 2cc954638a..bc44f66c91 100644 --- a/nemoguardrails/tracing/constants.py +++ b/nemoguardrails/tracing/constants.py @@ -308,7 +308,7 @@ class EventNames: """Standard event names for OpenTelemetry GenAI semantic conventions. Based on official spec at: - https://github.com/open-telemetry/semantic-conventions/blob/main/model/gen-ai/events.yaml + https://opentelemetry.io/docs/concepts/semantic-conventions/ """ GEN_AI_SYSTEM_MESSAGE = "gen_ai.system.message" diff --git a/nemoguardrails/utils.py b/nemoguardrails/utils.py index fee24614c5..9047b06e21 100644 --- a/nemoguardrails/utils.py +++ b/nemoguardrails/utils.py @@ -118,8 +118,9 @@ def _has_property(e: Dict[str, Any], p: Property) -> bool: ), Validator( "***UtteranceUserActionTranscriptUpdated events need to provide 'interim_transcript' of type 'str'", - lambda e: e["type"] != "UtteranceUserActionTranscriptUpdated" - or _has_property(e, Property("interim_transcript", str)), + lambda e: ( + e["type"] != "UtteranceUserActionTranscriptUpdated" or _has_property(e, Property("interim_transcript", str)) + ), ), Validator( "***UtteranceUserActionFinished events need to provide 'final_transcript' of type 'str'", diff --git a/scripts/check-docs-links.sh b/scripts/check-docs-links.sh deleted file mode 100755 index 87f7e4d48c..0000000000 --- a/scripts/check-docs-links.sh +++ /dev/null @@ -1,719 +0,0 @@ -#!/usr/bin/env bash -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Markdown/MDX link checker for Guardrails docs. -# -# Usage: -# scripts/check-docs-links.sh -# scripts/check-docs-links.sh --local-only -# scripts/check-docs-links.sh path/to/page.md path/to/page.mdx -# -# Environment: -# CHECK_DOC_LINKS_REMOTE If 0, skip http(s) probes. -# CHECK_DOC_LINKS_VERBOSE If 1, log each URL while curling. -# CHECK_DOC_LINKS_IGNORE_EXTRA Comma-separated extra http(s) URLs to skip. -# CHECK_DOC_LINKS_IGNORE_URL_REGEX Skip remote probes when the full URL matches this ERE. -# CHECK_DOCS_FERN_NAV_YML Override docs/index.yml for tests. -# NODE Node binary for Fern route parsing. -# CURL curl binary for remote probes. - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || true)" -if [[ -z "${REPO_ROOT:-}" ]]; then - REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -fi - -CURL="${CURL:-curl}" -NODE="${NODE:-node}" -CHECK_DOC_LINKS_REMOTE="${CHECK_DOC_LINKS_REMOTE:-1}" -VERBOSE="${CHECK_DOC_LINKS_VERBOSE:-0}" -EXTRA_FILES=() - -usage() { - cat <<'EOF' -Markdown/MDX link checker for Guardrails docs. - -Usage: scripts/check-docs-links.sh [options] [extra.md/.mdx ...] - -Options: - --local-only Do not curl http(s) URLs (same as CHECK_DOC_LINKS_REMOTE=0). - --verbose Log each URL while curling. - -h, --help Show this help. - -Environment: CHECK_DOC_LINKS_REMOTE, CHECK_DOC_LINKS_VERBOSE, - CHECK_DOC_LINKS_IGNORE_EXTRA, CHECK_DOC_LINKS_IGNORE_URL_REGEX, - CHECK_DOCS_FERN_NAV_YML, NODE, CURL. -EOF -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --local-only) - CHECK_DOC_LINKS_REMOTE=0 - shift - ;; - --verbose) - VERBOSE=1 - shift - ;; - -h | --help) - usage - exit 0 - ;; - --) - shift - EXTRA_FILES+=("$@") - break - ;; - -*) - echo "check-docs-links: unknown option: $1" >&2 - usage >&2 - exit 2 - ;; - *) - EXTRA_FILES+=("$1") - shift - ;; - esac -done - -log() { - printf '%s\n' "check-docs-links: $*" -} - -collect_default_docs() { - local f - for f in \ - "$REPO_ROOT/README.md" \ - "$REPO_ROOT/CONTRIBUTING.md" \ - "$REPO_ROOT/SECURITY.md" \ - "$REPO_ROOT/CHANGELOG.md"; do - [[ -f "$f" ]] && printf '%s\n' "$f" - done - if [[ -d "$REPO_ROOT/docs" ]]; then - find "$REPO_ROOT/docs" \ - -path "$REPO_ROOT/docs/_static/python-sdk-reference" -prune \ - -o -type f \( -name '*.md' -o -name '*.mdx' \) -print | LC_ALL=C sort - fi -} - -extract_targets() { - LC_ALL=C perl -CS -ne ' - if ($in_fence) { - if (/^\s*(`{3,}|~{3,})(.*)$/) { - my $fence = $1; - my $rest = $2; - my $char = substr($fence, 0, 1); - my $length = length($fence); - if ($char eq $fch && $length >= $flen && $rest =~ /^\s*$/) { - ($in_fence, $fch, $flen) = (0, "", 0); - } - } - next; - } - - my $line = $.; - my $text = $_; - my $visible = ""; - - while (length $text) { - if ($in_comment) { - if ($text =~ s/^(.*?)-->//s) { - $in_comment = 0; - next; - } - $text = ""; - next; - } - - if ($text =~ s/^(.*?)/) { - die "malformed HTML comment\n"; - } - - $visible .= $text; - last; - } - - if ($visible =~ /^\s*(`{3,}|~{3,})(.*)$/) { - my $fence = $1; - my $char = substr($fence, 0, 1); - my $length = length($fence); - ($in_fence, $fch, $flen) = (1, $char, $length); - next; - } - - my $scan = $visible; - $scan =~ s/`[^`]*`//g; - while ($scan =~ /\!?\[[^\]]*\]\(([^)\s]+)(?:\s+["'"'"'][^)"'"'"']*["'"'"'])?\)/g) { print $line . "\t" . $1 . "\n"; } - while ($scan =~ /<(https?:[^>\s]+)>/g) { print $line . "\t" . $1 . "\n"; } - while ($scan =~ /\bhref=(["'"'"'])([^"'"'"'\s]+)\1/g) { print $line . "\t" . $2 . "\n"; } - END { - die "malformed HTML comment\n" if $in_comment; - } - ' -- "$1" -} - -FERN_ROUTE_INDEX_LOADED=0 -FERN_ROUTE_INDEX="" - -load_fern_route_index() { - [[ "$FERN_ROUTE_INDEX_LOADED" -eq 1 ]] && return 0 - FERN_ROUTE_INDEX_LOADED=1 - - local nav_yml="${CHECK_DOCS_FERN_NAV_YML:-$REPO_ROOT/docs/index.yml}" - [[ -f "$nav_yml" ]] || return 0 - if ! command -v "$NODE" >/dev/null 2>&1; then - return 0 - fi - - local _fern_route_index_err - _fern_route_index_err="$(mktemp)" - if ! FERN_ROUTE_INDEX="$( - "$NODE" - "$REPO_ROOT" "$nav_yml" <<'NODE' 2>"$_fern_route_index_err" -const fs = require("node:fs"); -const path = require("node:path"); - -const repoRoot = process.argv[2]; -const navPath = process.argv[3]; -const docsRoot = path.join(repoRoot, "docs"); -const rows = []; -const routes = new Set(); - -function clean(value) { - let out = value.trim(); - const hash = out.indexOf(" #"); - if (hash >= 0) out = out.slice(0, hash).trim(); - if ((out.startsWith('"') && out.endsWith('"')) || (out.startsWith("'") && out.endsWith("'"))) { - out = out.slice(1, -1); - } - return out; -} - -function normalizeRoute(input) { - let out = input.replace(/\\/g, "/").replace(/^\/+/, ""); - out = out.replace(/\.(?:md|mdx)$/i, ""); - out = out.replace(/\/index$/i, ""); - return out; -} - -function emit(source, route) { - route = normalizeRoute(route); - if (!route) return; - rows.push(`${source}\t${route}`); - routes.add(route); -} - -function emitDocsIndexRoutes() { - const lines = fs.readFileSync(navPath, "utf8").split(/\r?\n/); - let stack = []; - let current = null; - for (const line of lines) { - const itemMatch = line.match(/^(\s*)-\s+(page|section):/); - if (itemMatch) { - const indent = itemMatch[1].length; - while (stack.length && stack[stack.length - 1].indent >= indent) stack.pop(); - current = { - indent, - type: itemMatch[2], - parent: stack.map((part) => part.slug), - path: "", - slug: "", - emitted: false, - pushed: false, - }; - continue; - } - - const propMatch = line.match(/^(\s*)(path|slug):\s*(.+?)\s*$/); - if (!propMatch || !current) continue; - const indent = propMatch[1].length; - if (indent !== current.indent + 2) continue; - - const key = propMatch[2]; - const value = clean(propMatch[3]); - if (key === "path") current.path = value; - if (key === "slug") current.slug = value; - if (!current.emitted && current.path && current.slug) { - emit(current.path, [...current.parent, current.slug].join("/")); - current.emitted = true; - } - if (!current.pushed && current.type === "section" && current.slug) { - stack.push({ indent: current.indent, slug: current.slug }); - current.pushed = true; - } - } -} - -function walk(directory) { - if (!fs.existsSync(directory)) return; - for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { - const fullPath = path.join(directory, entry.name); - if (entry.isDirectory()) { - walk(fullPath); - } else if (entry.isFile() && entry.name.endsWith(".mdx")) { - emitFrontmatterSlug(fullPath); - } - } -} - -function emitFrontmatterSlug(fullPath) { - const rel = path.relative(docsRoot, fullPath).replace(/\\/g, "/"); - const content = fs.readFileSync(fullPath, "utf8"); - const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); - if (!match) return; - const slugMatch = match[1].match(/^slug:\s*(.+?)\s*$/m); - if (!slugMatch) return; - emit(rel, clean(slugMatch[1])); -} - -function emitGeneratedNavigationRoutes() { - const navFiles = [ - path.join(docsRoot, "_static", "python-sdk-reference", "_navigation.yml"), - ]; - for (const generatedNav of navFiles) { - if (!fs.existsSync(generatedNav)) continue; - const lines = fs.readFileSync(generatedNav, "utf8").split(/\r?\n/); - let currentSlug = ""; - for (const line of lines) { - const slugMatch = line.match(/^\s*slug:\s*(.+?)\s*$/); - if (slugMatch) { - currentSlug = clean(slugMatch[1]); - routes.add(normalizeRoute(currentSlug)); - continue; - } - const pageMatch = line.match(/^\s*pageId:\s*(.+?)\s*$/); - if (pageMatch && currentSlug) { - emit(`_static/python-sdk-reference/${clean(pageMatch[1])}`, currentSlug); - } - } - } -} - -emitDocsIndexRoutes(); -emitGeneratedNavigationRoutes(); -walk(path.join(docsRoot, "_static", "python-sdk-reference", "guardrails-python-sdk")); - -for (const route of routes) { - rows.push(`\t${route}`); -} - -if (rows.length === 0) { - throw new Error(`no Fern routes found in ${navPath}`); -} -process.stdout.write(rows.join("\n")); -NODE - )"; then - echo "check-docs-links: failed to parse Fern navigation ${nav_yml#"$REPO_ROOT"/}: $(tr '\n' ' ' <"$_fern_route_index_err" | sed 's/[[:space:]]\+/ /g; s/^ //; s/ $//')" >&2 - rm -f "$_fern_route_index_err" - return 1 - fi - rm -f "$_fern_route_index_err" -} - -normalize_fern_route_path() { - local input="$1" part - input="${input#/}" - case "$input" in - nemo/guardrails/latest/*) input="${input#nemo/guardrails/latest/}" ;; - nemo/guardrails/*) input="${input#nemo/guardrails/}" ;; - latest/*) input="${input#latest/}" ;; - esac - input="${input%.mdx}" - input="${input%.md}" - input="${input%/index}" - - local -a parts=() out=() - local IFS='/' - read -r -a parts <<<"$input" - unset IFS - for part in "${parts[@]}"; do - case "$part" in - "" | .) ;; - ..) - if [[ "${#out[@]}" -eq 0 ]]; then - return 1 - fi - unset 'out[${#out[@]}-1]' - ;; - *) out+=("$part") ;; - esac - done - - local joined - joined="$( - IFS=/ - printf '%s' "${out[*]}" - )" - printf '%s' "$joined" -} - -fern_route_exists() { - local route="$1" - if ! load_fern_route_index; then - return 3 - fi - [[ -n "$FERN_ROUTE_INDEX" ]] || return 1 - - route="$(normalize_fern_route_path "$route")" || return 1 - while IFS=$'\t' read -r _source indexed_route || [[ -n "${indexed_route:-}" ]]; do - [[ "$indexed_route" == "$route" ]] && return 0 - done <<<"$FERN_ROUTE_INDEX" - return 1 -} - -fern_relative_ref_exists() { - local md_path="$1" stripped="$2" - local abs_md="$md_path" source_rel current route base - [[ "$abs_md" == /* ]] || abs_md="$REPO_ROOT/$abs_md" - case "$abs_md" in - "$REPO_ROOT/docs/"*) source_rel="${abs_md#"$REPO_ROOT/docs/"}" ;; - *) return 1 ;; - esac - - if ! load_fern_route_index; then - return 3 - fi - [[ -n "$FERN_ROUTE_INDEX" ]] || return 1 - - while IFS=$'\t' read -r _source current || [[ -n "${current:-}" ]]; do - [[ "$_source" == "$source_rel" ]] || continue - base="${current%/*}" - [[ "$base" == "$current" ]] && base="" - route="${base:+$base/}$stripped" - local _fern_rc - if fern_route_exists "$route"; then - _fern_rc=0 - else - _fern_rc=$? - fi - if [[ "$_fern_rc" -eq 0 ]]; then - return 0 - elif [[ "$_fern_rc" -eq 3 ]]; then - return 3 - fi - done <<<"$FERN_ROUTE_INDEX" - return 1 -} - -source_ref_exists() { - local base_dir="$1" stripped="$2" candidate - local -a candidates=("$stripped") - if [[ "$stripped" == */ ]]; then - candidates+=("${stripped}index.mdx" "${stripped}index.md") - else - candidates+=("$stripped.mdx" "$stripped.md" "$stripped/index.mdx" "$stripped/index.md") - fi - - for candidate in "${candidates[@]}"; do - if (cd "$base_dir" && [[ -e "$candidate" ]]); then - return 0 - fi - done - return 1 -} - -site_source_ref_exists() { - local stripped="$1" - local site_path="${stripped#/}" - local -a site_paths=("$site_path") - case "$site_path" in - nemo/guardrails/latest/*) site_paths+=("${site_path#nemo/guardrails/latest/}") ;; - nemo/guardrails/*) site_paths+=("${site_path#nemo/guardrails/}") ;; - latest/*) site_paths+=("${site_path#latest/}") ;; - esac - - local route_path - for route_path in "${site_paths[@]}"; do - if source_ref_exists "$REPO_ROOT/docs" "$route_path"; then - return 0 - fi - done - return 1 -} - -has_markdown_extension() { - case "$1" in - *.md | *.mdx) return 0 ;; - *) return 1 ;; - esac -} - -check_local_ref() { - local md_path="$1" line_no="$2" target="$3" - local stripped - - stripped="${target%%\#*}" - stripped="${stripped%%\?*}" - - [[ -z "$stripped" ]] && return 0 - [[ "$stripped" == api:* ]] && return 0 - [[ "$stripped" == mailto:* ]] && return 0 - [[ "$stripped" == tel:* ]] && return 0 - [[ "$stripped" == javascript:* ]] && return 0 - - if [[ "$stripped" == http://* || "$stripped" == https://* ]]; then - return 2 - fi - if [[ "$stripped" == *://* ]]; then - return 0 - fi - - if [[ "$stripped" == /* ]]; then - if [[ "$stripped" == /guardrails-python-sdk/* ]]; then - return 0 - fi - local _fern_rc - if fern_route_exists "$stripped"; then - _fern_rc=0 - else - _fern_rc=$? - fi - if [[ "$_fern_rc" -eq 0 ]] && has_markdown_extension "$stripped"; then - echo "check-docs-links: route-style link should omit .md/.mdx extension in $md_path:$line_no -> $target" >&2 - return 1 - fi - if [[ "$_fern_rc" -eq 0 ]]; then - return 0 - elif [[ "$_fern_rc" -eq 3 ]]; then - return 1 - fi - echo "check-docs-links: broken site route in $md_path:$line_no -> $target" >&2 - return 1 - fi - - local _fern_relative_rc - if fern_relative_ref_exists "$md_path" "$stripped"; then - _fern_relative_rc=0 - else - _fern_relative_rc=$? - fi - if [[ "$_fern_relative_rc" -eq 0 ]] && has_markdown_extension "$stripped"; then - echo "check-docs-links: route-style link should omit .md/.mdx extension in $md_path:$line_no -> $target" >&2 - return 1 - fi - if [[ "$_fern_relative_rc" -eq 0 ]]; then - return 0 - elif [[ "$_fern_relative_rc" -eq 3 ]]; then - return 1 - fi - if source_ref_exists "$(dirname "$md_path")" "$stripped"; then - return 0 - fi - echo "check-docs-links: broken local link in $md_path:$line_no -> $target" >&2 - return 1 -} - -check_remote_url() { - local url="$1" - if ! command -v "$CURL" >/dev/null 2>&1; then - echo "check-docs-links: curl not found; cannot verify $url" >&2 - return 1 - fi - if ! "$CURL" -fsS -L -o /dev/null \ - --connect-timeout 12 --max-time 35 \ - -A 'Guardrails-doc-link-check/1.0 (+https://github.com/NVIDIA-NeMo/Guardrails)' \ - "$url" 2>/dev/null; then - echo "check-docs-links: unreachable URL: $url" >&2 - return 1 - fi - return 0 -} - -normalize_url_for_ignore_match() { - local u="$1" - u="${u%%\#*}" - u="${u%/}" - printf '%s' "$u" -} - -check_docs_default_ignored_urls() { - printf '%s\n' \ - 'https://github.com/NVIDIA-NeMo/Guardrails/commits/develop' \ - 'https://github.com/NVIDIA-NeMo/Guardrails/pulls?q=is%3Apr+is%3Amerged' \ - 'https://github.com/NVIDIA-NeMo/Guardrails/pulls?q=is:pr+is:merged' -} - -url_should_skip_remote_probe() { - local url="$1" - local nu ign _re - nu="$(normalize_url_for_ignore_match "$url")" - - while IFS= read -r ign || [[ -n "${ign:-}" ]]; do - [[ -z "${ign:-}" ]] && continue - [[ "$(normalize_url_for_ignore_match "$ign")" == "$nu" ]] && return 0 - done < <(check_docs_default_ignored_urls) - - if [[ -n "${CHECK_DOC_LINKS_IGNORE_EXTRA:-}" ]]; then - local -a _extra_parts=() - local IFS=',' - read -ra _extra_parts <<<"${CHECK_DOC_LINKS_IGNORE_EXTRA}" - unset IFS - for ign in "${_extra_parts[@]}"; do - ign="${ign#"${ign%%[![:space:]]*}"}" - ign="${ign%"${ign##*[![:space:]]}"}" - [[ -z "$ign" ]] && continue - [[ "$(normalize_url_for_ignore_match "$ign")" == "$nu" ]] && return 0 - done - fi - - if [[ -n "${CHECK_DOC_LINKS_IGNORE_URL_REGEX:-}" ]]; then - _re="${CHECK_DOC_LINKS_IGNORE_URL_REGEX}" - [[ "$url" =~ $_re ]] && return 0 - fi - - return 1 -} - -run_links_check() { - local -a DOC_FILES - if [[ ${#EXTRA_FILES[@]} -gt 0 ]]; then - DOC_FILES=("${EXTRA_FILES[@]}") - else - DOC_FILES=() - while IFS= read -r _docf || [[ -n "${_docf:-}" ]]; do - [[ -z "${_docf:-}" ]] && continue - DOC_FILES+=("$_docf") - done < <(collect_default_docs | LC_ALL=C sort -u) - fi - - if [[ ${#DOC_FILES[@]} -eq 0 ]]; then - echo "check-docs-links: no Markdown/MDX files to scan under $REPO_ROOT" >&2 - return 1 - fi - - log "repository root: $REPO_ROOT" - log "scope: README, CONTRIBUTING, SECURITY, CHANGELOG, docs/**/*.{md,mdx}" - if [[ "$CHECK_DOC_LINKS_REMOTE" != 0 ]]; then - log "remote: curl unique http(s) targets (disable: CHECK_DOC_LINKS_REMOTE=0 or --local-only)" - else - log "remote: skipped (local paths only)" - fi - log "Markdown file(s) (${#DOC_FILES[@]}):" - local md - for md in "${DOC_FILES[@]}"; do - case "$md" in - "$REPO_ROOT"/*) log " ${md#"$REPO_ROOT"/}" ;; - *) log " $md" ;; - esac - done - - local failures=0 - declare -a REMOTE_URLS=() - - log "phase 1/2: local file targets and Fern routes for [](url) / ![]() / (code fences skipped)" - for md in "${DOC_FILES[@]}"; do - if [[ ! -f "$md" ]]; then - echo "check-docs-links: missing file: $md" >&2 - failures=1 - continue - fi - local target rc - local _targets_output _targets_err - _targets_err="$(mktemp)" - if ! _targets_output="$(extract_targets "$md" 2>"$_targets_err")"; then - echo "check-docs-links: malformed HTML comment in $md: $(tr '\n' ' ' <"$_targets_err" | sed 's/[[:space:]]\+/ /g; s/^ //; s/ $//')" >&2 - rm -f "$_targets_err" - failures=1 - continue - fi - rm -f "$_targets_err" - local line_no - while IFS=$'\t' read -r line_no target || [[ -n "${target:-}" ]]; do - [[ -z "$target" ]] && continue - if check_local_ref "$md" "$line_no" "$target"; then - rc=0 - else - rc=$? - fi - if [[ "$rc" -eq 0 ]]; then - continue - elif [[ "$rc" -eq 2 ]]; then - REMOTE_URLS+=("$target") - else - failures=1 - fi - done <<<"$_targets_output" - done - - if [[ "$failures" -ne 0 ]]; then - log "phase 1 failed" - return 1 - fi - log "phase 1 OK (local paths and Fern routes resolve)" - - local _n_raw _deduped _unique _i _u url - _n_raw="${#REMOTE_URLS[@]}" - _deduped="" - if [[ ${#REMOTE_URLS[@]} -gt 0 ]]; then - _deduped="$(printf '%s\n' "${REMOTE_URLS[@]}" | LC_ALL=C sort -u)" - _unique="$(printf '%s\n' "${REMOTE_URLS[@]}" | LC_ALL=C sort -u | grep -c . || true)" - else - _unique=0 - fi - log "http(s): ${_n_raw} reference(s) -> ${_unique} unique URL(s)" - if [[ -n "$_deduped" ]]; then - log "unique http(s) URL(s) (alphabetically):" - while IFS= read -r _u || [[ -n "${_u:-}" ]]; do - [[ -z "${_u:-}" ]] && continue - log " ${_u}" - done <<<"$_deduped" - fi - - if [[ "$CHECK_DOC_LINKS_REMOTE" != 0 ]]; then - if [[ -n "$_deduped" ]]; then - local _probe_list="" _skip_count=0 _probe_n=0 - while IFS= read -r url || [[ -n "${url:-}" ]]; do - [[ -z "${url:-}" ]] && continue - if url_should_skip_remote_probe "$url"; then - log " skipped (ignore list): ${url}" - _skip_count=$((_skip_count + 1)) - else - _probe_list+="${url}"$'\n' - fi - done <<<"$_deduped" - _probe_n="$(printf '%s\n' "$_probe_list" | grep -c . || true)" - log "phase 2/2: curl ${_probe_n} URL(s), ${_skip_count} skipped (GET, -L, fail 4xx/5xx)" - _i=0 - while IFS= read -r url || [[ -n "${url:-}" ]]; do - [[ -z "${url:-}" ]] && continue - _i=$((_i + 1)) - if [[ "$VERBOSE" -eq 1 ]]; then - log " [${_i}/${_probe_n}] ${url}" - fi - if ! check_remote_url "$url"; then - failures=1 - fi - done <<<"$_probe_list" - else - log "phase 2/2: no http(s) links" - fi - else - if [[ -n "$_deduped" ]]; then - log "phase 2/2: skipped ${_unique} URL(s) (local-only)" - else - log "phase 2/2: skipped (no http(s) links)" - fi - fi - - if [[ "$failures" -ne 0 ]]; then - log "phase 2 failed" - return 1 - fi - log "summary: ${#DOC_FILES[@]} file(s), local OK$( - [[ "$CHECK_DOC_LINKS_REMOTE" != 0 ]] && [[ ${_unique:-0} -gt 0 ]] && printf ', %s remote OK' "${_unique}" - )$( - [[ "$CHECK_DOC_LINKS_REMOTE" == 0 ]] && [[ ${_unique:-0} -gt 0 ]] && printf ' (%s remote not checked)' "${_unique}" - )" - log "done." -} - -run_links_check diff --git a/tests/test_docs_links.py b/tests/test_docs_links.py deleted file mode 100644 index e9ea82fe44..0000000000 --- a/tests/test_docs_links.py +++ /dev/null @@ -1,184 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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 os -import platform -import shutil -import subprocess -import tempfile -from pathlib import Path - -import pytest - -REPO_ROOT = Path(__file__).resolve().parents[1] -CHECK_DOCS_LINKS = REPO_ROOT / "scripts" / "check-docs-links.sh" - - -def run_link_check(file_path: Path, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]: - merged_env = os.environ.copy() - if env: - merged_env.update(env) - return subprocess.run( - ["bash", str(CHECK_DOCS_LINKS), "--local-only", str(file_path)], - cwd=REPO_ROOT, - env=merged_env, - text=True, - capture_output=True, - timeout=15, - check=False, - ) - - -@pytest.mark.skipif(platform.system() == "Windows", reason="bash script not available on Windows") -def test_reports_broken_local_markdown_links_with_source_line_numbers( - tmp_path: Path, -) -> None: - md_path = tmp_path / "guide.md" - (tmp_path / "exists.md").write_text("# ok\n", encoding="utf-8") - md_path.write_text( - "\n".join( - [ - "# Guide", - "", - "[working](./exists.md)", - "[broken](./missing.md)", - "```md", - "[ignored](./inside-code-fence.md)", - "```", - "", - ] - ), - encoding="utf-8", - ) - - result = run_link_check(md_path) - output = f"{result.stdout}{result.stderr}" - - assert result.returncode == 1 - assert f"broken local link in {md_path}:4 -> ./missing.md" in output - assert "inside-code-fence.md" not in output - - -@pytest.mark.skipif(platform.system() == "Windows", reason="bash script not available on Windows") -def test_ignores_links_inside_inline_code_and_html_comments(tmp_path: Path) -> None: - md_path = tmp_path / "guide.md" - md_path.write_text( - "\n".join( - [ - "# Guide", - "", - "Use `refer to [DOC PAGE](/doc/path)` as placeholder text.", - "", - "", - ] - ), - encoding="utf-8", - ) - - result = run_link_check(md_path) - output = f"{result.stdout}{result.stderr}" - - assert result.returncode == 0 - assert "/doc/path" not in output - assert "inside-comment.md" not in output - - -@pytest.mark.skipif(platform.system() == "Windows", reason="bash script not available on Windows") -def test_resolves_guardrails_fern_routes(tmp_path: Path) -> None: - md_path = tmp_path / "guide.mdx" - md_path.write_text( - "\n".join( - [ - "# Guide", - "", - "[Install](/get-started/installation-guide)", - '', - "[SDK](/guardrails-python-sdk/nemoguardrails)", - "", - ] - ), - encoding="utf-8", - ) - - result = run_link_check(md_path) - output = f"{result.stdout}{result.stderr}" - - assert result.returncode == 0, output - - -@pytest.mark.skipif(platform.system() == "Windows", reason="bash script not available on Windows") -def test_rejects_mdx_suffixes_for_links_that_resolve_as_fern_routes() -> None: - temp_dir = Path(tempfile.mkdtemp(prefix="check-docs-route-suffix-", dir=REPO_ROOT / "docs")) - try: - temp_path = temp_dir / "temp.mdx" - target_path = temp_dir / "target.mdx" - nav_path = temp_dir / "index.yml" - temp_nav_path = temp_path.relative_to(REPO_ROOT / "docs") - target_nav_path = target_path.relative_to(REPO_ROOT / "docs") - temp_path.write_text( - "\n".join( - [ - "---", - 'title: "Temporary Link Check Page"', - "---", - "", - "[Wrong](target.mdx)", - "[Right](target)", - "", - ] - ), - encoding="utf-8", - ) - target_path.write_text("# Target\n", encoding="utf-8") - nav_path.write_text( - "\n".join( - [ - "navigation:", - ' - page: "Temp"', - f" path: {temp_nav_path}", - " slug: temp", - ' - page: "Target"', - f" path: {target_nav_path}", - " slug: target", - "", - ] - ), - encoding="utf-8", - ) - - result = run_link_check(temp_path, {"CHECK_DOCS_FERN_NAV_YML": str(nav_path)}) - output = f"{result.stdout}{result.stderr}" - - assert result.returncode == 1 - assert (f"route-style link should omit .md/.mdx extension in {temp_path}:5 -> target.mdx") in output - assert f"broken local link in {temp_path}:6 -> target" not in output - finally: - shutil.rmtree(temp_dir) - - -@pytest.mark.skipif(platform.system() == "Windows", reason="bash script not available on Windows") -def test_fails_loudly_on_malformed_html_comments(tmp_path: Path) -> None: - md_path = tmp_path / "guide.md" - md_path.write_text( - "\n".join(["# Guide", "