diff --git a/.agents/skills/README.md b/.agents/skills/README.md index 8b758f45a..99546ab32 100644 --- a/.agents/skills/README.md +++ b/.agents/skills/README.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Maintainer Skills -This directory is the maintainer-only skill set for developing NeMo Flow +This directory is the maintainer-only skill set for developing NeMo Relay itself. Use these skills for repository work such as: @@ -15,5 +15,5 @@ Use these skills for repository work such as: - Extending middleware or observability internals - Validating library changes across bindings -Consumer-facing NeMo Flow usage skills live in the top-level `skills/` +Consumer-facing NeMo Relay usage skills live in the top-level `skills/` directory so they can be exported separately for integrators and end users. diff --git a/.agents/skills/add-binding-feature/SKILL.md b/.agents/skills/add-binding-feature/SKILL.md index bf1c91f31..7c37bbd40 100644 --- a/.agents/skills/add-binding-feature/SKILL.md +++ b/.agents/skills/add-binding-feature/SKILL.md @@ -1,6 +1,6 @@ --- name: add-binding-feature -description: Add or change a public NeMo Flow API surface across the core runtime and every affected binding +description: Add or change a public NeMo Relay API surface across the core runtime and every affected binding author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -32,7 +32,7 @@ Do not use this skill for: 2. **FFI / shared C surface** Add or update FFI wrappers in the relevant `crates/ffi/src/api/*.rs` module, re-export them through `crates/ffi/src/api/mod.rs`, and ensure the - generated `crates/ffi/nemo_flow.h` stays correct. + generated `crates/ffi/nemo_relay.h` stays correct. 3. **Language-native bindings** Update Python, Go, Node.js, and WebAssembly for every surface that should expose the capability. @@ -50,10 +50,10 @@ Do not use this skill for: | Layer | Convention | Example | |-------------|-------------------|--------------------------------------| -| Rust | `snake_case` | `nemo_flow_tool_call` | -| C FFI | `nemo_flow_` prefix | `nemo_flow_tool_call` | -| Python | `snake_case` | `nemo_flow.tools.call` | -| Go | `PascalCase` | `nemo_flow.ToolCall` | +| Rust | `snake_case` | `nemo_relay_tool_call` | +| C FFI | `nemo_relay_` prefix | `nemo_relay_tool_call` | +| Python | `snake_case` | `nemo_relay.tools.call` | +| Go | `PascalCase` | `nemo_relay.ToolCall` | | Node.js | `camelCase` | `toolCall` | | WebAssembly | `camelCase` | `toolCall` | @@ -66,9 +66,9 @@ Do not use this skill for: re-export in `crates/ffi/src/api/mod.rs` - [ ] Regenerate the shared library/header path with `just build-go` - [ ] Python native binding in `crates/python/src/py_api/mod.rs` -- [ ] Python wrapper with docstring in `python/nemo_flow/.py` -- [ ] Python type stubs updated in the relevant `python/nemo_flow/*.pyi` modules -- [ ] Go wrapper in `go/nemo_flow/nemo_flow.go` with doc comment +- [ ] Python wrapper with docstring in `python/nemo_relay/.py` +- [ ] Python type stubs updated in the relevant `python/nemo_relay/*.pyi` modules +- [ ] Go wrapper in `go/nemo_relay/nemo_relay.go` with doc comment - [ ] Go shorthand package updated if the capability belongs there - [ ] Node.js binding in `crates/node/src/api/mod.rs` - [ ] WebAssembly binding in `crates/wasm/src/api/mod.rs` diff --git a/.agents/skills/add-integration/SKILL.md b/.agents/skills/add-integration/SKILL.md index 829eabd44..2aeab32c9 100644 --- a/.agents/skills/add-integration/SKILL.md +++ b/.agents/skills/add-integration/SKILL.md @@ -1,6 +1,6 @@ --- name: add-integration -description: Add a new third-party framework integration maintained as a NeMo Flow patch set +description: Add a new third-party framework integration maintained as a NeMo Relay patch set author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -NeMo Flow integrations with upstream projects are maintained as manifest-pinned +NeMo Relay integrations with upstream projects are maintained as manifest-pinned local upstream checkouts under `third_party/`, bootstrapped from `third_party/sources.lock`, with corresponding patch files in `patches/`. @@ -24,9 +24,9 @@ exists and you are refreshing an existing patch set, use ## Required Patterns -- `nemo_flow` stays an optional dependency -- Framework behavior must fall back cleanly when NeMo Flow is unavailable -- Tool calls and LLM calls should use NeMo Flow managed execution where possible +- `nemo_relay` stays an optional dependency +- Framework behavior must fall back cleanly when NeMo Relay is unavailable +- Tool calls and LLM calls should use NeMo Relay managed execution where possible - Scope creation should mirror the framework's natural agent, graph, or function boundaries - Scope stack propagation must be explicit across worker threads or async @@ -68,16 +68,16 @@ This root command is the stable public wrapper. The implementation lives under ``` third_party// # local upstream checkout pinned by third_party/sources.lock -patches// # tracked NeMo Flow integration patch set - 0001-add-nemo-flow-integration.patch +patches// # tracked NeMo Relay integration patch set + 0001-add-nemo-relay-integration.patch ``` ## Checklist - [ ] Upstream checkout exists under `third_party/` - [ ] Optional import / activation guard is in place -- [ ] Tool calls are wrapped through NeMo Flow where appropriate -- [ ] LLM calls are wrapped through NeMo Flow where appropriate +- [ ] Tool calls are wrapped through NeMo Relay where appropriate +- [ ] LLM calls are wrapped through NeMo Relay where appropriate - [ ] Scope boundaries match the framework's execution model - [ ] Context propagation is correct across async or thread boundaries - [ ] Integration patch regenerates cleanly into `patches//` diff --git a/.agents/skills/add-middleware/SKILL.md b/.agents/skills/add-middleware/SKILL.md index 1bc2226a4..c4bd69f0a 100644 --- a/.agents/skills/add-middleware/SKILL.md +++ b/.agents/skills/add-middleware/SKILL.md @@ -1,6 +1,6 @@ --- name: add-middleware -description: Add a new guardrail or intercept type to the NeMo Flow middleware pipeline +description: Add a new guardrail or intercept type to the NeMo Relay middleware pipeline author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -NeMo Flow supports guardrails (validate/gate) and intercepts (transform) at various +NeMo Relay supports guardrails (validate/gate) and intercepts (transform) at various pipeline stages. Adding a new middleware type requires changes across all layers. Use this skill when introducing a new middleware registration surface or adding @@ -54,7 +54,7 @@ See `docs/about/concepts/middleware.md` for the full diagrams. pub type MyNewFn = Box Json + Send + Sync>; ``` -2. Add the registry field to `NemoFlowContextState` in +2. Add the registry field to `NemoRelayContextState` in `crates/core/src/api/runtime/state.rs`. Add a `SortedRegistry>` or `SortedRegistry>` @@ -66,7 +66,7 @@ Use the existing `global_*_registry_api!` and `scope_*_registry_api!` macro patterns in `crates/core/src/api/registry.rs`. Both global and scope-local variants are needed unless the design explicitly rules one out. -4. Add chain execution helpers to `NemoFlowContextState` in +4. Add chain execution helpers to `NemoRelayContextState` in `crates/core/src/api/runtime/state.rs`. Follow the pattern of `tool_sanitize_request_chain` or `tool_request_intercepts_chain`. diff --git a/.agents/skills/contribute-api/SKILL.md b/.agents/skills/contribute-api/SKILL.md index 502727734..d9968fe72 100644 --- a/.agents/skills/contribute-api/SKILL.md +++ b/.agents/skills/contribute-api/SKILL.md @@ -1,6 +1,6 @@ --- name: contribute-api -description: Contribute a new NeMo Flow public API surface safely, with binding parity and docs in mind +description: Contribute a new NeMo Relay public API surface safely, with binding parity and docs in mind author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- diff --git a/.agents/skills/contribute-docs/SKILL.md b/.agents/skills/contribute-docs/SKILL.md index 2780793d9..765acf2ed 100644 --- a/.agents/skills/contribute-docs/SKILL.md +++ b/.agents/skills/contribute-docs/SKILL.md @@ -1,6 +1,6 @@ --- name: contribute-docs -description: Contribute documentation or example changes that stay aligned with NeMo Flow public behavior +description: Contribute documentation or example changes that stay aligned with NeMo Relay public behavior author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- diff --git a/.agents/skills/contribute-integration/SKILL.md b/.agents/skills/contribute-integration/SKILL.md index c8d1f69b7..84fea48fb 100644 --- a/.agents/skills/contribute-integration/SKILL.md +++ b/.agents/skills/contribute-integration/SKILL.md @@ -1,6 +1,6 @@ --- name: contribute-integration -description: Contribute a new or updated third-party framework integration for NeMo Flow +description: Contribute a new or updated third-party framework integration for NeMo Relay author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -19,8 +19,8 @@ as LangChain, LangGraph, or another patched third-party project. ## Default Guidance -- Keep NeMo Flow optional -- Preserve the framework's original behavior when NeMo Flow is absent +- Keep NeMo Relay optional +- Preserve the framework's original behavior when NeMo Relay is absent - Wrap tool and LLM paths at the correct framework boundary - Keep the tracked patch artifact minimal and reproducible diff --git a/.agents/skills/maintain-ci/SKILL.md b/.agents/skills/maintain-ci/SKILL.md index 1a1c0300c..050350b16 100644 --- a/.agents/skills/maintain-ci/SKILL.md +++ b/.agents/skills/maintain-ci/SKILL.md @@ -1,6 +1,6 @@ --- name: maintain-ci -description: Maintain and review NeMo Flow GitHub Actions workflows with explicit per-job permissions, pinned action SHAs, deterministic caching, reusable workflow permission boundaries, and local validation +description: Maintain and review NeMo Relay GitHub Actions workflows with explicit per-job permissions, pinned action SHAs, deterministic caching, reusable workflow permission boundaries, and local validation author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- diff --git a/.agents/skills/maintain-integration-patches/SKILL.md b/.agents/skills/maintain-integration-patches/SKILL.md index adf6a3199..37e4e67f3 100644 --- a/.agents/skills/maintain-integration-patches/SKILL.md +++ b/.agents/skills/maintain-integration-patches/SKILL.md @@ -1,6 +1,6 @@ --- name: maintain-integration-patches -description: Refresh, rebase, regenerate, and validate existing NeMo Flow third-party integration patches +description: Refresh, rebase, regenerate, and validate existing NeMo Relay third-party integration patches author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -Use this skill when an existing `patches//0001-add-nemo-flow-integration.patch` +Use this skill when an existing `patches//0001-add-nemo-relay-integration.patch` has drifted against the pinned upstream checkout or needs regeneration after local changes. @@ -54,7 +54,7 @@ This root command is the stable public wrapper. The implementation lives under - Do not apply patches on top of a dirty upstream checkout unless you explicitly understand and intend the merge state. - Prefer the repo patch scripts over ad hoc `git diff > patch` workflows. -- Keep the patch minimal and focused on the NeMo Flow integration surface. +- Keep the patch minimal and focused on the NeMo Relay integration surface. - If upstream drift changes behavior, update docs or test expectations in the same branch. diff --git a/.agents/skills/maintain-observability/SKILL.md b/.agents/skills/maintain-observability/SKILL.md index 4ba3f9a06..222c5a070 100644 --- a/.agents/skills/maintain-observability/SKILL.md +++ b/.agents/skills/maintain-observability/SKILL.md @@ -1,6 +1,6 @@ --- name: maintain-observability -description: Maintain or extend NeMo Flow observability surfaces across ATIF, OpenTelemetry, and OpenInference +description: Maintain or extend NeMo Relay observability surfaces across ATIF, OpenTelemetry, and OpenInference author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- diff --git a/.agents/skills/maintain-optimizer/SKILL.md b/.agents/skills/maintain-optimizer/SKILL.md index 8a59c3002..3546457b4 100644 --- a/.agents/skills/maintain-optimizer/SKILL.md +++ b/.agents/skills/maintain-optimizer/SKILL.md @@ -1,6 +1,6 @@ --- name: maintain-optimizer -description: Maintain or extend the NeMo Flow adaptive surface across config, plugins, docs, and bindings; use this when users still say optimizer +description: Maintain or extend the NeMo Relay adaptive surface across config, plugins, docs, and bindings; use this when users still say optimizer author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -38,10 +38,10 @@ See `docs/plugins/adaptive/configuration.md` and - `crates/adaptive` - Shared plugin behavior in core and bindings -- Python adaptive/plugin wrappers in `python/nemo_flow/adaptive.py` and - `python/nemo_flow/plugin.py` -- Go adaptive helpers under `go/nemo_flow/adaptive` plus shared plugin - helpers in `go/nemo_flow` +- Python adaptive/plugin wrappers in `python/nemo_relay/adaptive.py` and + `python/nemo_relay/plugin.py` +- Go adaptive helpers under `go/nemo_relay/adaptive` plus shared plugin + helpers in `go/nemo_relay` - Node/WebAssembly adaptive helpers and plugin wrappers - Docs and examples that show canonical config shapes diff --git a/.agents/skills/maintain-packaging/SKILL.md b/.agents/skills/maintain-packaging/SKILL.md index 0463ee0ea..7fac31161 100644 --- a/.agents/skills/maintain-packaging/SKILL.md +++ b/.agents/skills/maintain-packaging/SKILL.md @@ -1,6 +1,6 @@ --- name: maintain-packaging -description: Maintain NeMo Flow package metadata, module paths, generated artifacts, and release-facing build surfaces +description: Maintain NeMo Relay package metadata, module paths, generated artifacts, and release-facing build surfaces author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,14 +14,14 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -Use this skill when a change affects how NeMo Flow is built, packaged, named, or +Use this skill when a change affects how NeMo Relay is built, packaged, named, or consumed outside the source tree. ## Audit Areas - Rust `Cargo.toml` package names and workspace metadata - Python packaging in `pyproject.toml` -- Go module path in `go/nemo_flow/go.mod` +- Go module path in `go/nemo_relay/go.mod` - Node workspace metadata in root `package.json` and `package-lock.json` - Node package metadata in `crates/node/package.json` - WebAssembly package naming and generated package expectations @@ -42,7 +42,7 @@ consumed outside the source tree. ## References - `pyproject.toml` -- `go/nemo_flow/go.mod` +- `go/nemo_relay/go.mod` - `package.json` - `package-lock.json` - `crates/node/package.json` diff --git a/.agents/skills/prepare-code-freeze/SKILL.md b/.agents/skills/prepare-code-freeze/SKILL.md index 0e2523ed2..749e33883 100644 --- a/.agents/skills/prepare-code-freeze/SKILL.md +++ b/.agents/skills/prepare-code-freeze/SKILL.md @@ -1,13 +1,13 @@ --- name: prepare-code-freeze -description: Prepare a NeMo Flow code freeze by creating the release branch, updating nightly alpha branch config, bumping main to the next version, and opening the required PR +description: Prepare a NeMo Relay code freeze by creating the release branch, updating nightly alpha branch config, bumping main to the next version, and opening the required PR author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- # Prepare Code Freeze -Use this skill when the user asks to start, prepare, or automate a NeMo Flow +Use this skill when the user asks to start, prepare, or automate a NeMo Relay code freeze. ## Companion Guidance @@ -18,7 +18,7 @@ opening the PR. ## Workflow This workflow assumes `upstream` is the NVIDIA repository remote -(`NVIDIA/NeMo-Flow`). The `origin` remote can be a maintainer's personal fork. +(`NVIDIA/NeMo-Relay`). The `origin` remote can be a maintainer's personal fork. 1. Confirm or infer the target release version from `upstream/main:Cargo.toml`. Derive the release branch as `release/.`. diff --git a/.agents/skills/prepare-pr/SKILL.md b/.agents/skills/prepare-pr/SKILL.md index 0884043bd..2ca9ca3ca 100644 --- a/.agents/skills/prepare-pr/SKILL.md +++ b/.agents/skills/prepare-pr/SKILL.md @@ -1,12 +1,12 @@ --- name: prepare-pr -description: Prepare, open, create, publish, update, or edit a NeMo Flow pull request or PR body with the right tests, docs, contributor hygiene, and repository pull request template +description: Prepare, open, create, publish, update, or edit a NeMo Relay pull request or PR body with the right tests, docs, contributor hygiene, and repository pull request template author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- -# Prepare A PR For NeMo Flow +# Prepare A PR For NeMo Relay ## Companion Guidance @@ -16,7 +16,7 @@ before editing. Use this skill at the end of a contributor or maintainer change before opening a pull request. Also use it whenever a user asks to create, open, publish, update, -or edit a NeMo Flow pull request, pull request description, or PR body. +or edit a NeMo Relay pull request, pull request description, or PR body. If this repo-local guidance conflicts with generic GitHub publishing, connector, or plugin guidance, this skill wins for PR body format, validation language, and diff --git a/.agents/skills/rename-surfaces/SKILL.md b/.agents/skills/rename-surfaces/SKILL.md index 5b4318f75..6636faba9 100644 --- a/.agents/skills/rename-surfaces/SKILL.md +++ b/.agents/skills/rename-surfaces/SKILL.md @@ -1,6 +1,6 @@ --- name: rename-surfaces -description: Perform a coordinated repository, package, crate, module, or symbol rename across NeMo Flow +description: Perform a coordinated repository, package, crate, module, or symbol rename across NeMo Relay author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -34,7 +34,7 @@ or branding text updates that must preserve functional identifiers. - Separate **branding text** from **functional identifiers**. - Preserve repository and import paths exactly where code depends on them. - Update generated or generated-from-build surfaces such as - `crates/ffi/nemo_flow.h` through the proper build step. + `crates/ffi/nemo_relay.h` through the proper build step. - Search for old names after the rename and validate every public language surface. diff --git a/.agents/skills/review-doc-style/SKILL.md b/.agents/skills/review-doc-style/SKILL.md index d02fdb40f..83d752393 100644 --- a/.agents/skills/review-doc-style/SKILL.md +++ b/.agents/skills/review-doc-style/SKILL.md @@ -16,13 +16,13 @@ before editing. Use this skill when reviewing docs-only changes, example-heavy changes, or any public-facing text update that should be checked against NVIDIA style guidance -and NeMo Flow repo conventions. +and NeMo Relay repo conventions. ## Review Priorities - Prioritize factual accuracy over copy polish - Flag stale commands, package names, APIs, bindings, repo paths, or support claims before stylistic issues -- Keep docs aligned with current NeMo Flow behavior, repo layout, and entry points +- Keep docs aligned with current NeMo Relay behavior, repo layout, and entry points - Apply NVIDIA technical-writing guidance where it improves clarity and consistency without watering down technical precision ## Review Flow @@ -33,7 +33,7 @@ and NeMo Flow repo conventions. - `README.md` - `docs/index.md` - Package or crate READMEs - - Binding-level source READMEs such as `python/nemo_flow/README.md` or `crates/core/README.md` + - Binding-level source READMEs such as `python/nemo_relay/README.md` or `crates/core/README.md` 4. Start with `assets/nvidia-style-guide.md`, then open only the focused support document needed for the issue under review. 5. Scan for high-signal style issues in headings, links, code formatting, terminology, procedures, and plain-English readability. 6. Report findings in severity order with file references and concrete rewrites. diff --git a/.agents/skills/review-doc-style/assets/nvidia-style-guide.md b/.agents/skills/review-doc-style/assets/nvidia-style-guide.md index 85a96414f..e53048f5f 100644 --- a/.agents/skills/review-doc-style/assets/nvidia-style-guide.md +++ b/.agents/skills/review-doc-style/assets/nvidia-style-guide.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # NVIDIA Style Guidance for Agents -Use this file as the first-pass reference for NeMo Flow documentation reviews. +Use this file as the first-pass reference for NeMo Relay documentation reviews. It condenses NVIDIA writing guidance into review actions and points to focused support documents for deeper checks. -This guide is not a substitute for verifying repository facts. For NeMo Flow +This guide is not a substitute for verifying repository facts. For NeMo Relay docs, factual accuracy and current API behavior are more important than copy polish. @@ -85,7 +85,7 @@ available. Keep the finding body focused on the reader impact and the fix. ## Common Agent Pitfalls - Do not enforce marketing or social-media rules on technical documentation. -- Do not add trademark symbols to NeMo Flow learning docs by default. +- Do not add trademark symbols to NeMo Relay learning docs by default. - Do not replace precise technical terms with simpler words when precision would be lost. - Do not flag passive voice when the actor is unknown or the action is the important part. - Do not rewrite API names, package names, command flags, or code literals for style. diff --git a/.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md b/.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md index 2808136ca..5882a9ab7 100644 --- a/.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md +++ b/.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md @@ -30,7 +30,7 @@ Use this table for common review calls: | Item | Format | Review Signal | |---|---|---| | Code elements, commands, parameters, package names, expressions | Monospace | Flag prose such as "run just test-rust" and rewrite as `run just test-rust`. | -| Directories, file names, and paths | Monospace | Use backticks around paths such as `python/nemo_flow/README.md`. | +| Directories, file names, and paths | Monospace | Use backticks around paths such as `python/nemo_relay/README.md`. | | Variables inside paths | Angle brackets inside monospace | Prefer `/home//.login` for placeholders. | | Error messages and strings | Quotation marks | Keep literal code strings in code formatting when that is clearer. | | UI buttons, menus, fields, and labels | Bold | Example: Select **Save**. | diff --git a/.agents/skills/small-fix/SKILL.md b/.agents/skills/small-fix/SKILL.md index e6b32f415..239e5cd6f 100644 --- a/.agents/skills/small-fix/SKILL.md +++ b/.agents/skills/small-fix/SKILL.md @@ -1,6 +1,6 @@ --- name: small-fix -description: Make a small, reviewable NeMo Flow bug fix without widening scope unnecessarily +description: Make a small, reviewable NeMo Relay bug fix without widening scope unnecessarily author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- diff --git a/.agents/skills/test-ffi-surface/SKILL.md b/.agents/skills/test-ffi-surface/SKILL.md index b16872d07..c79ec2f54 100644 --- a/.agents/skills/test-ffi-surface/SKILL.md +++ b/.agents/skills/test-ffi-surface/SKILL.md @@ -1,6 +1,6 @@ --- name: test-ffi-surface -description: Build and test the NeMo Flow FFI surface; use this for crates/ffi changes, header generation, or ABI-facing validation +description: Build and test the NeMo Relay FFI surface; use this for crates/ffi changes, header generation, or ABI-facing validation author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -36,11 +36,11 @@ just build-go # Required Rust validation cargo fmt --all just test-rust -cargo test -p nemo-flow-ffi +cargo test -p nemo-relay-ffi cargo clippy --workspace --all-targets -- -D warnings # Review header drift if the FFI surface changed -git diff -- crates/ffi/nemo_flow.h +git diff -- crates/ffi/nemo_relay.h ``` ## When To Escalate @@ -54,7 +54,7 @@ git diff -- crates/ffi/nemo_flow.h - `crates/ffi/Cargo.toml` - `crates/ffi/build.rs` - `crates/ffi/cbindgen.toml` -- `crates/ffi/nemo_flow.h` +- `crates/ffi/nemo_relay.h` - `just build-go` - `.pre-commit-config.yaml` - `README.md` diff --git a/.agents/skills/test-go-binding/SKILL.md b/.agents/skills/test-go-binding/SKILL.md index b3ec6c070..e790cedee 100644 --- a/.agents/skills/test-go-binding/SKILL.md +++ b/.agents/skills/test-go-binding/SKILL.md @@ -1,6 +1,6 @@ --- name: test-go-binding -description: Build and test the NeMo Flow Go binding; use this for go/nemo_flow changes or Go-facing integration checks +description: Build and test the NeMo Relay Go binding; use this for go/nemo_relay changes or Go-facing integration checks author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -Use this skill when the change is primarily in `go/nemo_flow` or the Go +Use this skill when the change is primarily in `go/nemo_relay` or the Go binding behavior it depends on. ## Important Constraint @@ -25,7 +25,7 @@ you want an explicit build-only pass or need the artifact for other work. ## Default Path -1. Format changed Go packages with `cd go/nemo_flow && go fmt ./...`. +1. Format changed Go packages with `cd go/nemo_relay && go fmt ./...`. 2. Run Go tests with `just test-go`. 3. If any Rust files changed as part of the Go work, also run `cargo fmt --all`, `just test-rust`, and @@ -41,7 +41,7 @@ you want an explicit build-only pass or need the artifact for other work. just test-go # Format Go files -cd go/nemo_flow && go fmt ./... +cd go/nemo_relay && go fmt ./... # Required when the Go change also touched Rust code cargo fmt --all @@ -70,8 +70,8 @@ directory before running the raw `go test` command directly. ## References -- `go/nemo_flow/go.mod` -- `go/nemo_flow/nemo_flow.go` +- `go/nemo_relay/go.mod` +- `go/nemo_relay/nemo_relay.go` - `README.md` - `docs/getting-started/installation.md` - `validate-change` diff --git a/.agents/skills/test-node-binding/SKILL.md b/.agents/skills/test-node-binding/SKILL.md index adb685fec..6feed60fb 100644 --- a/.agents/skills/test-node-binding/SKILL.md +++ b/.agents/skills/test-node-binding/SKILL.md @@ -1,6 +1,6 @@ --- name: test-node-binding -description: Build and test the NeMo Flow Node.js binding; use this for crates/node changes or Node-facing integration checks +description: Build and test the NeMo Relay Node.js binding; use this for crates/node changes or Node-facing integration checks author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -19,7 +19,7 @@ Node surface, or Node-facing examples/docs. ## Default Path -1. Format changed Node files with `npm run format --workspace=nemo-flow-node`. +1. Format changed Node files with `npm run format --workspace=nemo-relay-node`. 2. Install dependencies and build with `just build-node` when you need to validate packaging/build output. 3. Run `just test-node` for the normal dev/test loop. @@ -36,7 +36,7 @@ Node surface, or Node-facing examples/docs. just build-node # Format Node files -npm run format --workspace=nemo-flow-node +npm run format --workspace=nemo-relay-node # Standard test loop just test-node @@ -54,7 +54,7 @@ just ci=true test-node ```bash # Public API docstring checks when surface docs changed -npm run check:docstrings --workspace=nemo-flow-node +npm run check:docstrings --workspace=nemo-relay-node ``` ## When To Escalate diff --git a/.agents/skills/test-python-binding/SKILL.md b/.agents/skills/test-python-binding/SKILL.md index b30811303..360038309 100644 --- a/.agents/skills/test-python-binding/SKILL.md +++ b/.agents/skills/test-python-binding/SKILL.md @@ -1,6 +1,6 @@ --- name: test-python-binding -description: Build and test the NeMo Flow Python binding; use this for python/nemo_flow or crates/python changes +description: Build and test the NeMo Relay Python binding; use this for python/nemo_relay or crates/python changes author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -Use this skill when the change is primarily in `python/nemo_flow`, +Use this skill when the change is primarily in `python/nemo_relay`, `python/tests`, `crates/python`, or Python-facing docs/examples. ## Default Path @@ -27,7 +27,7 @@ Use this skill when the change is primarily in `python/nemo_flow`, `cargo clippy --workspace --all-targets -- -D warnings`. 5. Use `just build-python` when you want an explicit build-only pass. 6. If the native Rust bridge changed, add the Rust crate tests for - `nemo-flow-python`. + `nemo-relay-python`. ## Python Test Style @@ -69,7 +69,7 @@ cargo clippy --workspace --all-targets -- -D warnings just build-python # Native extension crate when crates/python changed -cargo test -p nemo-flow-python +cargo test -p nemo-relay-python ``` ## When To Escalate @@ -84,7 +84,7 @@ cargo test -p nemo-flow-python - `pyproject.toml` - `crates/python/Cargo.toml` - `crates/python/README.md` -- `python/nemo_flow/README.md` +- `python/nemo_relay/README.md` - `docs/getting-started/python.md` - `docs/contribute/testing-and-docs.md` - `validate-change` diff --git a/.agents/skills/test-rust-core/SKILL.md b/.agents/skills/test-rust-core/SKILL.md index 671b17a5a..b6d774677 100644 --- a/.agents/skills/test-rust-core/SKILL.md +++ b/.agents/skills/test-rust-core/SKILL.md @@ -1,6 +1,6 @@ --- name: test-rust-core -description: Build and test the NeMo Flow Rust core and adaptive crates; use this for crates/core, crates/adaptive, or shared runtime semantics changes +description: Build and test the NeMo Relay Rust core and adaptive crates; use this for crates/core, crates/adaptive, or shared runtime semantics changes author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -41,10 +41,10 @@ cargo fmt --all cargo clippy --workspace --all-targets -- -D warnings # Core runtime only -cargo test -p nemo-flow +cargo test -p nemo-relay # Adaptive crate when touched -cargo test -p nemo-flow-adaptive +cargo test -p nemo-relay-adaptive # Compile sweep just build-rust diff --git a/.agents/skills/test-wasm-binding/SKILL.md b/.agents/skills/test-wasm-binding/SKILL.md index 99edac7ea..43c238329 100644 --- a/.agents/skills/test-wasm-binding/SKILL.md +++ b/.agents/skills/test-wasm-binding/SKILL.md @@ -1,6 +1,6 @@ --- name: test-wasm-binding -description: Build and test the NeMo Flow WebAssembly binding; use this for crates/wasm changes or WebAssembly-facing integration checks +description: Build and test the NeMo Relay WebAssembly binding; use this for crates/wasm changes or WebAssembly-facing integration checks author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -20,14 +20,14 @@ or the WebAssembly-facing runtime surface. ## Default Path 1. Format changed WebAssembly JS/TS wrapper files with - `npm run precommit:format --workspace=nemo-flow-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts`. + `npm run precommit:format --workspace=nemo-relay-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts`. 2. Run the WebAssembly tests with `just test-wasm`. 3. If any Rust files changed as part of the WebAssembly work, also run `cargo fmt --all`, `just test-rust`, and `cargo clippy --workspace --all-targets -- -D warnings`. 4. Use `just build-wasm` when you want an explicit packaging/build pass. 5. Use `just ci=true test-wasm` when you need coverage reports. -6. Add `cargo test -p nemo-flow-wasm` when Rust-only WebAssembly helpers changed. +6. Add `cargo test -p nemo-relay-wasm` when Rust-only WebAssembly helpers changed. ## Common Commands @@ -36,7 +36,7 @@ or the WebAssembly-facing runtime surface. just test-wasm # Format WebAssembly JS/TS wrapper files -npm run precommit:format --workspace=nemo-flow-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts +npm run precommit:format --workspace=nemo-relay-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts # Required when the WebAssembly change also touched Rust code cargo fmt --all @@ -53,7 +53,7 @@ just ci=true build-wasm just ci=true test-wasm # Rust-side WebAssembly crate tests when needed -cargo test -p nemo-flow-wasm +cargo test -p nemo-relay-wasm ``` In the `justfile`, both `build-wasm` and `test-wasm` check the `ci` variable. diff --git a/.agents/skills/update-project-version/SKILL.md b/.agents/skills/update-project-version/SKILL.md index fd0de0833..0974e665d 100644 --- a/.agents/skills/update-project-version/SKILL.md +++ b/.agents/skills/update-project-version/SKILL.md @@ -1,6 +1,6 @@ --- name: update-project-version -description: Update the NeMo Flow project version across Cargo, Node, generated WebAssembly package metadata, and lockfiles without leaving release surfaces out of sync +description: Update the NeMo Relay project version across Cargo, Node, generated WebAssembly package metadata, and lockfiles without leaving release surfaces out of sync author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -14,7 +14,7 @@ Use `karpathy-guidelines` alongside this skill for implementation or review work. Keep changes scoped, surface assumptions, and define focused validation before editing. -Use this skill when changing the released NeMo Flow version, including +Use this skill when changing the released NeMo Relay version, including pre-release or build-metadata variants used during packaging. ## Source Of Truth @@ -43,9 +43,9 @@ pre-release or build-metadata variants used during packaging. version string. 2. Run `just set-version ` to update release-version source files: - `[workspace.package].version` - - `workspace.dependencies.nemo-flow.version` - - `workspace.dependencies.nemo-flow-adaptive.version` - - `workspace.dependencies.nemo-flow-ffi.version` + - `workspace.dependencies.nemo-relay.version` + - `workspace.dependencies.nemo-relay-adaptive.version` + - `workspace.dependencies.nemo-relay-ffi.version` - `crates/node/package.json` `version` - `integrations/openclaw/package.json` `version` - `package-lock.json` `packages["crates/node"].version` @@ -66,7 +66,7 @@ pre-release or build-metadata variants used during packaging. `./scripts/generate_attributions.sh node`. - If the change needs WebAssembly publish validation, rebuild the generated package with `just build-wasm` or - `NEMO_FLOW_WASM_RELEASE=1 npm run build:pkg --workspace=nemo-flow-wasm`. Inspect + `NEMO_RELAY_WASM_RELEASE=1 npm run build:pkg --workspace=nemo-relay-wasm`. Inspect `crates/wasm/pkg/package.json`, not `crates/wasm/package.json`. 5. Audit remaining references to the old version with targeted search. Separate true version pins from examples, generated attribution files, and unrelated @@ -74,7 +74,7 @@ pre-release or build-metadata variants used during packaging. ## Validation -- `rg -n '^version =|nemo-flow = \\{ version =|nemo-flow-adaptive = \\{ version =' Cargo.toml` +- `rg -n '^version =|nemo-relay = \\{ version =|nemo-relay-adaptive = \\{ version =' Cargo.toml` - `rg -n '\"version\"' crates/node/package.json integrations/openclaw/package.json package-lock.json` - `cargo check --workspace` - If Rust attribution files are expected to stay current: diff --git a/.agents/skills/validate-change/SKILL.md b/.agents/skills/validate-change/SKILL.md index 66d825a3c..c4204c2ab 100644 --- a/.agents/skills/validate-change/SKILL.md +++ b/.agents/skills/validate-change/SKILL.md @@ -1,6 +1,6 @@ --- name: validate-change -description: Choose and run the right NeMo Flow validation matrix for a change instead of using one fixed test list +description: Choose and run the right NeMo Relay validation matrix for a change instead of using one fixed test list author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -89,17 +89,17 @@ uv run pytest -k "" # Go just build-go just test-go -cd go/nemo_flow && go fmt ./... +cd go/nemo_relay && go fmt ./... # Node just build-node just test-node -npm run format --workspace=nemo-flow-node +npm run format --workspace=nemo-relay-node # WebAssembly just build-wasm just test-wasm -npm run precommit:format --workspace=nemo-flow-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts +npm run precommit:format --workspace=nemo-relay-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts # Third-party patches ./scripts/bootstrap-third-party.sh diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 1fc2b1b9a..72ff8cf9c 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -70,22 +70,22 @@ reviews: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety, callback error propagation, stable type conversion, and consistent async/stream semantics. Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere. - - path: "python/nemo_flow/**/*" + - path: "python/nemo_relay/**/*" instructions: | Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension. Stubs and runtime implementations should stay aligned. - - path: "go/nemo_flow/**/*" + - path: "go/nemo_relay/**/*" instructions: | Review Go binding changes for cgo memory ownership, race safety, callback cleanup, idiomatic exported APIs, and parity with Rust/FFI behavior. Any API change should include focused Go tests and consider race-test behavior. - - path: "{crates/**/tests/**,python/tests/**,go/nemo_flow/**/*_test.go}" + - path: "{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}" instructions: | Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant. Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests. - path: "patches/**/*.patch" instructions: | Patch changes should remain reviewable as regenerated diffs against the matching third_party submodule. - Check that integration behavior, package metadata, and tests remain consistent with the main NeMo Flow API. + Check that integration behavior, package metadata, and tests remain consistent with the main NeMo Relay API. - path: "{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}" instructions: | Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings. diff --git a/.github/ISSUE_TEMPLATE/01-bug.yml b/.github/ISSUE_TEMPLATE/01-bug.yml index d35f712ef..bf5b66fa7 100644 --- a/.github/ISSUE_TEMPLATE/01-bug.yml +++ b/.github/ISSUE_TEMPLATE/01-bug.yml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 name: Bug -description: Report a reproducible defect in NeMo Flow. +description: Report a reproducible defect in NeMo Relay. title: "[Bug]: " type: Bug body: @@ -33,14 +33,14 @@ body: attributes: label: Current behavior description: Describe what happened, including any error messages, traces, or incorrect output. - placeholder: NeMo Flow currently... + placeholder: NeMo Relay currently... validations: {required: true} - type: textarea id: expected_behavior attributes: label: Expected behavior description: Describe what you expected to happen. - placeholder: I expected NeMo Flow to... + placeholder: I expected NeMo Relay to... validations: {required: true} - type: textarea id: steps_to_reproduce @@ -58,7 +58,7 @@ body: label: Environment description: Include versions, platform, installation source, and relevant toolchain details. placeholder: | - - NeMo Flow version or commit: + - NeMo Relay version or commit: - OS and architecture: - Rust version: - Python version: diff --git a/.github/ISSUE_TEMPLATE/02-enhancement.yml b/.github/ISSUE_TEMPLATE/02-enhancement.yml index 7c844e38a..3310ced90 100644 --- a/.github/ISSUE_TEMPLATE/02-enhancement.yml +++ b/.github/ISSUE_TEMPLATE/02-enhancement.yml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 name: Enhancement -description: Propose a focused improvement to existing NeMo Flow behavior. +description: Propose a focused improvement to existing NeMo Relay behavior. title: "[Enhancement]: " type: Enhancement body: diff --git a/.github/actions/load-ci-tool-versions/action.yml b/.github/actions/load-ci-tool-versions/action.yml index 6f0750bf7..31be9d3c2 100644 --- a/.github/actions/load-ci-tool-versions/action.yml +++ b/.github/actions/load-ci-tool-versions/action.yml @@ -53,18 +53,18 @@ runs: source "${GITHUB_ACTION_PATH}/../../ci-tool-versions.env" required=( - NEMO_FLOW_CI_GO_VERSION - NEMO_FLOW_CI_DEFAULT_PYTHON_VER - NEMO_FLOW_CI_RUST_VERSION - NEMO_FLOW_CI_NODE_VERSION - NEMO_FLOW_CI_UV_VERSION - NEMO_FLOW_CI_PRE_COMMIT_VERSION - NEMO_FLOW_CI_JUST_VERSION - NEMO_FLOW_CI_WASM_PACK_VERSION - NEMO_FLOW_CI_CARGO_LLVM_COV_VERSION - NEMO_FLOW_CI_CARGO_NEXTEST_VERSION - NEMO_FLOW_CI_CARGO_DENY_VERSION - NEMO_FLOW_CI_CARGO_ABOUT_VERSION + NEMO_RELAY_CI_GO_VERSION + NEMO_RELAY_CI_DEFAULT_PYTHON_VER + NEMO_RELAY_CI_RUST_VERSION + NEMO_RELAY_CI_NODE_VERSION + NEMO_RELAY_CI_UV_VERSION + NEMO_RELAY_CI_PRE_COMMIT_VERSION + NEMO_RELAY_CI_JUST_VERSION + NEMO_RELAY_CI_WASM_PACK_VERSION + NEMO_RELAY_CI_CARGO_LLVM_COV_VERSION + NEMO_RELAY_CI_CARGO_NEXTEST_VERSION + NEMO_RELAY_CI_CARGO_DENY_VERSION + NEMO_RELAY_CI_CARGO_ABOUT_VERSION ) for name in "${required[@]}"; do @@ -75,16 +75,16 @@ runs: done { - printf 'go_version=%s\n' "$NEMO_FLOW_CI_GO_VERSION" - printf 'default_python_version=%s\n' "$NEMO_FLOW_CI_DEFAULT_PYTHON_VER" - printf 'rust_version=%s\n' "$NEMO_FLOW_CI_RUST_VERSION" - printf 'node_version=%s\n' "$NEMO_FLOW_CI_NODE_VERSION" - printf 'uv_version=%s\n' "$NEMO_FLOW_CI_UV_VERSION" - printf 'pre_commit_version=%s\n' "$NEMO_FLOW_CI_PRE_COMMIT_VERSION" - printf 'just_version=%s\n' "$NEMO_FLOW_CI_JUST_VERSION" - printf 'wasm_pack_version=%s\n' "$NEMO_FLOW_CI_WASM_PACK_VERSION" - printf 'cargo_llvm_cov_version=%s\n' "$NEMO_FLOW_CI_CARGO_LLVM_COV_VERSION" - printf 'cargo_nextest_version=%s\n' "$NEMO_FLOW_CI_CARGO_NEXTEST_VERSION" - printf 'cargo_deny_version=%s\n' "$NEMO_FLOW_CI_CARGO_DENY_VERSION" - printf 'cargo_about_version=%s\n' "$NEMO_FLOW_CI_CARGO_ABOUT_VERSION" + printf 'go_version=%s\n' "$NEMO_RELAY_CI_GO_VERSION" + printf 'default_python_version=%s\n' "$NEMO_RELAY_CI_DEFAULT_PYTHON_VER" + printf 'rust_version=%s\n' "$NEMO_RELAY_CI_RUST_VERSION" + printf 'node_version=%s\n' "$NEMO_RELAY_CI_NODE_VERSION" + printf 'uv_version=%s\n' "$NEMO_RELAY_CI_UV_VERSION" + printf 'pre_commit_version=%s\n' "$NEMO_RELAY_CI_PRE_COMMIT_VERSION" + printf 'just_version=%s\n' "$NEMO_RELAY_CI_JUST_VERSION" + printf 'wasm_pack_version=%s\n' "$NEMO_RELAY_CI_WASM_PACK_VERSION" + printf 'cargo_llvm_cov_version=%s\n' "$NEMO_RELAY_CI_CARGO_LLVM_COV_VERSION" + printf 'cargo_nextest_version=%s\n' "$NEMO_RELAY_CI_CARGO_NEXTEST_VERSION" + printf 'cargo_deny_version=%s\n' "$NEMO_RELAY_CI_CARGO_DENY_VERSION" + printf 'cargo_about_version=%s\n' "$NEMO_RELAY_CI_CARGO_ABOUT_VERSION" } >> "$GITHUB_OUTPUT" diff --git a/.github/ci-path-filters.yml b/.github/ci-path-filters.yml index ec6a27674..ca4ea67f0 100644 --- a/.github/ci-path-filters.yml +++ b/.github/ci-path-filters.yml @@ -27,7 +27,7 @@ rust_package: - 'crates/ffi/Cargo.toml' - 'crates/ffi/build.rs' - 'crates/ffi/cbindgen.toml' - - 'crates/ffi/nemo_flow.h' + - 'crates/ffi/nemo_relay.h' - 'crates/ffi/src/**' - 'justfile' - 'rust-toolchain.toml' @@ -63,7 +63,7 @@ python_package: - 'crates/python/src/**' - 'justfile' - 'pyproject.toml' - - 'python/nemo_flow/**' + - 'python/nemo_relay/**' - 'rust-toolchain.toml' - 'uv.lock' @@ -71,9 +71,9 @@ python_integration_langchain: # Includes LangGraph and DeepAgents integrations as well - 'justfile' - 'pyproject.toml' - - 'python/nemo_flow/integrations/deepagents/**' - - 'python/nemo_flow/integrations/langchain/**' - - 'python/nemo_flow/integrations/langgraph/**' + - 'python/nemo_relay/integrations/deepagents/**' + - 'python/nemo_relay/integrations/langchain/**' + - 'python/nemo_relay/integrations/langgraph/**' - 'python/tests/integrations/conftest.py' - 'python/tests/integrations/deepagents_tests/**' - 'python/tests/integrations/langchain_tests/**' @@ -118,7 +118,7 @@ docs: - 'crates/**/*.md' - 'docs/**' - 'integrations/coding-agents/**' - - 'python/nemo_flow/**' + - 'python/nemo_relay/**' - 'scripts/build-docs.sh' - 'scripts/docs/**' @@ -134,7 +134,7 @@ go: - 'crates/ffi/Cargo.toml' - 'crates/ffi/build.rs' - 'crates/ffi/cbindgen.toml' - - 'crates/ffi/nemo_flow.h' + - 'crates/ffi/nemo_relay.h' - 'crates/ffi/src/**' - 'go/**/!(*.md)' diff --git a/.github/ci-tool-versions.env b/.github/ci-tool-versions.env index cd2741998..5cfd96f6f 100644 --- a/.github/ci-tool-versions.env +++ b/.github/ci-tool-versions.env @@ -1,15 +1,15 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -NEMO_FLOW_CI_GO_VERSION=1.26.1 -NEMO_FLOW_CI_DEFAULT_PYTHON_VER=3.11 -NEMO_FLOW_CI_RUST_VERSION=1.93.0 -NEMO_FLOW_CI_NODE_VERSION=24 -NEMO_FLOW_CI_UV_VERSION=0.9.28 -NEMO_FLOW_CI_PRE_COMMIT_VERSION=4.5 -NEMO_FLOW_CI_JUST_VERSION=1.47.1 -NEMO_FLOW_CI_WASM_PACK_VERSION=0.14.0 -NEMO_FLOW_CI_CARGO_LLVM_COV_VERSION=0.8.5 -NEMO_FLOW_CI_CARGO_NEXTEST_VERSION=0.9.133 -NEMO_FLOW_CI_CARGO_DENY_VERSION=0.19.1 -NEMO_FLOW_CI_CARGO_ABOUT_VERSION=0.8.4 +NEMO_RELAY_CI_GO_VERSION=1.26.1 +NEMO_RELAY_CI_DEFAULT_PYTHON_VER=3.11 +NEMO_RELAY_CI_RUST_VERSION=1.93.0 +NEMO_RELAY_CI_NODE_VERSION=24 +NEMO_RELAY_CI_UV_VERSION=0.9.28 +NEMO_RELAY_CI_PRE_COMMIT_VERSION=4.5 +NEMO_RELAY_CI_JUST_VERSION=1.47.1 +NEMO_RELAY_CI_WASM_PACK_VERSION=0.14.0 +NEMO_RELAY_CI_CARGO_LLVM_COV_VERSION=0.8.5 +NEMO_RELAY_CI_CARGO_NEXTEST_VERSION=0.9.133 +NEMO_RELAY_CI_CARGO_DENY_VERSION=0.19.1 +NEMO_RELAY_CI_CARGO_ABOUT_VERSION=0.8.4 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3800e303c..e909f80f6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -345,7 +345,7 @@ jobs: ( cd release-assets - cli_assets=(nemo-flow-cli-*) + cli_assets=(nemo-relay-cli-*) sha256sum "${cli_assets[@]}" > SHA256SUMS sha256sum --check SHA256SUMS @@ -418,7 +418,7 @@ jobs: CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }} run: | set -euo pipefail - for package in nemo-flow nemo-flow-adaptive nemo-flow-ffi nemo-flow-cli; do + for package in nemo-relay nemo-relay-adaptive nemo-relay-ffi nemo-relay-cli; do cargo publish --package "$package" --no-verify --allow-dirty done @@ -491,7 +491,7 @@ jobs: if [[ "${{ github.ref_name }}" =~ -(alpha|beta|rc)\.[0-9]+$ ]]; then npm_tag="next" fi - printf 'NEMO_FLOW_NPM_DIST_TAG=%s\n' "$npm_tag" >> "$GITHUB_ENV" + printf 'NEMO_RELAY_NPM_DIST_TAG=%s\n' "$npm_tag" >> "$GITHUB_ENV" - name: Publish Node.js package to npm run: | @@ -499,14 +499,14 @@ jobs: unzip -q ./consolidated.zip -d combined echo "Platform binaries included:" ls -la combined/package/*.node - npm publish ./combined/package --access public --tag "${NEMO_FLOW_NPM_DIST_TAG}" + npm publish ./combined/package --access public --tag "${NEMO_RELAY_NPM_DIST_TAG}" - name: Publish OpenClaw plugin package to npm run: | set -euo pipefail for pkg in ./openclaw-package/*.tgz; do echo "Publishing ${pkg}..." - npm publish "${pkg}" --access public --tag "${NEMO_FLOW_NPM_DIST_TAG}" + npm publish "${pkg}" --access public --tag "${NEMO_RELAY_NPM_DIST_TAG}" done - name: Publish WebAssembly package to npm @@ -514,5 +514,5 @@ jobs: set -e for pkg in ./wasm-package/*.tgz; do echo "Publishing ${pkg}..." - npm publish "${pkg}" --access public --tag "${NEMO_FLOW_NPM_DIST_TAG}" + npm publish "${pkg}" --access public --tag "${NEMO_RELAY_NPM_DIST_TAG}" done diff --git a/.github/workflows/ci_check.yml b/.github/workflows/ci_check.yml index e11e78af3..b0b063378 100644 --- a/.github/workflows/ci_check.yml +++ b/.github/workflows/ci_check.yml @@ -28,8 +28,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -54,7 +54,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: @@ -78,7 +78,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -99,12 +99,12 @@ jobs: with: path: ${{ runner.temp }}/.cache/pre-commit key: >- - nemo-flow-pre-commit-${{ runner.os }}-${{ runner.arch }}-py${{ steps.ci-config.outputs.default_python_version }}-node${{ steps.ci-config.outputs.node_version }}-rust${{ steps.ci-config.outputs.rust_version }}-pc${{ steps.ci-config.outputs.pre_commit_version }}-${{ hashFiles('.pre-commit-config.yaml') }} + nemo-relay-pre-commit-${{ runner.os }}-${{ runner.arch }}-py${{ steps.ci-config.outputs.default_python_version }}-node${{ steps.ci-config.outputs.node_version }}-rust${{ steps.ci-config.outputs.rust_version }}-pc${{ steps.ci-config.outputs.pre_commit_version }}-${{ hashFiles('.pre-commit-config.yaml') }} restore-keys: | - nemo-flow-pre-commit-${{ runner.os }}-${{ runner.arch }}-py${{ steps.ci-config.outputs.default_python_version }}-node${{ steps.ci-config.outputs.node_version }}-rust${{ steps.ci-config.outputs.rust_version }}-pc${{ steps.ci-config.outputs.pre_commit_version }}- + nemo-relay-pre-commit-${{ runner.os }}-${{ runner.arch }}-py${{ steps.ci-config.outputs.default_python_version }}-node${{ steps.ci-config.outputs.node_version }}-rust${{ steps.ci-config.outputs.rust_version }}-pc${{ steps.ci-config.outputs.pre_commit_version }}- - name: pre-commit - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} env: FULL_CI: ${{ inputs.full_ci }} PRE_COMMIT_BASE: ${{ inputs.base }} @@ -120,7 +120,7 @@ jobs: FLOW_CI_UV_SYNC_EXTRA_ARGS+=(--extra langchain --extra langgraph --extra deepagents) fi - uv sync --inexact --no-install-project --no-install-package nemo-flow "${FLOW_CI_UV_SYNC_EXTRA_ARGS[@]}" + uv sync --inexact --no-install-project --no-install-package nemo-relay "${FLOW_CI_UV_SYNC_EXTRA_ARGS[@]}" if [[ "$FULL_CI" == "true" || -z "$PRE_COMMIT_BASE" ]]; then pre-commit run --all-files --show-diff-on-failure else diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 10142f030..2b88c04a5 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -26,8 +26,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -52,7 +52,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 with: @@ -66,7 +66,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -82,40 +82,40 @@ jobs: tool: just@${{ steps.ci-config.outputs.just_version }},sphinx-rustdocgen@1.0.1 - name: Install Documentation Dependencies - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: uv sync --no-default-groups --group docs --no-install-project - name: Install Node.js Documentation Dependencies - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: npm ci --ignore-scripts - name: Materialize Main Branch For Versioned Docs if: ${{ inputs.ref_type == 'tag' }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: git fetch --force origin +refs/heads/main:refs/heads/main - name: Check Documentation Links - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} env: - NEMO_FLOW_DOCS_DEPS_READY: "1" + NEMO_RELAY_DOCS_DEPS_READY: "1" run: just docs-linkcheck - name: Build Documentation Site if: ${{ startsWith(inputs.ref_name, 'pull-request/') || inputs.ref_name == 'main' }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} env: - NEMO_FLOW_DOCS_DEPS_READY: "1" + NEMO_RELAY_DOCS_DEPS_READY: "1" run: just docs - name: Build Versioned Documentation Site if: ${{ inputs.publish_docs }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} env: - NEMO_FLOW_DOCS_DEPS_READY: "1" + NEMO_RELAY_DOCS_DEPS_READY: "1" run: just docs-github-pages - name: Upload GitHub Pages Artifact if: ${{ inputs.publish_docs }} uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5 with: - path: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/docs/_build/pages + path: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/docs/_build/pages diff --git a/.github/workflows/ci_go.yml b/.github/workflows/ci_go.yml index c4cf7d761..9cdf4ebdc 100644 --- a/.github/workflows/ci_go.yml +++ b/.github/workflows/ci_go.yml @@ -16,8 +16,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -62,7 +62,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -74,7 +74,7 @@ jobs: cache: false - name: Run Go tests with coverage - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e just --set ci true --set output_dir "${{ github.workspace }}" test-go diff --git a/.github/workflows/ci_node.yml b/.github/workflows/ci_node.yml index 977eb92c1..d15e01569 100644 --- a/.github/workflows/ci_node.yml +++ b/.github/workflows/ci_node.yml @@ -35,8 +35,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -77,7 +77,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -92,12 +92,12 @@ jobs: node-version: ${{ steps.ci-config.outputs.node_version }} - name: Run Node tests with coverage - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: just --set ci true --set output_dir "${{ github.workspace }}" test-node - name: Run OpenClaw integration checks if: ${{ inputs.run_openclaw }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: just --set ci true test-openclaw - name: Upload Node coverage to Codecov @@ -149,7 +149,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -160,7 +160,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - name: Install managed Python for Zig packaging if: ${{ startsWith(matrix.platform, 'linux-') }} @@ -180,11 +180,11 @@ jobs: if: ${{ inputs.run_package }} run: | set -e - mkdir -p "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/npm" + mkdir -p "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/npm" - name: Derive Node package version if: ${{ inputs.run_package }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e version="$(node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync("crates/node/package.json", "utf8")); if (!pkg.version) { throw new Error("crates/node/package.json missing version field"); } console.log(pkg.version);')" @@ -194,17 +194,17 @@ jobs: else version="${version}+${sha}" fi - printf 'NEMO_FLOW_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" + printf 'NEMO_RELAY_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" - name: Package Node if: ${{ inputs.run_package }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e just \ --set ci true \ - --set output_dir "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}" \ - --set ref_name "${NEMO_FLOW_PACKAGE_VERSION}" \ + --set output_dir "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}" \ + --set ref_name "${NEMO_RELAY_PACKAGE_VERSION}" \ package-node - name: Upload npm package artifact @@ -212,7 +212,7 @@ jobs: if: ${{ inputs.run_package }} with: name: npm-${{ matrix.platform }} - path: ${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/npm/*.tgz + path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/npm/*.tgz if-no-files-found: error PackageOpenClaw: @@ -238,7 +238,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-openclaw-package-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-openclaw-package-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -253,7 +253,7 @@ jobs: tool: just@${{ steps.ci-config.outputs.just_version }} - name: Derive OpenClaw package version - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e version="$(node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync("integrations/openclaw/package.json", "utf8")); if (!pkg.version) { throw new Error("integrations/openclaw/package.json missing version field"); } console.log(pkg.version);')" @@ -263,23 +263,23 @@ jobs: else version="${version}+${sha}" fi - printf 'NEMO_FLOW_OPENCLAW_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" + printf 'NEMO_RELAY_OPENCLAW_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" - name: Package OpenClaw plugin - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -euo pipefail just \ --set ci true \ - --set output_dir "${NEMO_FLOW_CI_WORKSPACE_TMP}" \ - --set ref_name "${NEMO_FLOW_OPENCLAW_PACKAGE_VERSION}" \ + --set output_dir "${NEMO_RELAY_CI_WORKSPACE_TMP}" \ + --set ref_name "${NEMO_RELAY_OPENCLAW_PACKAGE_VERSION}" \ package-openclaw - name: Upload OpenClaw plugin artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: openclaw-npm - path: ${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/openclaw/*.tgz + path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/openclaw/*.tgz if-no-files-found: error Consolidate: diff --git a/.github/workflows/ci_python.yml b/.github/workflows/ci_python.yml index 7242f1cb8..5e3ef8b66 100644 --- a/.github/workflows/ci_python.yml +++ b/.github/workflows/ci_python.yml @@ -35,8 +35,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -77,7 +77,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -91,7 +91,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - name: Set up Windows ARM Python if: ${{ matrix.platform == 'windows-arm64' }} @@ -133,12 +133,12 @@ jobs: Add-Content -Path $env:GITHUB_ENV -Value "VCPKGRS_TRIPLET=arm64-windows-static-md" - name: Run Python tests with coverage - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: just --set ci true --set output_dir "${{ github.workspace }}" test-python - name: Run Python LangChain integration tests if: ${{ inputs.run_integration_langchain == 'true' }} - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: just --set ci true --set output_dir "${{ github.workspace }}" test-python-langchain - name: Upload Python coverage to Codecov @@ -152,7 +152,7 @@ jobs: verbose: true - name: Prune uv cache - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: uv cache prune --ci Package: @@ -193,7 +193,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -202,7 +202,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - name: Set up Windows ARM Python if: ${{ matrix.platform == 'windows-arm64' }} @@ -233,10 +233,10 @@ jobs: - name: Create packaging output directory run: | set -e - mkdir -p "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/wheels" + mkdir -p "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/wheels" - name: Derive Python package version - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)" @@ -250,24 +250,24 @@ jobs: else version="${version}+${sha}" fi - printf 'NEMO_FLOW_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" + printf 'NEMO_RELAY_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" - name: Package Python wheel - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e just \ - --set output_dir "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}" \ - --set ref_name "${NEMO_FLOW_PACKAGE_VERSION}" \ + --set output_dir "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}" \ + --set ref_name "${NEMO_RELAY_PACKAGE_VERSION}" \ package-python - name: Upload wheel artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: wheel-${{ matrix.platform }} - path: ${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/wheels/*.whl + path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/wheels/*.whl if-no-files-found: error - name: Prune uv cache - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: uv cache prune --ci diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index fb956d526..167b035dd 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -22,8 +22,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -84,7 +84,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -93,7 +93,7 @@ jobs: with: version: ${{ steps.ci-config.outputs.uv_version }} enable-cache: true - cache-dependency-glob: ${{ env.NEMO_FLOW_CI_WORKSPACE }}/uv.lock + cache-dependency-glob: ${{ env.NEMO_RELAY_CI_WORKSPACE }}/uv.lock - name: Set up Windows ARM Python if: ${{ matrix.platform == 'windows-arm64' }} @@ -130,7 +130,7 @@ jobs: tool: cargo-llvm-cov@${{ steps.ci-config.outputs.cargo_llvm_cov_version }},cargo-nextest@${{ steps.ci-config.outputs.cargo_nextest_version }},just@${{ steps.ci-config.outputs.just_version }} - name: Run Rust tests with coverage - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e args=( @@ -138,7 +138,7 @@ jobs: --set output_dir "${{ github.workspace }}" ) if [ "${{ matrix.run_redis_tests }}" = "true" ]; then - export NEMO_FLOW_RUN_REDIS_TESTS=1 + export NEMO_RELAY_RUN_REDIS_TESTS=1 fi just "${args[@]}" test-rust @@ -197,7 +197,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -211,13 +211,13 @@ jobs: sudo apt-get install -y musl-tools - name: Build CLI release binary - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e - cargo build --release --target "${{ matrix.target }}" -p nemo-flow-cli + cargo build --release --target "${{ matrix.target }}" -p nemo-relay-cli - name: Stage CLI binary artifact - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -euo pipefail target="${{ matrix.target }}" @@ -225,24 +225,24 @@ jobs: if [ "${{ github.ref_type }}" != "tag" ]; then version="dev-${GIT_COMMIT::8}" fi - binary="nemo-flow" - asset="nemo-flow-cli-${target}-${version}" + binary="nemo-relay" + asset="nemo-relay-cli-${target}-${version}" if [ "${{ runner.os }}" = "Windows" ]; then binary="${binary}.exe" asset="${asset}.exe" fi - source="${NEMO_FLOW_CI_WORKSPACE}/target/${target}/release/${binary}" + source="${NEMO_RELAY_CI_WORKSPACE}/target/${target}/release/${binary}" if [ ! -f "$source" ]; then echo "Error: expected CLI binary at ${source}" >&2 exit 1 fi - rm -rf "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli" - mkdir -p "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli" - cp "$source" "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli/${asset}" + rm -rf "${NEMO_RELAY_CI_WORKSPACE_TMP}/cli" + mkdir -p "${NEMO_RELAY_CI_WORKSPACE_TMP}/cli" + cp "$source" "${NEMO_RELAY_CI_WORKSPACE_TMP}/cli/${asset}" - name: Upload CLI binary artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: cli-${{ matrix.platform }} - path: ${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/cli/* + path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/cli/* if-no-files-found: error diff --git a/.github/workflows/ci_wasm.yml b/.github/workflows/ci_wasm.yml index ff75f3931..ed750da83 100644 --- a/.github/workflows/ci_wasm.yml +++ b/.github/workflows/ci_wasm.yml @@ -30,8 +30,8 @@ defaults: env: GH_TOKEN: "${{ github.token }}" GIT_COMMIT: "${{ github.sha }}" - NEMO_FLOW_CI_WORKSPACE: "${{ github.workspace }}" - NEMO_FLOW_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" + NEMO_RELAY_CI_WORKSPACE: "${{ github.workspace }}" + NEMO_RELAY_CI_WORKSPACE_TMP: "${{ github.workspace }}/tmp" UV_PYTHON_DOWNLOADS: never jobs: @@ -72,7 +72,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -91,7 +91,7 @@ jobs: tool: wasm-pack@${{ steps.ci-config.outputs.wasm_pack_version }} - name: Run WebAssembly tests with coverage - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: just --set ci true --set output_dir "${{ github.workspace }}" test-wasm - name: Upload WebAssembly coverage to Codecov @@ -127,7 +127,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: nemo-flow-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} + shared-key: nemo-relay-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.ci-config.outputs.rust_version }} workspaces: . -> target cache-all-crates: true cache-bin: false @@ -144,10 +144,10 @@ jobs: - name: Create packaging output directory run: | set -e - mkdir -p "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/wasm" + mkdir -p "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/wasm" - name: Derive WebAssembly package version - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)" @@ -161,20 +161,20 @@ jobs: else version="${version}-${sha}" fi - printf 'NEMO_FLOW_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" + printf 'NEMO_RELAY_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV" - name: Package WebAssembly bundler - working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} + working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }} run: | set -e just \ - --set output_dir "${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}" \ - --set ref_name "${NEMO_FLOW_PACKAGE_VERSION}" \ + --set output_dir "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}" \ + --set ref_name "${NEMO_RELAY_PACKAGE_VERSION}" \ package-wasm - name: Upload WebAssembly package artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: wasm-bundler - path: ${{ env.NEMO_FLOW_CI_WORKSPACE_TMP }}/wasm/*.tgz + path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/wasm/*.tgz if-no-files-found: error diff --git a/.github/workflows/nightly-alpha-tag.yaml b/.github/workflows/nightly-alpha-tag.yaml index cf00d1bc1..99873d071 100644 --- a/.github/workflows/nightly-alpha-tag.yaml +++ b/.github/workflows/nightly-alpha-tag.yaml @@ -54,13 +54,13 @@ jobs: - name: Create nightly alpha tag env: - NEMO_FLOW_NIGHTLY_BRANCH: ${{ matrix.branch }} - NEMO_FLOW_NIGHTLY_TAG_TOKEN: ${{ secrets.NEMO_FLOW_NIGHTLY_TAG_TOKEN }} + NEMO_RELAY_NIGHTLY_BRANCH: ${{ matrix.branch }} + NEMO_RELAY_NIGHTLY_TAG_TOKEN: ${{ secrets.NEMO_RELAY_NIGHTLY_TAG_TOKEN }} run: | set -euo pipefail - if [[ -z "$NEMO_FLOW_NIGHTLY_TAG_TOKEN" ]]; then - echo "Error: NEMO_FLOW_NIGHTLY_TAG_TOKEN is required so the tag push can trigger tag CI." >&2 + if [[ -z "$NEMO_RELAY_NIGHTLY_TAG_TOKEN" ]]; then + echo "Error: NEMO_RELAY_NIGHTLY_TAG_TOKEN is required so the tag push can trigger tag CI." >&2 exit 1 fi @@ -83,10 +83,10 @@ jobs: existing_sha="$(git ls-remote --tags origin "refs/tags/${tag}" | awk '{print $1}' || true)" fi if [[ "$existing_sha" == "$target_sha" ]]; then - echo "Nightly alpha tag already exists for ${NEMO_FLOW_NIGHTLY_BRANCH}: ${tag}" + echo "Nightly alpha tag already exists for ${NEMO_RELAY_NIGHTLY_BRANCH}: ${tag}" exit 0 fi - echo "Error: nightly alpha tag ${tag} already exists at ${existing_sha}, not ${NEMO_FLOW_NIGHTLY_BRANCH} HEAD ${target_sha}" >&2 + echo "Error: nightly alpha tag ${tag} already exists at ${existing_sha}, not ${NEMO_RELAY_NIGHTLY_BRANCH} HEAD ${target_sha}" >&2 exit 1 fi @@ -94,9 +94,9 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git tag \ --annotate \ - --message "NeMo Flow ${version} Nightly ${tag_date}" \ + --message "NeMo Relay ${version} Nightly ${tag_date}" \ "$tag" \ "$target_sha" - git remote set-url origin "https://x-access-token:${NEMO_FLOW_NIGHTLY_TAG_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git remote set-url origin "https://x-access-token:${NEMO_RELAY_NIGHTLY_TAG_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" git push origin "refs/tags/${tag}" - echo "Created nightly alpha tag for ${NEMO_FLOW_NIGHTLY_BRANCH}: ${tag}" + echo "Created nightly alpha tag for ${NEMO_RELAY_NIGHTLY_BRANCH}: ${tag}" diff --git a/.gitignore b/.gitignore index 961eb3287..f267ae45b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,14 +11,14 @@ __pycache__/ *.pyo *.egg-info/ *.so -python/nemo_flow/_native*.so +python/nemo_relay/_native*.so # Python (Windows) -python/nemo_flow/_native*.pyd +python/nemo_relay/_native*.pyd # Go -go/nemo_flow/nemo_flow_test -go/nemo_flow/nemo_flow_test.exe +go/nemo_relay/nemo_relay_test +go/nemo_relay/nemo_relay_test.exe # Node.js (NAPI-RS) node_modules/ @@ -47,7 +47,7 @@ crates/wasm/junit.xml .coverage *.profraw *.profdata -go/nemo_flow/coverage.out +go/nemo_relay/coverage.out go_junit_report.xml *.dSYM/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 329ff8fdb..755b825b5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,16 +15,16 @@ stages: - publish variables: - NEMO_FLOW_CI_DEBIAN_VERSION: "trixie" - NEMO_FLOW_CI_JUST_VERSION: "1.40.0" - NEMO_FLOW_CI_NODE_VERSION: "24" - NEMO_FLOW_CI_PYTHON_VERSION: "3.11" - NEMO_FLOW_CI_RUST_VERSION: "1.93.0" - NEMO_FLOW_CI_UV_VERSION: "0.9.28" - NEMO_FLOW_CI_GITHUB_REPOSITORY: "NVIDIA/NeMo-Flow" - NEMO_FLOW_CI_GITHUB_WORKFLOW_FILE: "ci.yaml" - NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS: "7200" - NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS: "60" + NEMO_RELAY_CI_DEBIAN_VERSION: "trixie" + NEMO_RELAY_CI_JUST_VERSION: "1.40.0" + NEMO_RELAY_CI_NODE_VERSION: "24" + NEMO_RELAY_CI_PYTHON_VERSION: "3.11" + NEMO_RELAY_CI_RUST_VERSION: "1.93.0" + NEMO_RELAY_CI_UV_VERSION: "0.9.28" + NEMO_RELAY_CI_GITHUB_REPOSITORY: "NVIDIA/NeMo-Relay" + NEMO_RELAY_CI_GITHUB_WORKFLOW_FILE: "ci.yaml" + NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS: "7200" + NEMO_RELAY_CI_GITHUB_RUN_POLL_SECONDS: "60" check:sonar: stage: check @@ -60,11 +60,11 @@ collect:github-artifacts: - | set -eu - if [ -z "${NEMO_FLOW_CI_GITHUB_TOKEN:-}" ]; then - echo "Error: NEMO_FLOW_CI_GITHUB_TOKEN is required to download GitHub Actions artifacts." >&2 + if [ -z "${NEMO_RELAY_CI_GITHUB_TOKEN:-}" ]; then + echo "Error: NEMO_RELAY_CI_GITHUB_TOKEN is required to download GitHub Actions artifacts." >&2 exit 1 fi - export GH_TOKEN="${NEMO_FLOW_CI_GITHUB_TOKEN}" + export GH_TOKEN="${NEMO_RELAY_CI_GITHUB_TOKEN}" mkdir -p collected/wheels collected/wasm collected/node downloaded @@ -75,24 +75,24 @@ collect:github-artifacts: fi tag_ref="tags/${tag}" - deadline="$(( $(date -u +%s) + NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS ))" + deadline="$(( $(date -u +%s) + NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS ))" - echo "Waiting for tag ${tag} in ${NEMO_FLOW_CI_GITHUB_REPOSITORY}" - while ! gh api "repos/${NEMO_FLOW_CI_GITHUB_REPOSITORY}/git/ref/${tag_ref}" >/dev/null 2>&1; do + echo "Waiting for tag ${tag} in ${NEMO_RELAY_CI_GITHUB_REPOSITORY}" + while ! gh api "repos/${NEMO_RELAY_CI_GITHUB_REPOSITORY}/git/ref/${tag_ref}" >/dev/null 2>&1; do if [ "$(date -u +%s)" -ge "$deadline" ]; then - echo "Error: tag ${tag} did not appear within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2 + echo "Error: tag ${tag} did not appear within ${NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2 exit 1 fi - sleep "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS" + sleep "$NEMO_RELAY_CI_GITHUB_RUN_POLL_SECONDS" done - echo "Waiting for ${NEMO_FLOW_CI_GITHUB_WORKFLOW_FILE} run for tag ${tag}" + echo "Waiting for ${NEMO_RELAY_CI_GITHUB_WORKFLOW_FILE} run for tag ${tag}" run_id="" while [ -z "$run_id" ]; do run_id="$( gh run list \ - --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" \ - --workflow "$NEMO_FLOW_CI_GITHUB_WORKFLOW_FILE" \ + --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" \ + --workflow "$NEMO_RELAY_CI_GITHUB_WORKFLOW_FILE" \ --event push \ --branch "$tag" \ --limit 1 \ @@ -103,10 +103,10 @@ collect:github-artifacts: break fi if [ "$(date -u +%s)" -ge "$deadline" ]; then - echo "Error: no GitHub Actions run found for tag ${tag} within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2 + echo "Error: no GitHub Actions run found for tag ${tag} within ${NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2 exit 1 fi - sleep "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS" + sleep "$NEMO_RELAY_CI_GITHUB_RUN_POLL_SECONDS" done if [ -z "$run_id" ]; then echo "Error: no GitHub Actions run found for tag ${tag}." >&2 @@ -115,23 +115,23 @@ collect:github-artifacts: run_html_url="$( gh run view "$run_id" \ - --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" \ + --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" \ --json url \ --jq '.url' )" echo "Watching GitHub Actions run ${run_id} for tag ${tag}: ${run_html_url}" - if ! timeout "$NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS" \ + if ! timeout "$NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS" \ gh run watch "$run_id" \ - --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" \ - --interval "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS" \ + --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" \ + --interval "$NEMO_RELAY_CI_GITHUB_RUN_POLL_SECONDS" \ --exit-status; then - echo "Error: GitHub Actions run ${run_id} for tag ${tag} failed, was cancelled, or did not complete within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds: ${run_html_url}" >&2 + echo "Error: GitHub Actions run ${run_id} for tag ${tag} failed, was cancelled, or did not complete within ${NEMO_RELAY_CI_GITHUB_RUN_WAIT_SECONDS} seconds: ${run_html_url}" >&2 exit 1 fi - gh run download "$run_id" --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" --pattern 'wheel-*' --dir downloaded/wheels - gh run download "$run_id" --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" --name wasm-bundler --dir downloaded/wasm - gh run download "$run_id" --repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" --name npm-consolidated --dir downloaded/node + gh run download "$run_id" --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" --pattern 'wheel-*' --dir downloaded/wheels + gh run download "$run_id" --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" --name wasm-bundler --dir downloaded/wasm + gh run download "$run_id" --repo "$NEMO_RELAY_CI_GITHUB_REPOSITORY" --name npm-consolidated --dir downloaded/node find downloaded/wheels -type f -name '*.whl' -exec cp {} collected/wheels/ \; find downloaded/wasm -type f -name '*.tgz' -exec cp {} collected/wasm/ \; @@ -159,7 +159,7 @@ collect:github-artifacts: printf '{\n' printf ' "run_id": "%s",\n' "$run_id" printf ' "run_url": "%s",\n' "$run_html_url" - printf ' "workflow": "%s",\n' "$NEMO_FLOW_CI_GITHUB_WORKFLOW_FILE" + printf ' "workflow": "%s",\n' "$NEMO_RELAY_CI_GITHUB_WORKFLOW_FILE" printf ' "tag": "%s"\n' "$tag" printf '}\n' } > collected/github-run.json @@ -176,7 +176,7 @@ collect:github-artifacts: publish:artifactory:wheels: stage: publish image: - name: ghcr.io/astral-sh/uv:${NEMO_FLOW_CI_UV_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION}-slim + name: ghcr.io/astral-sh/uv:${NEMO_RELAY_CI_UV_VERSION}-${NEMO_RELAY_CI_DEBIAN_VERSION}-slim pull_policy: if-not-present rules: - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG @@ -188,8 +188,8 @@ publish:artifactory:wheels: - | set -eu - if [ -z "${NEMO_FLOW_CI_ARTIFACTORY_USER:-}" ] || [ -z "${NEMO_FLOW_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_FLOW_CI_ARTIFACTORY_PYPI_URL:-}" ]; then - echo "Error: uploading wheels to Artifactory requires NEMO_FLOW_CI_ARTIFACTORY_USER, NEMO_FLOW_CI_ARTIFACTORY_KEY, and NEMO_FLOW_CI_ARTIFACTORY_PYPI_URL." >&2 + if [ -z "${NEMO_RELAY_CI_ARTIFACTORY_USER:-}" ] || [ -z "${NEMO_RELAY_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_RELAY_CI_ARTIFACTORY_PYPI_URL:-}" ]; then + echo "Error: uploading wheels to Artifactory requires NEMO_RELAY_CI_ARTIFACTORY_USER, NEMO_RELAY_CI_ARTIFACTORY_KEY, and NEMO_RELAY_CI_ARTIFACTORY_PYPI_URL." >&2 exit 1 fi if ! ls collected/wheels/*.whl >/dev/null 2>&1; then @@ -197,15 +197,15 @@ publish:artifactory:wheels: exit 1 fi - UV_PUBLISH_USERNAME="${NEMO_FLOW_CI_ARTIFACTORY_USER}" \ - UV_PUBLISH_PASSWORD="${NEMO_FLOW_CI_ARTIFACTORY_KEY}" \ - UV_PUBLISH_URL="${NEMO_FLOW_CI_ARTIFACTORY_PYPI_URL}" \ + UV_PUBLISH_USERNAME="${NEMO_RELAY_CI_ARTIFACTORY_USER}" \ + UV_PUBLISH_PASSWORD="${NEMO_RELAY_CI_ARTIFACTORY_KEY}" \ + UV_PUBLISH_URL="${NEMO_RELAY_CI_ARTIFACTORY_PYPI_URL}" \ uv publish --no-progress collected/wheels/*.whl publish:artifactory:cargo: stage: publish image: - name: rust:${NEMO_FLOW_CI_RUST_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION} + name: rust:${NEMO_RELAY_CI_RUST_VERSION}-${NEMO_RELAY_CI_DEBIAN_VERSION} pull_policy: if-not-present rules: - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG @@ -215,11 +215,11 @@ publish:artifactory:cargo: artifacts: true before_script: - apt-get update -qq && apt-get install -y --no-install-recommends ca-certificates curl git nodejs && rm -rf /var/lib/apt/lists/* - - cargo install just --version "${NEMO_FLOW_CI_JUST_VERSION}" --locked + - cargo install just --version "${NEMO_RELAY_CI_JUST_VERSION}" --locked - curl -LsSf https://astral.sh/uv/install.sh -o /tmp/install-uv.sh - - UV_VERSION="${NEMO_FLOW_CI_UV_VERSION}" sh /tmp/install-uv.sh + - UV_VERSION="${NEMO_RELAY_CI_UV_VERSION}" sh /tmp/install-uv.sh - export PATH="${HOME}/.cargo/bin:${HOME}/.local/bin:${PATH}" - - uv python install "${NEMO_FLOW_CI_PYTHON_VERSION}" + - uv python install "${NEMO_RELAY_CI_PYTHON_VERSION}" - rustc --version - just --version - uv --version @@ -227,8 +227,8 @@ publish:artifactory:cargo: - | set -eu - if [ -z "${NEMO_FLOW_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_FLOW_CI_ARTIFACTORY_CARGO_URL:-}" ]; then - echo "Error: uploading Cargo crates to Artifactory requires NEMO_FLOW_CI_ARTIFACTORY_KEY and NEMO_FLOW_CI_ARTIFACTORY_CARGO_URL." >&2 + if [ -z "${NEMO_RELAY_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_RELAY_CI_ARTIFACTORY_CARGO_URL:-}" ]; then + echo "Error: uploading Cargo crates to Artifactory requires NEMO_RELAY_CI_ARTIFACTORY_KEY and NEMO_RELAY_CI_ARTIFACTORY_CARGO_URL." >&2 exit 1 fi if [ ! -f collected/github-run.json ]; then @@ -259,10 +259,10 @@ publish:artifactory:cargo: [registry] global-credential-providers = ["cargo:token"] [registries] - artifactory = { index = "sparse+${NEMO_FLOW_CI_ARTIFACTORY_CARGO_URL}" } + artifactory = { index = "sparse+${NEMO_RELAY_CI_ARTIFACTORY_CARGO_URL}" } EOF - export CARGO_REGISTRIES_ARTIFACTORY_TOKEN="Bearer ${NEMO_FLOW_CI_ARTIFACTORY_KEY}" - export NEMO_FLOW_ARTIFACTORY_CRATE_DIRS="core adaptive ffi cli" + export CARGO_REGISTRIES_ARTIFACTORY_TOKEN="Bearer ${NEMO_RELAY_CI_ARTIFACTORY_KEY}" + export NEMO_RELAY_ARTIFACTORY_CRATE_DIRS="core adaptive ffi cli" crates="$( uv run --no-project python - <<'PY' @@ -272,14 +272,14 @@ publish:artifactory:cargo: manifest = Path("Cargo.toml") text = manifest.read_text() - for crate_dir in os.environ["NEMO_FLOW_ARTIFACTORY_CRATE_DIRS"].split(): + for crate_dir in os.environ["NEMO_RELAY_ARTIFACTORY_CRATE_DIRS"].split(): before = f'path = "crates/{crate_dir}"' after = f'{before}, registry = "artifactory"' if after not in text: text = text.replace(before, after) manifest.write_text(text) - for crate_dir in os.environ["NEMO_FLOW_ARTIFACTORY_CRATE_DIRS"].split(): + for crate_dir in os.environ["NEMO_RELAY_ARTIFACTORY_CRATE_DIRS"].split(): crate_manifest = Path("crates") / crate_dir / "Cargo.toml" print(tomllib.loads(crate_manifest.read_text())["package"]["name"]) PY @@ -292,7 +292,7 @@ publish:artifactory:cargo: publish:artifactory:npm: stage: publish image: - name: node:${NEMO_FLOW_CI_NODE_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION} + name: node:${NEMO_RELAY_CI_NODE_VERSION}-${NEMO_RELAY_CI_DEBIAN_VERSION} pull_policy: if-not-present rules: - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG @@ -306,8 +306,8 @@ publish:artifactory:npm: - | set -eu - if [ -z "${NEMO_FLOW_CI_ARTIFACTORY_USER:-}" ] || [ -z "${NEMO_FLOW_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_FLOW_CI_ARTIFACTORY_NPM_URL:-}" ]; then - echo "Error: uploading npm packages to Artifactory requires NEMO_FLOW_CI_ARTIFACTORY_USER, NEMO_FLOW_CI_ARTIFACTORY_KEY, and NEMO_FLOW_CI_ARTIFACTORY_NPM_URL." >&2 + if [ -z "${NEMO_RELAY_CI_ARTIFACTORY_USER:-}" ] || [ -z "${NEMO_RELAY_CI_ARTIFACTORY_KEY:-}" ] || [ -z "${NEMO_RELAY_CI_ARTIFACTORY_NPM_URL:-}" ]; then + echo "Error: uploading npm packages to Artifactory requires NEMO_RELAY_CI_ARTIFACTORY_USER, NEMO_RELAY_CI_ARTIFACTORY_KEY, and NEMO_RELAY_CI_ARTIFACTORY_NPM_URL." >&2 exit 1 fi if [ ! -f collected/node/consolidated.zip ]; then @@ -326,9 +326,9 @@ publish:artifactory:npm: exit 1 fi - registry_url="${NEMO_FLOW_CI_ARTIFACTORY_NPM_URL%/}/" + registry_url="${NEMO_RELAY_CI_ARTIFACTORY_NPM_URL%/}/" registry_key="${registry_url#https:}" - npm_auth="$(printf '%s:%s' "${NEMO_FLOW_CI_ARTIFACTORY_USER}" "${NEMO_FLOW_CI_ARTIFACTORY_KEY}" | base64 | tr -d '\n')" + npm_auth="$(printf '%s:%s' "${NEMO_RELAY_CI_ARTIFACTORY_USER}" "${NEMO_RELAY_CI_ARTIFACTORY_KEY}" | base64 | tr -d '\n')" npm config set registry "$registry_url" npm config set "${registry_key}:_auth" "$npm_auth" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5d33d551d..06af80c4c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: entry: python3 scripts/lint/check_copyright.py language: system files: '\.(rs|go|py|pyi|toml|yaml|yml|md|mjs|js|ts|h|sh)$|\.gitignore$' - exclude: '(/SKILL\.md|index\.js|index\.d\.ts|nemo_flow\.h|node_modules/|target/|\.venv/|pkg/|^\.github/pull_request_template\.md)$' + exclude: '(/SKILL\.md|index\.js|index\.d\.ts|nemo_relay\.h|node_modules/|target/|\.venv/|pkg/|^\.github/pull_request_template\.md)$' # General file hygiene - repo: https://github.com/pre-commit/pre-commit-hooks @@ -67,7 +67,11 @@ repos: - --no-progress - --include-fragments - --exclude - - '^https://www\.npmjs\.com/package/nemo-flow-(node|wasm)$' + - '^https://www\.npmjs\.com/package/nemo-relay-(node|wasm)$' + - --exclude + - '^https://github\.com/NVIDIA/NeMo-Relay(?:/.*)?$' + - --exclude + - '^https://nvidia\.github\.io/NeMo-Relay(?:/.*)?$' - README.md - CONTRIBUTING.md - docs/**/*.md @@ -103,9 +107,9 @@ repos: hooks: - id: ffi-header-sync name: ffi header sync - entry: cargo check -p nemo-flow-ffi + entry: cargo check -p nemo-relay-ffi language: system - files: '^crates/ffi/(Cargo\.toml|cbindgen\.toml|nemo_flow\.h|src/.*\.rs)$' + files: '^crates/ffi/(Cargo\.toml|cbindgen\.toml|nemo_relay\.h|src/.*\.rs)$' pass_filenames: false - id: cargo-fmt @@ -168,7 +172,7 @@ repos: - id: go-vet name: go vet - entry: bash -c 'cd go/nemo_flow && go vet ./...' + entry: bash -c 'cd go/nemo_relay && go vet ./...' language: system types: [go] pass_filenames: false diff --git a/AGENTS.md b/AGENTS.md index 94fe15838..e67dc8ab5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ This file provides guidance to agents, including Claude Code and OpenAI Codex, w ## Project Overview -NeMo Flow is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first. +NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first. The shared runtime model is: @@ -26,22 +26,22 @@ integration patches, and agent-facing skills. ```text crates/ - core/ # Rust core runtime crate, published as nemo-flow + core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ - nemo_flow/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers + nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ - nemo_flow/ # Experimental Go CGo binding and tests + nemo_relay/ # Experimental Go CGo binding and tests docs/ # Sphinx documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # Pinned upstream checkouts for sample integration patches -patches/ # NeMo Flow patch sets applied to third_party checkouts -skills/ # Published Codex/agent skills for NeMo Flow usage patterns +patches/ # NeMo Relay patch sets applied to third_party checkouts +skills/ # Published Codex/agent skills for NeMo Relay usage patterns ``` ## Prerequisites @@ -136,11 +136,11 @@ just clean Focused fallback commands are acceptable for narrow loops: ```bash -cargo test -p nemo-flow -- +cargo test -p nemo-relay -- uv run pytest python/tests/test_scope.py uv run pytest -k "test_name" cd crates/node && node --test --test-name-pattern="pattern" tests/*.mjs -cd go/nemo_flow && go test -v -run TestFoo ./... +cd go/nemo_relay && go test -v -run TestFoo ./... wasm-pack test --node crates/wasm ``` @@ -167,7 +167,7 @@ repository. - Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0. - `SKILL.md` files are skill entrypoints and do not need SPDX headers, but they must always start with YAML frontmatter containing at least `name` and `description`. -- Follow binding naming conventions: Rust and Python `snake_case`, C FFI exports prefixed `nemo_flow_`, Go `PascalCase` for public APIs, Node.js `camelCase`. +- Follow binding naming conventions: Rust and Python `snake_case`, C FFI exports prefixed `nemo_relay_`, Go `PascalCase` for public APIs, Node.js `camelCase`. - Preserve the shared runtime model across bindings. Do not add behavior to one primary binding without considering Rust, Python, and Node.js parity. - Prefer documented public APIs and stable wrapper commands. Do not rely on internal helpers in examples or user-facing docs. - Keep primary documentation focused on Rust, Python, and Node.js. Treat Go, WebAssembly, and raw FFI as experimental and source-first unless binding-support guidance changes. @@ -197,15 +197,15 @@ These notes summarize how each language binding relates to the Rust runtime sour truth. - Rust is the source of truth for runtime behavior. Binding APIs should mirror the Rust semantics unless a language-specific wrapper intentionally improves ergonomics. -- Python wrapper modules live under `python/nemo_flow/`; the native extension is built from `crates/python` with `maturin`. -- Node.js public entry points include the main runtime package plus `nemo-flow-node/typed`, `nemo-flow-node/plugin`, and `nemo-flow-node/adaptive`. +- Python wrapper modules live under `python/nemo_relay/`; the native extension is built from `crates/python` with `maturin`. +- Node.js public entry points include the main runtime package plus `nemo-relay-node/typed`, `nemo-relay-node/plugin`, and `nemo-relay-node/adaptive`. - Go uses the C FFI and requires the FFI library build before tests; `just test-go` handles the library path setup. - WebAssembly includes Rust wasm-bindgen tests plus JS wrapper/package tests; `just test-wasm` runs both paths. ## Third-Party Integrations And Patches ### Patch-based Integrations -Sample integrations are maintained as patch sets, not as primary package source. The pinned upstream checkouts are listed in `third_party/sources.lock`, local checkouts live under `third_party/`, and NeMo Flow patches live under `patches/`. +Sample integrations are maintained as patch sets, not as primary package source. The pinned upstream checkouts are listed in `third_party/sources.lock`, local checkouts live under `third_party/`, and NeMo Relay patches live under `patches/`. Current integration patch sets include: @@ -228,10 +228,10 @@ Use the stable root-level wrappers: `apply-patches.sh` expects clean third-party checkouts. After editing an integration checkout, run `./scripts/generate-patches.sh` to regenerate patch files and verify they apply to a clean detached checkout. ### Public API-based Integrations -Some integrations can be implemented using public APIs without patching. Currently the Python based integrations are located under `python/nemo_flow/integrations/` with their own README files and test suites. +Some integrations can be implemented using public APIs without patching. Currently the Python based integrations are located under `python/nemo_relay/integrations/` with their own README files and test suites. Current public API-based integrations include: -- LangChain: `python/nemo_flow/integrations/langchain` +- LangChain: `python/nemo_relay/integrations/langchain` ## Documentation And Contribution Workflow diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19924a6a9..ae426c158 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,9 +3,9 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# Contributing to NeMo Flow +# Contributing to NeMo Relay -Thank you for your interest in contributing to NeMo Flow. This guide covers the development workflow, coding standards, and pull request process. +Thank you for your interest in contributing to NeMo Relay. This guide covers the development workflow, coding standards, and pull request process. ## Development Setup @@ -14,12 +14,12 @@ changes. ### Package Installation -If you are consuming NeMo Flow rather than developing this repository, install +If you are consuming NeMo Relay rather than developing this repository, install the published package for your language: -- **Rust crate** -- `cargo add nemo-flow` -- **Python package** -- `uv add nemo-flow` or `pip install nemo-flow` -- **Node.js package** -- `npm install nemo-flow-node` +- **Rust crate** -- `cargo add nemo-relay` +- **Python package** -- `uv add nemo-relay` or `pip install nemo-relay` +- **Node.js package** -- `npm install nemo-relay-node` Go, WebAssembly, and the raw FFI surface are currently experimental and remain source-first. @@ -42,7 +42,7 @@ bindings from source in the same branch. Clone the repository and build the workspace: ```bash -git clone && cd NeMo-Flow +git clone && cd NeMo-Relay uv sync cargo install just --locked @@ -56,7 +56,7 @@ Validate the source builds for the experimental bindings when you touch them: ```bash # Go binding (requires the release FFI library) -cd go/nemo_flow +cd go/nemo_relay CGO_LDFLAGS="-L../../target/release" LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}../../target/release" go test -v ./... cd ../.. @@ -130,7 +130,7 @@ Use these Go commands and conventions when changing the experimental Go binding. These general conventions apply across files and language surfaces. -- Use the naming conventions appropriate to each language: Rust `snake_case`, C FFI exports prefixed `nemo_flow_`, Go `PascalCase`, Node.js `camelCase`, Python `snake_case`. +- Use the naming conventions appropriate to each language: Rust `snake_case`, C FFI exports prefixed `nemo_relay_`, Go `PascalCase`, Node.js `camelCase`, Python `snake_case`. ## Pre-commit Hooks @@ -145,7 +145,7 @@ The hooks enforce: - **General**: trailing whitespace removal, end-of-file fixup, YAML/TOML/JSON validity, merge conflict marker detection, large file check (500 KB max) - **Docs**: Markdown link checking for `README.md`, `CONTRIBUTING.md`, and `docs/` via `lychee` - **Python**: Ruff linting and formatting, ty type checking -- **Rust**: FFI header sync for `crates/ffi/nemo_flow.h` through Cargo/build.rs, `cargo fmt` formatting check, `cargo clippy` lints, `cargo deny` auditing +- **Rust**: FFI header sync for `crates/ffi/nemo_relay.h` through Cargo/build.rs, `cargo fmt` formatting check, `cargo clippy` lints, `cargo deny` auditing - **Go**: `gofmt` formatting, `go vet` static analysis To run all hooks manually against the entire codebase: diff --git a/Cargo.lock b/Cargo.lock index 5b8ef7b9d..d80171546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1189,7 +1189,7 @@ dependencies = [ ] [[package]] -name = "nemo-flow" +name = "nemo-relay" version = "0.3.0" dependencies = [ "async-trait", @@ -1220,11 +1220,11 @@ dependencies = [ ] [[package]] -name = "nemo-flow-adaptive" +name = "nemo-relay-adaptive" version = "0.3.0" dependencies = [ "chrono", - "nemo-flow", + "nemo-relay", "redis", "regex", "serde", @@ -1239,7 +1239,7 @@ dependencies = [ ] [[package]] -name = "nemo-flow-cli" +name = "nemo-relay-cli" version = "0.3.0" dependencies = [ "async-stream", @@ -1252,8 +1252,8 @@ dependencies = [ "futures-util", "http", "http-body-util", - "nemo-flow", - "nemo-flow-adaptive", + "nemo-relay", + "nemo-relay-adaptive", "reqwest", "rustls", "serde", @@ -1269,14 +1269,14 @@ dependencies = [ ] [[package]] -name = "nemo-flow-ffi" +name = "nemo-relay-ffi" version = "0.3.0" dependencies = [ "cbindgen", "chrono", "libc", - "nemo-flow", - "nemo-flow-adaptive", + "nemo-relay", + "nemo-relay-adaptive", "serde_json", "tokio", "tokio-stream", @@ -1284,15 +1284,15 @@ dependencies = [ ] [[package]] -name = "nemo-flow-node" +name = "nemo-relay-node" version = "0.3.0" dependencies = [ "chrono", "napi", "napi-build", "napi-derive", - "nemo-flow", - "nemo-flow-adaptive", + "nemo-relay", + "nemo-relay-adaptive", "serde", "serde_json", "tokio", @@ -1301,12 +1301,12 @@ dependencies = [ ] [[package]] -name = "nemo-flow-python" +name = "nemo-relay-python" version = "0.3.0" dependencies = [ "chrono", - "nemo-flow", - "nemo-flow-adaptive", + "nemo-relay", + "nemo-relay-adaptive", "pyo3", "pyo3-async-runtimes", "pythonize", @@ -1318,13 +1318,13 @@ dependencies = [ ] [[package]] -name = "nemo-flow-wasm" +name = "nemo-relay-wasm" version = "0.3.0" dependencies = [ "chrono", "js-sys", - "nemo-flow", - "nemo-flow-adaptive", + "nemo-relay", + "nemo-relay-adaptive", "send_wrapper", "serde", "serde-wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 942e3d0ac..bc57452fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,13 @@ resolver = "2" version = "0.3.0" edition = "2024" license = "Apache-2.0" -repository = "https://github.com/NVIDIA/NeMo-Flow" +repository = "https://github.com/NVIDIA/NeMo-Relay" [workspace.dependencies] -nemo-flow = { version = "0.3.0", path = "crates/core", default-features = false } -nemo-flow-adaptive = { version = "0.3.0", path = "crates/adaptive" } -nemo-flow-ffi = { version = "0.3.0", path = "crates/ffi" } -nemo-flow-cli = { version = "0.3.0", path = "crates/cli" } +nemo-relay = { version = "0.3.0", path = "crates/core", default-features = false } +nemo-relay-adaptive = { version = "0.3.0", path = "crates/adaptive" } +nemo-relay-ffi = { version = "0.3.0", path = "crates/ffi" } +nemo-relay-cli = { version = "0.3.0", path = "crates/cli" } uuid = "=1.18.1" [workspace.lints.rust] diff --git a/README.md b/README.md index 35bfcc4ab..a946f9916 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,23 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -## What Is NeMo Flow? - -NeMo Flow is a portable execution runtime for agent systems that already have a +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NVIDIA NeMo Relay + +## What Is NeMo Relay? + +NeMo Relay is a portable execution runtime for agent systems that already have a framework, model provider, policy layer, or observability backend. It gives those systems one consistent way to describe, control, and observe what happens when an agent crosses a request, tool, or LLM boundary. @@ -30,7 +30,7 @@ harness code, NeMo Guardrails, tracing systems, and evaluation pipelines. NeMo Flow sits underneath those choices as the shared runtime contract for scopes, middleware, plugins, lifecycle events, adaptive behavior, and observability. -Built as a Rust core with primary Rust, Python, and Node.js bindings, NeMo Flow +Built as a Rust core with primary Rust, Python, and Node.js bindings, NeMo Relay lets applications keep their orchestration model while runtime behavior stays consistent across frameworks and languages. @@ -45,7 +45,7 @@ consistent across frameworks and languages. - 📡 **Emit one lifecycle stream**: Subscribers consume canonical runtime events in-process or export them as [ATIF v1.6](https://github.com/harbor-framework/harbor/blob/main/rfcs/0001-trajectory-format.md) trajectories, OpenTelemetry traces, or OpenInference-compatible traces. -- 🧩 **Integrate without a framework migration**: NeMo Flow can sit below NeMo +- 🧩 **Integrate without a framework migration**: NeMo Relay can sit below NeMo ecosystem components, third-party agent frameworks, provider adapters, or direct application code. - ⚙️ **Install reusable runtime behavior**: Plugins configure middleware, @@ -75,7 +75,7 @@ consistent across frameworks and languages. flowchart LR App[Application or Framework] - subgraph Runtime[NeMo Flow Runtime] + subgraph Runtime[NeMo Relay Runtime] direction TB Scopes[Scopes] Middleware[Middleware] @@ -99,31 +99,31 @@ Install the published package for your language: ```bash # Rust -cargo add nemo-flow +cargo add nemo-relay # Python -uv add nemo-flow +uv add nemo-relay # Node.js -npm install nemo-flow-node +npm install nemo-relay-node ``` -The NeMo Flow CLI is offered as a separate crate: +The NeMo Relay CLI is offered as a separate crate: ```bash -cargo install nemo-flow-cli +cargo install nemo-relay-cli ``` For source builds, testing, and contribution workflow, see [CONTRIBUTING.md](CONTRIBUTING.md). ## Documentation -End-user documentation lives at [nvidia.github.io/NeMo-Flow](https://nvidia.github.io/NeMo-Flow/). +End-user documentation lives at [nvidia.github.io/NeMo-Relay](https://nvidia.github.io/NeMo-Relay/). The primary documentation track covers Rust, Python, and Node.js. The Go, WebAssembly, and raw FFI surfaces are currently experimental and remain source-first under -`go/nemo_flow`, `crates/wasm`, and `crates/ffi`. +`go/nemo_relay`, `crates/wasm`, and `crates/ffi`. ## Binding Status @@ -134,15 +134,15 @@ The table below summarizes the support level for each binding surface. | Python | ✅ Fully Supported | Fully documented with Quick Start and Guides | | Node.js | ✅ Fully Supported | Fully documented with Quick Start and Guides | | Rust | ✅ Fully Supported | Fully documented with Quick Start and Guides | -| NeMo Flow CLI | 🚧 Experimental | Install with `cargo install nemo-flow-cli`. | -| Go | 🚧 Experimental | Source-first under `go/nemo_flow`. | +| NeMo Relay CLI | 🚧 Experimental | Install with `cargo install nemo-relay-cli`. | +| Go | 🚧 Experimental | Source-first under `go/nemo_relay`. | | WebAssembly | 🚧 Experimental | Source-first under `crates/wasm`. | | FFI | 🚧 Experimental | Source-first under `crates/ffi`. | ## Agent Harness Support -NeMo Flow CLI offers experimental support for several agent harnesses. -Refer to the NeMo Flow CLI documentation for additional information. +NeMo Relay CLI offers experimental support for several agent harnesses. +Refer to the NeMo Relay CLI documentation for additional information. Below is our support matrix for agent harnesses. @@ -162,7 +162,7 @@ sample integrations are maintained as patch sets against upstream projects. Some integrations can be implemented using public APIs without patching. Public API-based integrations live under language-specific integration packages such as -`python/nemo_flow/integrations/` and `integrations/`. +`python/nemo_relay/integrations/` and `integrations/`. Below is the support matrix for our public API integrations. @@ -175,19 +175,19 @@ Below is the support matrix for our public API integrations. #### LangChain -The Python `nemo-flow` package ships several extras that offer comprehensive +The Python `nemo-relay` package ships several extras that offer comprehensive middleware support for the following packages: - LangChain - LangGraph - Deep Agents -See the [Python package README](python/nemo_flow/README.md) for more information. +See the [Python package README](python/nemo_relay/README.md) for more information. #### OpenClaw -An OpenClaw plugin is available as a Node package `nemo-flow-openclaw`. -It relies on OpenClaw public plugin hooks plus the generic NeMo Flow plugin +An OpenClaw plugin is available as a Node package `nemo-relay-openclaw`. +It relies on OpenClaw public plugin hooks plus the generic NeMo Relay plugin configuration shape to export telemetry. See the [OpenClaw package README](integrations/openclaw/README.md) for more information. @@ -218,4 +218,4 @@ The following roadmap outlines planned features and integrations for upcoming re ## License -NeMo Flow is licensed under the [Apache License 2.0](LICENSE). +NeMo Relay is licensed under the [Apache License 2.0](LICENSE). diff --git a/RELEASING.md b/RELEASING.md index 69766002c..ff25914b5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,9 +3,9 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# Releasing NeMo Flow +# Releasing NeMo Relay -This document is the maintainer playbook for cutting NeMo Flow releases. It +This document is the maintainer playbook for cutting NeMo Relay releases. It describes the release contract, the version files that must be updated, the tag format that CI accepts, the package surfaces that are published, and the checks to run before and after a tag push. @@ -30,9 +30,9 @@ The release pipeline publishes these package surfaces from a tag push: | Ecosystem | Published Surface | |---|---| -| crates.io | `nemo-flow`, `nemo-flow-adaptive`, `nemo-flow-ffi`, `nemo-flow-cli` | -| PyPI | `nemo-flow` | -| npm | `nemo-flow-node`, `nemo-flow-openclaw`, `nemo-flow-wasm` | +| crates.io | `nemo-relay`, `nemo-relay-adaptive`, `nemo-relay-ffi`, `nemo-relay-cli` | +| PyPI | `nemo-relay` | +| npm | `nemo-relay-node`, `nemo-relay-openclaw`, `nemo-relay-wasm` | | GitHub Pages | The documentation site, including the versioned docs build | Go remains source-first. There is no separate Go package-manager publication @@ -44,13 +44,13 @@ pipeline schedule. ## Version Model -NeMo Flow versions are anchored on the workspace SemVer in the repository root +NeMo Relay versions are anchored on the workspace SemVer in the repository root `Cargo.toml`. - The root `Cargo.toml` `workspace.package.version` is the canonical release version for the Rust workspace. - The root `Cargo.toml` `workspace.dependencies` entries for - `nemo-flow`, `nemo-flow-adaptive`, `nemo-flow-ffi`, and `nemo-flow-cli` must + `nemo-relay`, `nemo-relay-adaptive`, `nemo-relay-ffi`, and `nemo-relay-cli` must stay aligned with that same version. - `crates/node/package.json` carries the base npm version for the Node.js package. The repository-root `package-lock.json` carries the npm workspace @@ -92,7 +92,7 @@ latest `main` commit. Name the branch from the target release major and minor version: These examples assume `upstream` is the NVIDIA repository remote -(`NVIDIA/NeMo-Flow`). The `origin` remote is usually a maintainer's personal +(`NVIDIA/NeMo-Relay`). The `origin` remote is usually a maintainer's personal fork. ```bash @@ -131,8 +131,8 @@ Before you create a release tag, confirm the following: 3. The working tree you use for local validation is clean or disposable. 4. Registry credentials and repository settings are in place: - GitHub Actions `id-token: write` access for the top-level crates.io publish job - - crates.io trusted publishers for `nemo-flow`, `nemo-flow-adaptive`, - `nemo-flow-ffi`, and `nemo-flow-cli` are configured for the top-level + - crates.io trusted publishers for `nemo-relay`, `nemo-relay-adaptive`, + `nemo-relay-ffi`, and `nemo-relay-cli` are configured for the top-level [`.github/workflows/ci.yaml`](.github/workflows/ci.yaml) workflow - GitHub Actions `id-token: write` access is available for the top-level npm publish job - GitHub Actions `id-token: write` access for the top-level PyPI publish job @@ -152,7 +152,7 @@ The helper updates: 1. The root [`Cargo.toml`](Cargo.toml) workspace version. 2. The root [`Cargo.toml`](Cargo.toml) `workspace.dependencies` versions for - `nemo-flow`, `nemo-flow-adaptive`, `nemo-flow-ffi`, and `nemo-flow-cli`. + `nemo-relay`, `nemo-relay-adaptive`, `nemo-relay-ffi`, and `nemo-relay-cli`. 3. [`crates/node/package.json`](crates/node/package.json) and the `crates/node` entry in the root [`package-lock.json`](package-lock.json) to the same release version. @@ -240,8 +240,8 @@ The release pipeline then: 5. Publishes packages from the top-level workflow after the reusable packaging jobs complete: - `publish-rust` stamps Cargo workspace versions from the release tag, then - runs `cargo publish --package` for `nemo-flow`, `nemo-flow-adaptive`, - `nemo-flow-ffi`, and `nemo-flow-cli` through trusted publishing from + runs `cargo publish --package` for `nemo-relay`, `nemo-relay-adaptive`, + `nemo-relay-ffi`, and `nemo-relay-cli` through trusted publishing from the top-level workflow - `publish-python` uploads the wheel artifacts to PyPI with trusted publishing from the top-level workflow @@ -278,8 +278,8 @@ NVIDIA Artifactory publication for the same tag: npm trusted publishing has its own registry-side constraints: - Each npm package can only have one trusted publisher configured at a time. -- Because this repository publishes `nemo-flow-node`, `nemo-flow-openclaw`, and - `nemo-flow-wasm`, configure trusted publishers for all three packages before +- Because this repository publishes `nemo-relay-node`, `nemo-relay-openclaw`, and + `nemo-relay-wasm`, configure trusted publishers for all three packages before pushing a release tag. - npm trusted publishing currently supports GitHub-hosted runners, not self-hosted runners. @@ -309,8 +309,8 @@ for that tag. After the release is live, verify: 1. The expected crates are visible on crates.io. -2. The `nemo-flow` wheel is visible on PyPI. -3. The `nemo-flow-node`, `nemo-flow-openclaw`, and `nemo-flow-wasm` packages +2. The `nemo-relay` wheel is visible on PyPI. +3. The `nemo-relay-node`, `nemo-relay-openclaw`, and `nemo-relay-wasm` packages are visible on npm. 4. The GitHub Pages deployment completed successfully. 5. The GitHub Release page is complete and accurate. diff --git a/codecov.yml b/codecov.yml index 601bb8775..851f4f9a3 100644 --- a/codecov.yml +++ b/codecov.yml @@ -67,7 +67,7 @@ component_management: - component_id: go_binding name: Go Binding paths: - - "go/nemo_flow" + - "go/nemo_relay" - "crates/ffi/src" statuses: - type: project @@ -78,7 +78,7 @@ component_management: - component_id: python_binding name: Python Binding paths: - - "python/nemo_flow" + - "python/nemo_relay" - "crates/python/src" statuses: - type: project @@ -135,7 +135,7 @@ ignore: - "target/" - "**/*.d.ts" - "**/*.pyi" - - "python/nemo_flow/lib_native*.dylib.dSYM/**" + - "python/nemo_relay/lib_native*.dylib.dSYM/**" # WebAssembly Rust wrappers are covered through wasm-pack execution and # reported through generated package JavaScript coverage. - "crates/wasm/src/" diff --git a/crates/adaptive/Cargo.toml b/crates/adaptive/Cargo.toml index ee3276c4e..c59bf27e4 100644 --- a/crates/adaptive/Cargo.toml +++ b/crates/adaptive/Cargo.toml @@ -2,19 +2,19 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-adaptive" +name = "nemo-relay-adaptive" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Adaptive runtime primitives and Redis-backed learning components for NeMo Flow." +description = "Adaptive runtime primitives and Redis-backed learning components for NeMo Relay." readme = "README.md" [lints] workspace = true [dependencies] -nemo-flow.workspace = true +nemo-relay.workspace = true uuid = { workspace = true, features = ["v4", "v7", "serde"] } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/crates/adaptive/README.md b/crates/adaptive/README.md index 7410c78bb..14bc33317 100644 --- a/crates/adaptive/README.md +++ b/crates/adaptive/README.md @@ -3,22 +3,22 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow-adaptive` is the Rust companion crate for adaptive NeMo Flow -runtime behavior. Use it with `nemo-flow` when an agent runtime should learn +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay-adaptive` is the Rust companion crate for adaptive NeMo Relay +runtime behavior. Use it with `nemo-relay` when an agent runtime should learn from observed executions, inject runtime hints, or persist adaptive state. Adaptive behavior is installed through the same plugin system used by the core @@ -28,7 +28,7 @@ framework. ## Why Use It? - ⚙️ **Install adaptive behavior through plugins**: Enable adaptive runtime - components through the same configuration path as other NeMo Flow plugins. + components through the same configuration path as other NeMo Relay plugins. - 📈 **Learn from observed executions**: Derive runtime hints from scope, tool, and LLM events without replacing the application framework. - 💾 **Choose local or shared state**: Use in-memory state for local runs or the @@ -45,10 +45,10 @@ framework. adaptive hints, tool parallelism, and the Adaptive Cache Governor. - ✅ **State backends**: In-memory state by default and Redis-backed state behind the `redis-backend` feature. -- ✅ **Learning primitives**: Runtime helpers and learners built on NeMo Flow +- ✅ **Learning primitives**: Runtime helpers and learners built on NeMo Relay events. - ✅ **Adaptive Cache Governor (ACG) module surface**: The canonical - `nemo_flow_adaptive::acg` module for PromptIR, provider plugins, stability + `nemo_relay_adaptive::acg` module for PromptIR, provider plugins, stability analysis, and cache telemetry normalization. ## Installation @@ -56,20 +56,20 @@ framework. Install the published crate alongside the core runtime: ```bash -cargo add nemo-flow nemo-flow-adaptive +cargo add nemo-relay nemo-relay-adaptive ``` Enable Redis-backed state only when the application needs shared persistence: ```bash -cargo add nemo-flow-adaptive --features redis-backend +cargo add nemo-relay-adaptive --features redis-backend ``` For local source development: ```bash -cargo build -p nemo-flow-adaptive -cargo test -p nemo-flow-adaptive +cargo build -p nemo-relay-adaptive +cargo test -p nemo-relay-adaptive ``` ## Getting Started @@ -77,7 +77,7 @@ cargo test -p nemo-flow-adaptive Create a default adaptive config and select the in-memory backend: ```rust -use nemo_flow_adaptive::{AdaptiveConfig, BackendSpec, StateConfig}; +use nemo_relay_adaptive::{AdaptiveConfig, BackendSpec, StateConfig}; let config = AdaptiveConfig { state: Some(StateConfig { @@ -91,7 +91,7 @@ Register the adaptive plugin component before validating or initializing plugin configuration that includes an `adaptive` component: ```rust -nemo_flow_adaptive::plugin_component::register_adaptive_component()?; +nemo_relay_adaptive::plugin_component::register_adaptive_component()?; ``` ## Feature Flags @@ -103,4 +103,4 @@ of the adaptive pipeline. ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/adaptive/src/acg/anthropic_plugin.rs b/crates/adaptive/src/acg/anthropic_plugin.rs index 885a73b1e..fbfc36fe7 100644 --- a/crates/adaptive/src/acg/anthropic_plugin.rs +++ b/crates/adaptive/src/acg/anthropic_plugin.rs @@ -93,10 +93,10 @@ impl ProviderPlugin for AnthropicCachePlugin { impl HintPlanApplier for AnthropicCachePlugin { fn apply_hint_plan( &self, - request: &nemo_flow::api::llm::LlmRequest, + request: &nemo_relay::api::llm::LlmRequest, prompt_ir: &PromptIR, hint_plan: &HintPlan, - ) -> crate::acg::error::Result { + ) -> crate::acg::error::Result { crate::acg::request_surfaces::apply_request_surface( self.plugin_id(), request, diff --git a/crates/adaptive/src/acg/debug.rs b/crates/adaptive/src/acg/debug.rs index 3fcb4fb02..0a6181d65 100644 --- a/crates/adaptive/src/acg/debug.rs +++ b/crates/adaptive/src/acg/debug.rs @@ -7,7 +7,7 @@ use std::sync::OnceLock; use serde_json::{Map, Value}; -const ACG_DEBUG_ENV: &str = "NEMO_FLOW_ACG_DEBUG"; +const ACG_DEBUG_ENV: &str = "NEMO_RELAY_ACG_DEBUG"; fn env_flag_enabled(value: &str) -> bool { !matches!( @@ -40,7 +40,7 @@ pub(crate) fn emit(event: &str, payload: Value) { } } - eprintln!("nemo-flow-adaptive acg-debug {}", Value::Object(body)); + eprintln!("nemo-relay-adaptive acg-debug {}", Value::Object(body)); } #[cfg(test)] diff --git a/crates/adaptive/src/acg/ir_builder.rs b/crates/adaptive/src/acg/ir_builder.rs index 6f8584aaf..a40702d63 100644 --- a/crates/adaptive/src/acg/ir_builder.rs +++ b/crates/adaptive/src/acg/ir_builder.rs @@ -6,7 +6,7 @@ use chrono::Utc; use uuid::Uuid; -use nemo_flow::codec::request::{ +use nemo_relay::codec::request::{ AnnotatedLlmRequest, ContentPart, Message, MessageContent, ToolCall, ToolDefinition, }; diff --git a/crates/adaptive/src/acg/openai_plugin.rs b/crates/adaptive/src/acg/openai_plugin.rs index e54c113ff..ed1eafe9c 100644 --- a/crates/adaptive/src/acg/openai_plugin.rs +++ b/crates/adaptive/src/acg/openai_plugin.rs @@ -87,10 +87,10 @@ impl ProviderPlugin for OpenAICachePlugin { impl HintPlanApplier for OpenAICachePlugin { fn apply_hint_plan( &self, - request: &nemo_flow::api::llm::LlmRequest, + request: &nemo_relay::api::llm::LlmRequest, prompt_ir: &PromptIR, hint_plan: &HintPlan, - ) -> crate::acg::error::Result { + ) -> crate::acg::error::Result { crate::acg::request_surfaces::apply_request_surface( self.plugin_id(), request, diff --git a/crates/adaptive/src/acg/plugin.rs b/crates/adaptive/src/acg/plugin.rs index 63d291574..14f69427d 100644 --- a/crates/adaptive/src/acg/plugin.rs +++ b/crates/adaptive/src/acg/plugin.rs @@ -23,7 +23,7 @@ //! in concurrent contexts. //! - **Object-safe**: The trait is designed to be used as a trait object. -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use crate::acg::capability::BackendCapabilities; use crate::acg::prompt_ir::PromptIR; diff --git a/crates/adaptive/src/acg/request_surfaces/anthropic_messages.rs b/crates/adaptive/src/acg/request_surfaces/anthropic_messages.rs index 927fa8ee5..2017c0001 100644 --- a/crates/adaptive/src/acg/request_surfaces/anthropic_messages.rs +++ b/crates/adaptive/src/acg/request_surfaces/anthropic_messages.rs @@ -3,7 +3,7 @@ //! Anthropic Messages request-surface applier. -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::{Value, json}; use crate::acg::debug as acg_debug; diff --git a/crates/adaptive/src/acg/request_surfaces/mod.rs b/crates/adaptive/src/acg/request_surfaces/mod.rs index ee348cfc8..94f3bc71c 100644 --- a/crates/adaptive/src/acg/request_surfaces/mod.rs +++ b/crates/adaptive/src/acg/request_surfaces/mod.rs @@ -15,7 +15,7 @@ pub(crate) mod openai_responses; use std::collections::HashSet; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::Value; use crate::acg::prompt_ir::PromptIR; diff --git a/crates/adaptive/src/acg/request_surfaces/openai_chat.rs b/crates/adaptive/src/acg/request_surfaces/openai_chat.rs index 07f348818..ee8002e3b 100644 --- a/crates/adaptive/src/acg/request_surfaces/openai_chat.rs +++ b/crates/adaptive/src/acg/request_surfaces/openai_chat.rs @@ -3,7 +3,7 @@ //! OpenAI Chat request-surface applier. -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use crate::acg::prompt_ir::PromptIR; use crate::acg::request_surfaces::RequestSurfaceApplier; diff --git a/crates/adaptive/src/acg/request_surfaces/openai_responses.rs b/crates/adaptive/src/acg/request_surfaces/openai_responses.rs index a48833916..dd319111d 100644 --- a/crates/adaptive/src/acg/request_surfaces/openai_responses.rs +++ b/crates/adaptive/src/acg/request_surfaces/openai_responses.rs @@ -3,7 +3,7 @@ //! OpenAI Responses request-surface applier. -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::Value; use crate::acg::prompt_ir::PromptIR; diff --git a/crates/adaptive/src/acg/telemetry.rs b/crates/adaptive/src/acg/telemetry.rs index 6d3ae4a2d..421cd5e69 100644 --- a/crates/adaptive/src/acg/telemetry.rs +++ b/crates/adaptive/src/acg/telemetry.rs @@ -10,7 +10,7 @@ //! Populated by provider-specific normalization logic in Phase 9. use chrono::{DateTime, Utc}; -use nemo_flow::codec::response::Usage; +use nemo_relay::codec::response::Usage; use serde::{Deserialize, Serialize}; use uuid::Uuid; diff --git a/crates/adaptive/src/acg/types.rs b/crates/adaptive/src/acg/types.rs index b13b0f5b1..1f9206092 100644 --- a/crates/adaptive/src/acg/types.rs +++ b/crates/adaptive/src/acg/types.rs @@ -358,7 +358,7 @@ pub struct OptimizationIntentBundle { /// # Examples /// /// ``` -/// use nemo_flow_adaptive::acg::AgentIdentity; +/// use nemo_relay_adaptive::acg::AgentIdentity; /// use std::collections::HashMap; /// /// let id = AgentIdentity { diff --git a/crates/adaptive/src/acg_component.rs b/crates/adaptive/src/acg_component.rs index 40183779f..7d5ccaddc 100644 --- a/crates/adaptive/src/acg_component.rs +++ b/crates/adaptive/src/acg_component.rs @@ -23,17 +23,17 @@ use crate::acg::{ PassthroughPlugin, SharingScope, StabilityAnalysisResult, debug as acg_debug, }; use chrono::Utc; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::runtime::{ +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::runtime::{ LlmExecutionFn, LlmExecutionNextFn, LlmRequestInterceptFn, LlmStreamExecutionFn, LlmStreamExecutionNextFn, }; -use nemo_flow::codec::anthropic::AnthropicMessagesCodec; -use nemo_flow::codec::openai_chat::OpenAIChatCodec; -use nemo_flow::codec::openai_responses::OpenAIResponsesCodec; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::traits::LlmCodec; -use nemo_flow::json::Json; +use nemo_relay::codec::anthropic::AnthropicMessagesCodec; +use nemo_relay::codec::openai_chat::OpenAIChatCodec; +use nemo_relay::codec::openai_responses::OpenAIResponsesCodec; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::traits::LlmCodec; +use nemo_relay::json::Json; use uuid::Uuid; use crate::acg_profile::{derive_acg_learning_key, derive_acg_profile_key}; @@ -620,7 +620,7 @@ pub(crate) fn create_acg_llm_execution_intercept( translate_request(&request, &agent_id, &provider, plugin.as_ref(), &cache) .unwrap_or(request); next(translated).await - }) as Pin> + Send>> + }) as Pin> + Send>> }, ) } diff --git a/crates/adaptive/src/acg_profile.rs b/crates/adaptive/src/acg_profile.rs index 6551712b9..01e5c3b29 100644 --- a/crates/adaptive/src/acg_profile.rs +++ b/crates/adaptive/src/acg_profile.rs @@ -5,7 +5,7 @@ //! LLM requests. use crate::acg::canonicalize::{canonicalize_value, sha256_hex}; -use nemo_flow::codec::request::{ +use nemo_relay::codec::request::{ AnnotatedLlmRequest, ContentPart, Message, MessageContent, ToolDefinition, }; diff --git a/crates/adaptive/src/adaptive_hints_intercept.rs b/crates/adaptive/src/adaptive_hints_intercept.rs index 33875f4fb..05613aadb 100644 --- a/crates/adaptive/src/adaptive_hints_intercept.rs +++ b/crates/adaptive/src/adaptive_hints_intercept.rs @@ -12,9 +12,9 @@ use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Arc, RwLock}; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::runtime::LlmRequestInterceptFn; -use nemo_flow::codec::request::AnnotatedLlmRequest; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::runtime::LlmRequestInterceptFn; +use nemo_relay::codec::request::AnnotatedLlmRequest; use crate::context_helpers::{ extract_scope_path, read_manual_latency_sensitivity, resolve_agent_id, @@ -116,7 +116,7 @@ fn inject_agent_hints(request: &mut LlmRequest, hints: &AgentHints) { /// /// Constructed via [`AdaptiveHintsIntercept::new`] and converted to an /// [`LlmRequestInterceptFn`] via [`AdaptiveHintsIntercept::into_request_fn`] for -/// registration with the NeMo Flow runtime. +/// registration with the NeMo Relay runtime. pub struct AdaptiveHintsIntercept { hot_cache: Arc>, agent_id: String, diff --git a/crates/adaptive/src/cache_diagnostics.rs b/crates/adaptive/src/cache_diagnostics.rs index 554aade67..df892ecf8 100644 --- a/crates/adaptive/src/cache_diagnostics.rs +++ b/crates/adaptive/src/cache_diagnostics.rs @@ -11,7 +11,7 @@ use crate::acg::ir_builder::build_prompt_ir; use crate::acg::prompt_ir::PromptIR; use crate::acg::{CacheRequestFacts, CapabilityRegistry}; use chrono::{DateTime, Utc}; -use nemo_flow::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest; use crate::acg_profile::derive_acg_learning_key; use crate::types::cache::HotCache; diff --git a/crates/adaptive/src/config.rs b/crates/adaptive/src/config.rs index db2e9cdd1..c24bc4e50 100644 --- a/crates/adaptive/src/config.rs +++ b/crates/adaptive/src/config.rs @@ -3,7 +3,7 @@ //! Canonical adaptive config and diagnostics types. -use nemo_flow::plugin::ConfigPolicy; +use nemo_relay::plugin::ConfigPolicy; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value as Json}; @@ -216,7 +216,7 @@ fn default_acg_priority() -> i32 { 50 } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl AdaptiveConfig { agent_id => { label: "fallback_agent_id", kind: String, optional: true }, state => { @@ -263,7 +263,7 @@ nemo_flow::editor_config! { } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl StateConfig { backend => { label: "backend", @@ -274,21 +274,21 @@ nemo_flow::editor_config! { } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl BackendSpec { kind => { label: "kind", kind: Enum, values: ["in_memory", "redis"] }, config => { label: "config", kind: Json }, } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl TelemetryComponentConfig { subscriber_name => { label: "subscriber_name", kind: String, optional: true }, learners => { label: "learners", kind: Json }, } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl AdaptiveHintsComponentConfig { priority => { label: "priority", kind: Integer }, break_chain => { label: "break_chain", kind: Boolean }, @@ -297,7 +297,7 @@ nemo_flow::editor_config! { } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl ToolParallelismComponentConfig { priority => { label: "priority", kind: Integer }, mode => { @@ -308,7 +308,7 @@ nemo_flow::editor_config! { } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl AcgComponentConfig { provider => { label: "provider", @@ -326,7 +326,7 @@ nemo_flow::editor_config! { } } -nemo_flow::editor_config! { +nemo_relay::editor_config! { impl crate::acg::stability::StabilityThresholds { stable_threshold => { label: "stable_threshold", kind: Float }, semi_stable_threshold => { label: "semi_stable_threshold", kind: Float }, diff --git a/crates/adaptive/src/context_helpers.rs b/crates/adaptive/src/context_helpers.rs index 16e84023b..95367c67d 100644 --- a/crates/adaptive/src/context_helpers.rs +++ b/crates/adaptive/src/context_helpers.rs @@ -3,7 +3,7 @@ //! Context helpers for reading scope metadata on the intercept hot path. //! -//! These functions read from the NeMo Flow scope stack (via [`current_scope_stack`]) +//! These functions read from the NeMo Relay scope stack (via [`current_scope_stack`]) //! to extract information needed by the LLM request intercept: //! //! - [`extract_scope_path`]: collects function names from the scope stack for trie lookup @@ -16,14 +16,14 @@ //! # Metadata Convention //! //! Manual latency sensitivity is stored in scope metadata under the JSON path -//! `/nemo_flow_adaptive/latency_sensitivity` as a positive integer. +//! `/nemo_relay_adaptive/latency_sensitivity` as a positive integer. -use nemo_flow::api::runtime::current_scope_stack; -use nemo_flow::api::scope::ScopeType; +use nemo_relay::api::runtime::current_scope_stack; +use nemo_relay::api::scope::ScopeType; use uuid::Uuid; /// Metadata key path for manual latency sensitivity annotation. -pub const LATENCY_SENSITIVITY_POINTER: &str = "/nemo_flow_adaptive/latency_sensitivity"; +pub const LATENCY_SENSITIVITY_POINTER: &str = "/nemo_relay_adaptive/latency_sensitivity"; /// Session-local scope identity used to coordinate warm-first cohorts. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -34,7 +34,7 @@ pub struct SharedParentScopeIdentity { pub shared_parent_uuid: Uuid, } -/// Extracts the current function call path from the NeMo Flow scope stack. +/// Extracts the current function call path from the NeMo Relay scope stack. /// /// Walks all scopes from root to top, skipping the root scope (index 0), /// and collects names of Agent and Function scopes. This path is used @@ -63,7 +63,7 @@ pub fn extract_scope_path() -> Vec { /// Reads the maximum manual latency sensitivity from all scopes in the current scope stack. /// -/// Walks all scopes and checks metadata for `/nemo_flow_adaptive/latency_sensitivity`. +/// Walks all scopes and checks metadata for `/nemo_relay_adaptive/latency_sensitivity`. /// Uses max-merge semantics: if multiple scopes have annotations, the highest wins. /// /// # Returns @@ -131,10 +131,10 @@ pub fn set_latency_sensitivity(value: u32) -> std::result::Result<(), String> { let meta = scope.metadata.get_or_insert_with(|| serde_json::json!({})); if let Some(obj) = meta.as_object_mut() { - let nemo_flow_adaptive = obj - .entry("nemo_flow_adaptive") + let nemo_relay_adaptive = obj + .entry("nemo_relay_adaptive") .or_insert_with(|| serde_json::json!({})); - if let Some(np_obj) = nemo_flow_adaptive.as_object_mut() { + if let Some(np_obj) = nemo_relay_adaptive.as_object_mut() { np_obj.insert( "latency_sensitivity".to_string(), serde_json::json!(effective), diff --git a/crates/adaptive/src/drain.rs b/crates/adaptive/src/drain.rs index 91ab7a29c..3ffffb72c 100644 --- a/crates/adaptive/src/drain.rs +++ b/crates/adaptive/src/drain.rs @@ -9,8 +9,8 @@ use std::sync::{ atomic::{AtomicUsize, Ordering}, }; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::scope::ScopeType; +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::scope::ScopeType; use uuid::Uuid; use crate::learner::traits::Learner; @@ -180,7 +180,7 @@ async fn store_run( completed_run: &RunRecord, ) -> bool { if let Err(error) = backend.store_run_dyn(completed_run).await { - eprintln!("nemo-flow-adaptive drain: store_run failed: {error}"); + eprintln!("nemo-relay-adaptive drain: store_run failed: {error}"); return false; } true @@ -197,7 +197,7 @@ async fn run_learners( .process_run(completed_run, backend.as_ref(), hot_cache) .await { - eprintln!("nemo-flow-adaptive drain: learner failed: {error}"); + eprintln!("nemo-relay-adaptive drain: learner failed: {error}"); } } } @@ -213,7 +213,7 @@ async fn refresh_hot_cache_plan( guard.plan = plan; } } - Err(error) => eprintln!("nemo-flow-adaptive drain: load_plan failed: {error}"), + Err(error) => eprintln!("nemo-relay-adaptive drain: load_plan failed: {error}"), } } diff --git a/crates/adaptive/src/error.rs b/crates/adaptive/src/error.rs index 2cdf3f57e..7d7f22879 100644 --- a/crates/adaptive/src/error.rs +++ b/crates/adaptive/src/error.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Error types for the nemo-flow-adaptive crate. +//! Error types for the nemo-relay-adaptive crate. -use nemo_flow::plugin::PluginError; +use nemo_relay::plugin::PluginError; use thiserror::Error; -/// The error type for all nemo-flow-adaptive operations. +/// The error type for all nemo-relay-adaptive operations. #[derive(Debug, Error)] pub enum AdaptiveError { /// Configuration validation failed. @@ -29,7 +29,7 @@ pub enum AdaptiveError { #[error("internal error: {0}")] Internal(String), - /// A registration with the NeMo Flow runtime failed. + /// A registration with the NeMo Relay runtime failed. #[error("registration failed: {0}")] RegistrationFailed(String), @@ -61,7 +61,7 @@ impl From for AdaptiveError { } } -/// A specialized [`Result`](std::result::Result) type for nemo-flow-adaptive operations. +/// A specialized [`Result`](std::result::Result) type for nemo-relay-adaptive operations. pub type Result = std::result::Result; #[cfg(test)] diff --git a/crates/adaptive/src/intercepts.rs b/crates/adaptive/src/intercepts.rs index df4a49d93..6641cd744 100644 --- a/crates/adaptive/src/intercepts.rs +++ b/crates/adaptive/src/intercepts.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Intercept factories for the `nemo-flow-adaptive` crate, including Adaptive +//! Intercept factories for the `nemo-relay-adaptive` crate, including Adaptive //! Cache Governor (ACG) intercepts. use std::collections::HashMap; @@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; use std::time::Duration; -use nemo_flow::api::runtime::{ToolExecutionFn, ToolExecutionNextFn}; -use nemo_flow::error::Result as FlowResult; -use nemo_flow::json::Json; +use nemo_relay::api::runtime::{ToolExecutionFn, ToolExecutionNextFn}; +use nemo_relay::error::Result as FlowResult; +use nemo_relay::json::Json; use tokio::sync::{Mutex, Notify}; use uuid::Uuid; @@ -22,7 +22,7 @@ use crate::context_helpers::resolve_shared_parent_scope_identity; use crate::types::cache::HotCache; /// Header key used to propagate serialized adaptive agent hints. -pub const AGENT_HINTS_HEADER_KEY: &str = "x-nemo-flow-adaptive-agent-hints"; +pub const AGENT_HINTS_HEADER_KEY: &str = "x-nemo-relay-adaptive-agent-hints"; pub(crate) const WARM_FIRST_MAX_WAIT_MS: u64 = 150; #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/adaptive/src/lib.rs b/crates/adaptive/src/lib.rs index 3dd2d7af6..9843a2e56 100644 --- a/crates/adaptive/src/lib.rs +++ b/crates/adaptive/src/lib.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! # NeMo Flow Adaptive +//! # NeMo Relay Adaptive //! -//! Adaptive config helpers and core-plugin integration for NeMo Flow. +//! Adaptive config helpers and core-plugin integration for NeMo Relay. //! Adaptive behavior is enabled through the generic core plugin system. //! //! This crate provides the adaptive runtime, persistence abstractions, learner //! implementations, and Adaptive Cache Governor (ACG) analysis types used to -//! derive and apply runtime hints from observed NeMo Flow executions. +//! derive and apply runtime hints from observed NeMo Relay executions. pub mod acg; pub mod acg_component; pub mod acg_learner; diff --git a/crates/adaptive/src/plugin_component.rs b/crates/adaptive/src/plugin_component.rs index 15cc731dc..62ccfd4b6 100644 --- a/crates/adaptive/src/plugin_component.rs +++ b/crates/adaptive/src/plugin_component.rs @@ -7,7 +7,7 @@ use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex}; -use nemo_flow::plugin::{ +use nemo_relay::plugin::{ ConfigDiagnostic, ConfigPolicy, DiagnosticLevel, Plugin, PluginComponentSpec, PluginError, PluginRegistration, PluginRegistrationContext, Result, UnsupportedBehavior, deregister_plugin, lookup_plugin, register_plugin, diff --git a/crates/adaptive/src/redis.rs b/crates/adaptive/src/redis.rs index 8a3c99d4b..923632d8f 100644 --- a/crates/adaptive/src/redis.rs +++ b/crates/adaptive/src/redis.rs @@ -48,7 +48,7 @@ impl RedisBackend { /// # Arguments /// /// * `url` — Redis connection URL (e.g. `redis://127.0.0.1:6379`). - /// * `key_prefix` — String prepended to every Redis key (e.g. `"nemo_flow:"`). + /// * `key_prefix` — String prepended to every Redis key (e.g. `"nemo_relay:"`). /// /// # Errors /// diff --git a/crates/adaptive/src/runtime/backend.rs b/crates/adaptive/src/runtime/backend.rs index 906f44085..dedc4bcc4 100644 --- a/crates/adaptive/src/runtime/backend.rs +++ b/crates/adaptive/src/runtime/backend.rs @@ -26,7 +26,7 @@ pub async fn build_backend( .config .get("key_prefix") .and_then(|value| value.as_str()) - .unwrap_or("nemo_flow:"); + .unwrap_or("nemo_relay:"); Ok(Arc::new(RedisBackend::new(url, key_prefix).await.map_err( |error| AdaptiveError::Storage(error.to_string()), )?)) diff --git a/crates/adaptive/src/runtime/features.rs b/crates/adaptive/src/runtime/features.rs index 0604c696b..af2553a9e 100644 --- a/crates/adaptive/src/runtime/features.rs +++ b/crates/adaptive/src/runtime/features.rs @@ -12,15 +12,15 @@ use std::sync::{ use std::time::Duration; use crate::acg::CacheRequestFacts; -use nemo_flow::api::event::Event; -use nemo_flow::api::registry::{ +use nemo_relay::api::event::Event; +use nemo_relay::api::registry::{ scope_deregister_llm_request_intercept, scope_register_llm_request_intercept, }; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ EventSubscriberFn, LlmExecutionFn, LlmRequestInterceptFn, LlmStreamExecutionFn, ToolExecutionFn, }; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::plugin::{ +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::plugin::{ ConfigReport, DiagnosticLevel, PluginError, PluginRegistration as ComponentRegistration, PluginRegistrationContext as HostedRegistrationContext, rollback_registrations, }; @@ -49,7 +49,7 @@ use crate::subscriber::create_subscriber_with_counter; use crate::tool_parallelism_learner::ToolParallelismLearner; use crate::types::cache::HotCache; -/// Hosted adaptive runtime that registers NeMo Flow plugin components. +/// Hosted adaptive runtime that registers NeMo Relay plugin components. /// /// This type validates configuration, builds the configured storage backend, /// registers intercepts and subscribers, and maintains the hot cache used by @@ -294,7 +294,7 @@ impl AdaptiveRuntime { /// Bind the runtime's ACG request rewrite to an active scope. /// /// External framework integrations can bind the runtime to a session scope - /// and then invoke ``nemo_flow.llm.request_intercepts(...)`` explicitly at + /// and then invoke ``nemo_relay.llm.request_intercepts(...)`` explicitly at /// the provider boundary. Once any scope is bound, this runtime's hosted /// ACG execution intercept becomes pass-through so external frameworks do /// not double-translate requests. @@ -395,7 +395,7 @@ impl AdaptiveRuntime { && let Err(error) = load_persisted_acg_state(&agent_id, backend.as_ref(), &self.hot_cache).await { - eprintln!("nemo-flow-adaptive: acg hot cache seeding failed: {error}"); + eprintln!("nemo-relay-adaptive: acg hot cache seeding failed: {error}"); } let mut pending = self.pending_features(&agent_id); @@ -431,7 +431,7 @@ impl AdaptiveRuntime { guard.plan = plan; } } - Err(error) => eprintln!("nemo-flow-adaptive: hot cache seeding failed: {error}"), + Err(error) => eprintln!("nemo-relay-adaptive: hot cache seeding failed: {error}"), } } diff --git a/crates/adaptive/src/runtime/validation.rs b/crates/adaptive/src/runtime/validation.rs index e2f28f5a3..8d0393791 100644 --- a/crates/adaptive/src/runtime/validation.rs +++ b/crates/adaptive/src/runtime/validation.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -use nemo_flow::plugin::{ +use nemo_relay::plugin::{ ConfigDiagnostic, ConfigPolicy, ConfigReport, DiagnosticLevel, UnsupportedBehavior, }; diff --git a/crates/adaptive/src/subscriber.rs b/crates/adaptive/src/subscriber.rs index 3094e7742..56dbe94b2 100644 --- a/crates/adaptive/src/subscriber.rs +++ b/crates/adaptive/src/subscriber.rs @@ -8,9 +8,9 @@ use std::sync::{ atomic::{AtomicUsize, Ordering}, }; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::runtime::EventSubscriberFn; -use nemo_flow::api::scope::ScopeType; +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::runtime::EventSubscriberFn; +use nemo_relay::api::scope::ScopeType; use crate::types::records::{CallKind, CallRecord}; diff --git a/crates/adaptive/src/types/records.rs b/crates/adaptive/src/types/records.rs index aae750e69..f80b39741 100644 --- a/crates/adaptive/src/types/records.rs +++ b/crates/adaptive/src/types/records.rs @@ -54,11 +54,11 @@ pub struct CallRecord { /// Annotated request captured for Adaptive Cache Governor (ACG) analysis, /// when available. #[serde(skip_serializing_if = "Option::is_none", default)] - pub annotated_request: Option>, + pub annotated_request: Option>, /// Annotated response captured for Adaptive Cache Governor (ACG) analysis, /// when available. #[serde(skip_serializing_if = "Option::is_none", default)] - pub annotated_response: Option>, + pub annotated_response: Option>, } /// Telemetry record for one observed agent run. diff --git a/crates/adaptive/tests/coverage/error_tests.rs b/crates/adaptive/tests/coverage/error_tests.rs index 3f8f02676..ed8489a19 100644 --- a/crates/adaptive/tests/coverage/error_tests.rs +++ b/crates/adaptive/tests/coverage/error_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for error in the NeMo Flow adaptive crate. +//! Coverage tests for error in the NeMo Relay adaptive crate. use super::*; -use nemo_flow::plugin::PluginError; +use nemo_relay::plugin::PluginError; #[test] fn test_not_found_display() { diff --git a/crates/adaptive/tests/coverage/subscriber_tests.rs b/crates/adaptive/tests/coverage/subscriber_tests.rs index 7928b5e7f..045625686 100644 --- a/crates/adaptive/tests/coverage/subscriber_tests.rs +++ b/crates/adaptive/tests/coverage/subscriber_tests.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for subscriber in the NeMo Flow adaptive crate. +//! Coverage tests for subscriber in the NeMo Relay adaptive crate. use super::*; -use nemo_flow::api::event::{ +use nemo_relay::api::event::{ BaseEvent, CategoryProfile, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, }; -use nemo_flow::api::scope::ScopeType; -use nemo_flow::codec::response::{AnnotatedLlmResponse, FinishReason}; +use nemo_relay::api::scope::ScopeType; +use nemo_relay::codec::response::{AnnotatedLlmResponse, FinishReason}; use std::sync::Arc; #[derive(Clone, Copy)] diff --git a/crates/adaptive/tests/integration/acg_module_surface_tests.rs b/crates/adaptive/tests/integration/acg_module_surface_tests.rs index 87433e79e..16bf0dd94 100644 --- a/crates/adaptive/tests/integration/acg_module_surface_tests.rs +++ b/crates/adaptive/tests/integration/acg_module_surface_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for acg module surface in the NeMo Flow adaptive crate. +//! Integration tests for acg module surface in the NeMo Relay adaptive crate. -use nemo_flow_adaptive::acg::prompt_ir::PromptIR; -use nemo_flow_adaptive::acg::{ +use nemo_relay_adaptive::acg::prompt_ir::PromptIR; +use nemo_relay_adaptive::acg::{ AcgError, AgentIdentity, CacheTelemetryEvent, CapabilityRegistry, sha256_hex, }; use std::sync::Arc; @@ -40,13 +40,13 @@ fn acg_module_surface_shared_utility_symbols_compile_from_canonical_namespace() #[test] fn acg_module_surface_analysis_symbols_compile_from_canonical_namespace() { - use nemo_flow_adaptive::acg::profile::{BlockStabilityScore, StabilityClass}; - use nemo_flow_adaptive::acg::prompt_ir::{ + use nemo_relay_adaptive::acg::profile::{BlockStabilityScore, StabilityClass}; + use nemo_relay_adaptive::acg::prompt_ir::{ BlockContentType, PromptBlock, PromptIR, PromptRole, ProvenanceLabel, SensitivityLabel, SpanId, }; - use nemo_flow_adaptive::acg::retention::RetentionThresholds; - use nemo_flow_adaptive::acg::stability::{StabilityThresholds, analyze_stability}; + use nemo_relay_adaptive::acg::retention::RetentionThresholds; + use nemo_relay_adaptive::acg::stability::{StabilityThresholds, analyze_stability}; let _: Option = None; let thresholds = RetentionThresholds::default(); @@ -77,8 +77,8 @@ fn acg_module_surface_analysis_symbols_compile_from_canonical_namespace() { #[test] fn acg_module_surface_variable_extractor_keeps_regex_detection_behavior() { - use nemo_flow_adaptive::acg::prompt_ir::SpanId; - use nemo_flow_adaptive::acg::variable_extractor::{ + use nemo_relay_adaptive::acg::prompt_ir::SpanId; + use nemo_relay_adaptive::acg::variable_extractor::{ default_variable_patterns, extract_variables, }; @@ -101,10 +101,10 @@ fn acg_module_surface_variable_extractor_keeps_regex_detection_behavior() { #[test] fn acg_module_surface_policy_and_ir_builder_symbols_compile_from_canonical_namespace() { - use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; - use nemo_flow_adaptive::acg::ir_builder::build_prompt_ir; - use nemo_flow_adaptive::acg::policy::{CachePolicy, PolicyEnvelope}; - use nemo_flow_adaptive::acg::{ModelClass, SharingScope}; + use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; + use nemo_relay_adaptive::acg::ir_builder::build_prompt_ir; + use nemo_relay_adaptive::acg::policy::{CachePolicy, PolicyEnvelope}; + use nemo_relay_adaptive::acg::{ModelClass, SharingScope}; let _: Option> = None; @@ -168,11 +168,11 @@ fn acg_module_surface_policy_and_ir_builder_symbols_compile_from_canonical_names #[test] fn acg_module_surface_build_prompt_ir_inserts_tool_schema_before_first_non_system_message() { - use nemo_flow::codec::request::{ + use nemo_relay::codec::request::{ AnnotatedLlmRequest, FunctionDefinition, Message, MessageContent, ToolDefinition, }; - use nemo_flow_adaptive::acg::ir_builder::build_prompt_ir; - use nemo_flow_adaptive::acg::prompt_ir::{BlockContentType, PromptRole}; + use nemo_relay_adaptive::acg::ir_builder::build_prompt_ir; + use nemo_relay_adaptive::acg::prompt_ir::{BlockContentType, PromptRole}; let request = AnnotatedLlmRequest { messages: vec![ @@ -233,12 +233,12 @@ fn acg_module_surface_build_prompt_ir_inserts_tool_schema_before_first_non_syste #[test] fn acg_module_surface_analyze_stability_limits_stable_prefix_when_later_span_is_missing() { - use nemo_flow_adaptive::acg::profile::StabilityClass; - use nemo_flow_adaptive::acg::prompt_ir::{ + use nemo_relay_adaptive::acg::profile::StabilityClass; + use nemo_relay_adaptive::acg::prompt_ir::{ BlockContentType, PromptBlock, PromptIR, PromptRole, ProvenanceLabel, SensitivityLabel, SpanId, }; - use nemo_flow_adaptive::acg::stability::{StabilityThresholds, analyze_stability}; + use nemo_relay_adaptive::acg::stability::{StabilityThresholds, analyze_stability}; let make_block = |span: &str, index: u32, role: PromptRole, content: &str| PromptBlock { span_id: SpanId(span.to_string()), @@ -290,11 +290,11 @@ fn acg_module_surface_analyze_stability_limits_stable_prefix_when_later_span_is_ #[test] fn acg_module_surface_provider_plugin_symbols_compile_from_canonical_namespace() { - use nemo_flow_adaptive::acg::anthropic_plugin::AnthropicCachePlugin; - use nemo_flow_adaptive::acg::openai_plugin::OpenAICachePlugin; - use nemo_flow_adaptive::acg::passthrough::PassthroughPlugin; - use nemo_flow_adaptive::acg::plugin::ProviderPlugin; - use nemo_flow_adaptive::acg::plugin_registry::PluginRegistry; + use nemo_relay_adaptive::acg::anthropic_plugin::AnthropicCachePlugin; + use nemo_relay_adaptive::acg::openai_plugin::OpenAICachePlugin; + use nemo_relay_adaptive::acg::passthrough::PassthroughPlugin; + use nemo_relay_adaptive::acg::plugin::ProviderPlugin; + use nemo_relay_adaptive::acg::plugin_registry::PluginRegistry; let capabilities = CapabilityRegistry::with_defaults(); let anthropic: Arc = Arc::new(AnthropicCachePlugin::new(&capabilities)); diff --git a/crates/adaptive/tests/integration/redis_tests.rs b/crates/adaptive/tests/integration/redis_tests.rs index 94f3c16ff..34dcadb5a 100644 --- a/crates/adaptive/tests/integration/redis_tests.rs +++ b/crates/adaptive/tests/integration/redis_tests.rs @@ -4,31 +4,31 @@ //! Redis integration tests for [`RedisBackend`]. //! //! These tests require a running Redis instance at `redis://127.0.0.1/` -//! and only run when `NEMO_FLOW_RUN_REDIS_TESTS=1` is set. +//! and only run when `NEMO_RELAY_RUN_REDIS_TESTS=1` is set. #![cfg(feature = "redis-backend")] use std::sync::{Arc, RwLock}; use chrono::Utc; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; -use nemo_flow_adaptive::acg::{StabilityThresholds, analyze_stability, build_prompt_ir}; -use nemo_flow_adaptive::acg_learner::AcgLearner; -use nemo_flow_adaptive::cache_diagnostics::{CacheDiagnosticsTracker, build_cache_request_facts}; -use nemo_flow_adaptive::learner::traits::Learner; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay_adaptive::acg::{StabilityThresholds, analyze_stability, build_prompt_ir}; +use nemo_relay_adaptive::acg_learner::AcgLearner; +use nemo_relay_adaptive::cache_diagnostics::{CacheDiagnosticsTracker, build_cache_request_facts}; +use nemo_relay_adaptive::learner::traits::Learner; use uuid::Uuid; -use nemo_flow_adaptive::redis::RedisBackend; -use nemo_flow_adaptive::storage::traits::{StorageBackend, StorageBackendDyn}; -use nemo_flow_adaptive::trie::accumulator::{AccumulatorState, NodeAccumulators, RunningStats}; -use nemo_flow_adaptive::trie::data_models::PredictionTrieNode; -use nemo_flow_adaptive::trie::serialization::TrieEnvelope; -use nemo_flow_adaptive::types::cache::HotCache; -use nemo_flow_adaptive::types::metadata::MetadataEnvelope; -use nemo_flow_adaptive::types::plan::ExecutionPlan; -use nemo_flow_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::redis::RedisBackend; +use nemo_relay_adaptive::storage::traits::{StorageBackend, StorageBackendDyn}; +use nemo_relay_adaptive::trie::accumulator::{AccumulatorState, NodeAccumulators, RunningStats}; +use nemo_relay_adaptive::trie::data_models::PredictionTrieNode; +use nemo_relay_adaptive::trie::serialization::TrieEnvelope; +use nemo_relay_adaptive::types::cache::HotCache; +use nemo_relay_adaptive::types::metadata::MetadataEnvelope; +use nemo_relay_adaptive::types::plan::ExecutionPlan; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; -const REDIS_TEST_ENV: &str = "NEMO_FLOW_RUN_REDIS_TESTS"; +const REDIS_TEST_ENV: &str = "NEMO_RELAY_RUN_REDIS_TESTS"; // --------------------------------------------------------------------------- // Helpers @@ -485,7 +485,7 @@ async fn redis_integration_persists_runtime_seed_entries_and_manifest_cleanup() let manifest = std::fs::read_to_string(format!("{}/Cargo.toml", env!("CARGO_MANIFEST_DIR"))) .expect("adaptive manifest should be readable"); assert!( - !manifest.contains("nemo-flow-acg"), + !manifest.contains("nemo-relay-acg"), "adaptive manifest should not depend directly on the compatibility shim" ); } diff --git a/crates/adaptive/tests/integration/runtime_integration_tests.rs b/crates/adaptive/tests/integration/runtime_integration_tests.rs index 5302a8328..c371c506d 100644 --- a/crates/adaptive/tests/integration/runtime_integration_tests.rs +++ b/crates/adaptive/tests/integration/runtime_integration_tests.rs @@ -1,47 +1,47 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for runtime integration in the NeMo Flow adaptive crate. +//! Integration tests for runtime integration in the NeMo Relay adaptive crate. use std::pin::Pin; use std::sync::{Arc, Mutex as StdMutex, RwLock}; use chrono::Utc; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::llm::{ +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmStreamCallExecuteParams, llm_call_execute, llm_request_intercepts, llm_stream_call_execute, }; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::api::tool::tool_call_execute; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; -use nemo_flow::codec::response::AnnotatedLlmResponse; -use nemo_flow::codec::traits::LlmResponseCodec; -use nemo_flow::error::{FlowError, Result as FlowResult}; -use nemo_flow::plugin::{ +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::tool::tool_call_execute; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::codec::response::AnnotatedLlmResponse; +use nemo_relay::codec::traits::LlmResponseCodec; +use nemo_relay::error::{FlowError, Result as FlowResult}; +use nemo_relay::plugin::{ ConfigDiagnostic, DiagnosticLevel, Plugin, PluginComponentSpec, PluginConfig, PluginError, PluginRegistrationContext, clear_plugin_configuration, deregister_plugin, initialize_plugins, register_plugin, validate_plugin_config, }; -use nemo_flow::plugin::{ConfigPolicy, UnsupportedBehavior}; -use nemo_flow_adaptive::acg::{StabilityThresholds, analyze_stability, build_prompt_ir}; -use nemo_flow_adaptive::acg_learner::AcgLearner; -use nemo_flow_adaptive::cache_diagnostics::{CacheDiagnosticsTracker, build_cache_request_facts}; -use nemo_flow_adaptive::config::{ +use nemo_relay::plugin::{ConfigPolicy, UnsupportedBehavior}; +use nemo_relay_adaptive::acg::{StabilityThresholds, analyze_stability, build_prompt_ir}; +use nemo_relay_adaptive::acg_learner::AcgLearner; +use nemo_relay_adaptive::cache_diagnostics::{CacheDiagnosticsTracker, build_cache_request_facts}; +use nemo_relay_adaptive::config::{ AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, StateConfig, TelemetryComponentConfig, ToolParallelismComponentConfig, }; -use nemo_flow_adaptive::learner::traits::Learner; -use nemo_flow_adaptive::plugin_component::{ +use nemo_relay_adaptive::learner::traits::Learner; +use nemo_relay_adaptive::plugin_component::{ ComponentSpec as AdaptiveComponent, register_adaptive_component, }; -use nemo_flow_adaptive::types::cache::HotCache; -use nemo_flow_adaptive::types::records::{CallKind, CallRecord, RunRecord}; -use nemo_flow_adaptive::{InMemoryBackend, StorageBackendDyn}; +use nemo_relay_adaptive::types::cache::HotCache; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::{InMemoryBackend, StorageBackendDyn}; use serde_json::{Map, Value as Json, json}; use tokio::sync::Mutex; use tokio_stream::StreamExt; @@ -60,7 +60,7 @@ fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } fn sample_annotated_request(model: &str) -> AnnotatedLlmRequest { @@ -344,7 +344,7 @@ struct FailingResponseCodec; impl LlmResponseCodec for FailingResponseCodec { fn decode_response( &self, - _response: &nemo_flow::json::Json, + _response: &nemo_relay::json::Json, ) -> FlowResult { Err(FlowError::Internal( "response annotation intentionally failed for test".to_string(), @@ -393,8 +393,8 @@ async fn runtime_integration_response_codec_decode_failure_keeps_annotations_opt .unwrap() .iter() .find(|event| { - event.scope_type() == Some(nemo_flow::api::scope::ScopeType::Llm) - && event.scope_category() == Some(nemo_flow::api::event::ScopeCategory::End) + event.scope_type() == Some(nemo_relay::api::scope::ScopeType::Llm) + && event.scope_category() == Some(nemo_relay::api::event::ScopeCategory::End) }) .cloned() .expect("llm end event should still emit"); @@ -506,9 +506,9 @@ async fn runtime_integration_acg_learner_reuses_learning_buckets_across_growing_ "{agent_id}::model=claude-3-5-sonnet::seed={}::system={}::tools=no-tools", short_hash(&format!( "user:{}", - nemo_flow_adaptive::acg::sha256_hex("Summarize the latest findings") + nemo_relay_adaptive::acg::sha256_hex("Summarize the latest findings") )), - short_hash(&nemo_flow_adaptive::acg::sha256_hex( + short_hash(&nemo_relay_adaptive::acg::sha256_hex( "You are a careful planner" )), ); @@ -608,7 +608,7 @@ async fn test_adaptive_plugin_registers_and_passes_calls_through() { let tool_func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let tool_result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("search") .args(json!({"query": "test"})) .func(tool_func) @@ -809,7 +809,7 @@ async fn test_top_level_plugin_registers_request_and_execution_intercepts() { let tool_func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let tool_result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("search") .args(json!({"query": "test"})) .func(tool_func) diff --git a/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs b/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs index 21dc43eb4..7ecfa4290 100644 --- a/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs +++ b/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for tool parallelism plan in the NeMo Flow adaptive crate. +//! Integration tests for tool parallelism plan in the NeMo Relay adaptive crate. use std::sync::{Arc, RwLock}; @@ -9,14 +9,14 @@ use chrono::{Duration, Utc}; use serde_json::json; use uuid::Uuid; -use nemo_flow_adaptive::{ +use nemo_relay_adaptive::{ InMemoryBackend, StorageBackend, StorageBackendDyn, ToolParallelismLearner, }; -use nemo_flow_adaptive::learner::traits::Learner; -use nemo_flow_adaptive::types::cache::HotCache; -use nemo_flow_adaptive::types::metadata::{MetadataEnvelope, ParallelHint}; -use nemo_flow_adaptive::types::plan::{ExecutionPlan, ParallelGroup}; -use nemo_flow_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::learner::traits::Learner; +use nemo_relay_adaptive::types::cache::HotCache; +use nemo_relay_adaptive::types::metadata::{MetadataEnvelope, ParallelHint}; +use nemo_relay_adaptive::types::plan::{ExecutionPlan, ParallelGroup}; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; fn make_hot_cache() -> Arc> { Arc::new(RwLock::new(HotCache { diff --git a/crates/adaptive/tests/unit/acg/anthropic_messages_surface_tests.rs b/crates/adaptive/tests/unit/acg/anthropic_messages_surface_tests.rs index d1ffc2624..415c538e3 100644 --- a/crates/adaptive/tests/unit/acg/anthropic_messages_surface_tests.rs +++ b/crates/adaptive/tests/unit/acg/anthropic_messages_surface_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for anthropic messages surface in the NeMo Flow adaptive crate. +//! Unit tests for anthropic messages surface in the NeMo Relay adaptive crate. use serde_json::json; use super::*; use chrono::Utc; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use uuid::Uuid; use crate::acg::prompt_ir::{ diff --git a/crates/adaptive/tests/unit/acg/anthropic_plugin_tests.rs b/crates/adaptive/tests/unit/acg/anthropic_plugin_tests.rs index 6d12697b0..1b41721c4 100644 --- a/crates/adaptive/tests/unit/acg/anthropic_plugin_tests.rs +++ b/crates/adaptive/tests/unit/acg/anthropic_plugin_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for anthropic plugin in the NeMo Flow adaptive crate. +//! Unit tests for anthropic plugin in the NeMo Relay adaptive crate. use std::sync::Arc; @@ -22,7 +22,7 @@ use crate::acg::types::{ OptimizationIntent, OptimizationIntentBundle, RetentionIntent, RetentionTier, SharingScope, TranslationStatus, }; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use super::AnthropicCachePlugin; diff --git a/crates/adaptive/tests/unit/acg/canonicalize_tests.rs b/crates/adaptive/tests/unit/acg/canonicalize_tests.rs index 60e4e7663..e41d8c97f 100644 --- a/crates/adaptive/tests/unit/acg/canonicalize_tests.rs +++ b/crates/adaptive/tests/unit/acg/canonicalize_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for canonicalize in the NeMo Flow adaptive crate. +//! Unit tests for canonicalize in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/acg/capability_tests.rs b/crates/adaptive/tests/unit/acg/capability_tests.rs index 8fd32a85e..4120735d6 100644 --- a/crates/adaptive/tests/unit/acg/capability_tests.rs +++ b/crates/adaptive/tests/unit/acg/capability_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for capability in the NeMo Flow adaptive crate. +//! Unit tests for capability in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/acg/debug_tests.rs b/crates/adaptive/tests/unit/acg/debug_tests.rs index 210451b0c..401ae8c81 100644 --- a/crates/adaptive/tests/unit/acg/debug_tests.rs +++ b/crates/adaptive/tests/unit/acg/debug_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for debug in the NeMo Flow adaptive crate. +//! Unit tests for debug in the NeMo Relay adaptive crate. use std::process::Command; @@ -22,7 +22,7 @@ fn debug_env_flag_enabled_recognizes_truthy_and_falsey_values() { #[test] fn debug_emit_emits_object_and_scalar_payloads_when_enabled_in_child_process() { - if std::env::var_os("NEMO_FLOW_ACG_DEBUG_CHILD").is_some() { + if std::env::var_os("NEMO_RELAY_ACG_DEBUG_CHILD").is_some() { emit("object", json!({"value": 1})); emit("scalar", json!("payload")); return; @@ -34,14 +34,14 @@ fn debug_emit_emits_object_and_scalar_payloads_when_enabled_in_child_process() { "acg::debug::tests::debug_emit_emits_object_and_scalar_payloads_when_enabled_in_child_process", "--nocapture", ]) - .env("NEMO_FLOW_ACG_DEBUG_CHILD", "1") - .env("NEMO_FLOW_ACG_DEBUG", "1") + .env("NEMO_RELAY_ACG_DEBUG_CHILD", "1") + .env("NEMO_RELAY_ACG_DEBUG", "1") .output() .unwrap(); assert!(output.status.success()); let stderr = String::from_utf8_lossy(&output.stderr); - assert!(stderr.contains("nemo-flow-adaptive acg-debug")); + assert!(stderr.contains("nemo-relay-adaptive acg-debug")); assert!(stderr.contains("\"event\":\"object\"")); assert!(stderr.contains("\"value\":1")); assert!(stderr.contains("\"event\":\"scalar\"")); diff --git a/crates/adaptive/tests/unit/acg/economics_internal_tests.rs b/crates/adaptive/tests/unit/acg/economics_internal_tests.rs index e3d570cab..7a6a01364 100644 --- a/crates/adaptive/tests/unit/acg/economics_internal_tests.rs +++ b/crates/adaptive/tests/unit/acg/economics_internal_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for economics internal in the NeMo Flow adaptive crate. +//! Unit tests for economics internal in the NeMo Relay adaptive crate. use std::collections::HashSet; diff --git a/crates/adaptive/tests/unit/acg/economics_policy_tests.rs b/crates/adaptive/tests/unit/acg/economics_policy_tests.rs index aa8aefcac..1d4a00966 100644 --- a/crates/adaptive/tests/unit/acg/economics_policy_tests.rs +++ b/crates/adaptive/tests/unit/acg/economics_policy_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for economics policy in the NeMo Flow adaptive crate. +//! Unit tests for economics policy in the NeMo Relay adaptive crate. use std::collections::HashSet; diff --git a/crates/adaptive/tests/unit/acg/error_tests.rs b/crates/adaptive/tests/unit/acg/error_tests.rs index 7648dccee..4601c3fd1 100644 --- a/crates/adaptive/tests/unit/acg/error_tests.rs +++ b/crates/adaptive/tests/unit/acg/error_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for error in the NeMo Flow adaptive crate. +//! Unit tests for error in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/acg/ir_builder_tests.rs b/crates/adaptive/tests/unit/acg/ir_builder_tests.rs index b435f8095..2fee6ba62 100644 --- a/crates/adaptive/tests/unit/acg/ir_builder_tests.rs +++ b/crates/adaptive/tests/unit/acg/ir_builder_tests.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for ir builder in the NeMo Flow adaptive crate. +//! Unit tests for ir builder in the NeMo Relay adaptive crate. -use nemo_flow::codec::request::{ +use nemo_relay::codec::request::{ AnnotatedLlmRequest, ContentPart, FunctionCall, FunctionDefinition, Message, MessageContent, ToolCall, ToolDefinition, }; diff --git a/crates/adaptive/tests/unit/acg/mod.rs b/crates/adaptive/tests/unit/acg/mod.rs index 056a8593a..35d782cda 100644 --- a/crates/adaptive/tests/unit/acg/mod.rs +++ b/crates/adaptive/tests/unit/acg/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for acg in the NeMo Flow adaptive crate. +//! Unit tests for acg in the NeMo Relay adaptive crate. mod economics_policy_tests; mod ir_builder_tests; diff --git a/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs b/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs index e600b54de..f4c228482 100644 --- a/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs +++ b/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for multi breakpoint in the NeMo Flow adaptive crate. +//! Unit tests for multi breakpoint in the NeMo Relay adaptive crate. use std::collections::HashSet; diff --git a/crates/adaptive/tests/unit/acg/openai_plugin_tests.rs b/crates/adaptive/tests/unit/acg/openai_plugin_tests.rs index 3b9723e58..b6c4d4255 100644 --- a/crates/adaptive/tests/unit/acg/openai_plugin_tests.rs +++ b/crates/adaptive/tests/unit/acg/openai_plugin_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for openai plugin in the NeMo Flow adaptive crate. +//! Unit tests for openai plugin in the NeMo Relay adaptive crate. use std::sync::Arc; @@ -20,7 +20,7 @@ use crate::acg::types::{ ModelRoutingIntent, OptimizationIntent, OptimizationIntentBundle, ReasonCode, RetentionIntent, RetentionTier, SharingScope, TranslationStatus, }; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use super::OpenAICachePlugin; diff --git a/crates/adaptive/tests/unit/acg/openai_responses_surface_tests.rs b/crates/adaptive/tests/unit/acg/openai_responses_surface_tests.rs index 92011949f..d39cb2b12 100644 --- a/crates/adaptive/tests/unit/acg/openai_responses_surface_tests.rs +++ b/crates/adaptive/tests/unit/acg/openai_responses_surface_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for openai responses surface in the NeMo Flow adaptive crate. +//! Unit tests for openai responses surface in the NeMo Relay adaptive crate. use chrono::Utc; use serde_json::json; diff --git a/crates/adaptive/tests/unit/acg/passthrough_tests.rs b/crates/adaptive/tests/unit/acg/passthrough_tests.rs index 2aa0c44ce..b120d0e5f 100644 --- a/crates/adaptive/tests/unit/acg/passthrough_tests.rs +++ b/crates/adaptive/tests/unit/acg/passthrough_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for passthrough in the NeMo Flow adaptive crate. +//! Unit tests for passthrough in the NeMo Relay adaptive crate. use std::sync::Arc; @@ -19,7 +19,7 @@ use crate::acg::types::{ ModelClass, ModelRoutingIntent, OptimizationIntent, OptimizationIntentBundle, ReasonCode, SharingScope, TranslationStatus, }; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use super::PassthroughPlugin; diff --git a/crates/adaptive/tests/unit/acg/plugin_registry_tests.rs b/crates/adaptive/tests/unit/acg/plugin_registry_tests.rs index 340338bb2..42c347319 100644 --- a/crates/adaptive/tests/unit/acg/plugin_registry_tests.rs +++ b/crates/adaptive/tests/unit/acg/plugin_registry_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for plugin registry in the NeMo Flow adaptive crate. +//! Unit tests for plugin registry in the NeMo Relay adaptive crate. use std::sync::Arc; diff --git a/crates/adaptive/tests/unit/acg/plugin_tests.rs b/crates/adaptive/tests/unit/acg/plugin_tests.rs index 0ffb45640..8b852b8ed 100644 --- a/crates/adaptive/tests/unit/acg/plugin_tests.rs +++ b/crates/adaptive/tests/unit/acg/plugin_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for plugin in the NeMo Flow adaptive crate. +//! Unit tests for plugin in the NeMo Relay adaptive crate. use super::*; use std::sync::Arc; diff --git a/crates/adaptive/tests/unit/acg/profile_tests.rs b/crates/adaptive/tests/unit/acg/profile_tests.rs index d3378f82f..90421b860 100644 --- a/crates/adaptive/tests/unit/acg/profile_tests.rs +++ b/crates/adaptive/tests/unit/acg/profile_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for profile in the NeMo Flow adaptive crate. +//! Unit tests for profile in the NeMo Relay adaptive crate. use chrono::Utc; diff --git a/crates/adaptive/tests/unit/acg/prompt_ir_tests.rs b/crates/adaptive/tests/unit/acg/prompt_ir_tests.rs index 5119a37e8..2bc7ddbe8 100644 --- a/crates/adaptive/tests/unit/acg/prompt_ir_tests.rs +++ b/crates/adaptive/tests/unit/acg/prompt_ir_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for prompt ir in the NeMo Flow adaptive crate. +//! Unit tests for prompt ir in the NeMo Relay adaptive crate. use super::*; use chrono::Utc; diff --git a/crates/adaptive/tests/unit/acg/request_surface_tests.rs b/crates/adaptive/tests/unit/acg/request_surface_tests.rs index 622b60575..b8014f682 100644 --- a/crates/adaptive/tests/unit/acg/request_surface_tests.rs +++ b/crates/adaptive/tests/unit/acg/request_surface_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for request surface in the NeMo Flow adaptive crate. +//! Unit tests for request surface in the NeMo Relay adaptive crate. use chrono::Utc; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::json; use uuid::Uuid; diff --git a/crates/adaptive/tests/unit/acg/retention_tests.rs b/crates/adaptive/tests/unit/acg/retention_tests.rs index 35fc71312..5dd5bf517 100644 --- a/crates/adaptive/tests/unit/acg/retention_tests.rs +++ b/crates/adaptive/tests/unit/acg/retention_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for retention in the NeMo Flow adaptive crate. +//! Unit tests for retention in the NeMo Relay adaptive crate. use crate::acg::profile::DistributionSummary; use crate::acg::retention::{ diff --git a/crates/adaptive/tests/unit/acg/stability_internal_tests.rs b/crates/adaptive/tests/unit/acg/stability_internal_tests.rs index f1277b935..c39843586 100644 --- a/crates/adaptive/tests/unit/acg/stability_internal_tests.rs +++ b/crates/adaptive/tests/unit/acg/stability_internal_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for stability internal in the NeMo Flow adaptive crate. +//! Unit tests for stability internal in the NeMo Relay adaptive crate. use chrono::Utc; diff --git a/crates/adaptive/tests/unit/acg/telemetry_tests.rs b/crates/adaptive/tests/unit/acg/telemetry_tests.rs index 025e4f1b0..7ce86135b 100644 --- a/crates/adaptive/tests/unit/acg/telemetry_tests.rs +++ b/crates/adaptive/tests/unit/acg/telemetry_tests.rs @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for telemetry in the NeMo Flow adaptive crate. +//! Unit tests for telemetry in the NeMo Relay adaptive crate. use super::*; use chrono::{TimeZone, Utc}; -use nemo_flow::codec::response::Usage; +use nemo_relay::codec::response::Usage; use uuid::Uuid; fn assert_send_sync() {} diff --git a/crates/adaptive/tests/unit/acg/translation_tests.rs b/crates/adaptive/tests/unit/acg/translation_tests.rs index f0796be57..0cfa9816a 100644 --- a/crates/adaptive/tests/unit/acg/translation_tests.rs +++ b/crates/adaptive/tests/unit/acg/translation_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for translation in the NeMo Flow adaptive crate. +//! Unit tests for translation in the NeMo Relay adaptive crate. use super::{ AnthropicHintDirective, HintPlan, HintTarget, HintTranslation, HintTranslator, @@ -16,7 +16,7 @@ use crate::acg::types::{ SharingScope, TranslationReport, }; use chrono::Utc; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::json; use uuid::Uuid; diff --git a/crates/adaptive/tests/unit/acg/types_tests.rs b/crates/adaptive/tests/unit/acg/types_tests.rs index 8bd7b531c..8c1ddd590 100644 --- a/crates/adaptive/tests/unit/acg/types_tests.rs +++ b/crates/adaptive/tests/unit/acg/types_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for types in the NeMo Flow adaptive crate. +//! Unit tests for types in the NeMo Relay adaptive crate. use super::*; use chrono::Utc; diff --git a/crates/adaptive/tests/unit/acg/variable_extractor_tests.rs b/crates/adaptive/tests/unit/acg/variable_extractor_tests.rs index ee6c08647..75f335f0b 100644 --- a/crates/adaptive/tests/unit/acg/variable_extractor_tests.rs +++ b/crates/adaptive/tests/unit/acg/variable_extractor_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for variable extractor in the NeMo Flow adaptive crate. +//! Unit tests for variable extractor in the NeMo Relay adaptive crate. use regex::Regex; diff --git a/crates/adaptive/tests/unit/acg_component_tests.rs b/crates/adaptive/tests/unit/acg_component_tests.rs index cc3c30a91..71c5aaabd 100644 --- a/crates/adaptive/tests/unit/acg_component_tests.rs +++ b/crates/adaptive/tests/unit/acg_component_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for acg component in the NeMo Flow adaptive crate. +//! Unit tests for acg component in the NeMo Relay adaptive crate. use super::*; @@ -15,10 +15,10 @@ use crate::acg::prompt_ir::{ }; use crate::storage::memory::InMemoryBackend; use crate::storage::traits::StorageBackendDyn; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::runtime::LlmExecutionNextFn; -use nemo_flow::api::runtime::LlmStreamExecutionNextFn; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::runtime::LlmExecutionNextFn; +use nemo_relay::api::runtime::LlmStreamExecutionNextFn; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; use serde_json::{Value, json}; use tokio_stream::StreamExt; @@ -592,7 +592,7 @@ async fn acg_component_stream_execution_intercept_rewrites_streaming_requests() Box::pin(async move { Ok(Box::pin(tokio_stream::iter(vec![Ok(req.content)])) as Pin< - Box> + Send>, + Box> + Send>, >) }) }); diff --git a/crates/adaptive/tests/unit/acg_learner_tests.rs b/crates/adaptive/tests/unit/acg_learner_tests.rs index 84e610966..664ff5126 100644 --- a/crates/adaptive/tests/unit/acg_learner_tests.rs +++ b/crates/adaptive/tests/unit/acg_learner_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for acg learner in the NeMo Flow adaptive crate. +//! Unit tests for acg learner in the NeMo Relay adaptive crate. use std::future::Future; use std::pin::Pin; use chrono::Utc; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; use uuid::Uuid; use super::*; diff --git a/crates/adaptive/tests/unit/acg_profile_tests.rs b/crates/adaptive/tests/unit/acg_profile_tests.rs index 1b5a4e82f..b09dfc9ad 100644 --- a/crates/adaptive/tests/unit/acg_profile_tests.rs +++ b/crates/adaptive/tests/unit/acg_profile_tests.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for acg profile in the NeMo Flow adaptive crate. +//! Unit tests for acg profile in the NeMo Relay adaptive crate. -use nemo_flow::codec::request::{ +use nemo_relay::codec::request::{ AnnotatedLlmRequest, ContentPart, FunctionDefinition, Message, MessageContent, OpenAiImageUrl, ToolDefinition, }; diff --git a/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs b/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs index 58a3d3b29..a7efa190e 100644 --- a/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs +++ b/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs @@ -1,16 +1,16 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for adaptive hints intercept in the NeMo Flow adaptive crate. +//! Unit tests for adaptive hints intercept in the NeMo Relay adaptive crate. use super::*; use std::sync::{Mutex, OnceLock}; use crate::trie::data_models::{LlmCallPrediction, PredictionMetrics}; -use nemo_flow::api::runtime::current_scope_stack; -use nemo_flow::api::scope::ScopeType; -use nemo_flow::api::scope::{pop_scope, push_scope}; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::api::runtime::current_scope_stack; +use nemo_relay::api::scope::ScopeType; +use nemo_relay::api::scope::{pop_scope, push_scope}; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; static TEST_MUTEX: OnceLock> = OnceLock::new(); @@ -154,14 +154,14 @@ fn test_adaptive_hints_intercept_injects_prediction_hints_and_manual_override() let req_fn = intercept.into_request_fn(); let agent_scope = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("scope-agent") .scope_type(ScopeType::Agent) .build(), ) .unwrap(); let function_scope = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("step") .scope_type(ScopeType::Function) .parent(&agent_scope) @@ -218,13 +218,13 @@ fn test_adaptive_hints_intercept_injects_prediction_hints_and_manual_override() assert_eq!(returned_annotated, Some(annotated)); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&function_scope.uuid) .build(), ) .unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&agent_scope.uuid) .build(), ) diff --git a/crates/adaptive/tests/unit/cache_diagnostics_tests.rs b/crates/adaptive/tests/unit/cache_diagnostics_tests.rs index 86aadef3c..b46c7b846 100644 --- a/crates/adaptive/tests/unit/cache_diagnostics_tests.rs +++ b/crates/adaptive/tests/unit/cache_diagnostics_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for cache diagnostics in the NeMo Flow adaptive crate. +//! Unit tests for cache diagnostics in the NeMo Relay adaptive crate. use std::sync::{Arc, RwLock}; @@ -13,7 +13,7 @@ use crate::acg::prompt_ir::{ }; use crate::acg::stability::StabilityAnalysisResult; use chrono::{Duration, TimeZone, Utc}; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; use serde_json::Map; use uuid::Uuid; diff --git a/crates/adaptive/tests/unit/config_tests.rs b/crates/adaptive/tests/unit/config_tests.rs index dabe2e3a5..22f8ed6f6 100644 --- a/crates/adaptive/tests/unit/config_tests.rs +++ b/crates/adaptive/tests/unit/config_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for config in the NeMo Flow adaptive crate. +//! Unit tests for config in the NeMo Relay adaptive crate. use super::*; -use nemo_flow::config_editor::{EditorConfig, EditorFieldKind}; +use nemo_relay::config_editor::{EditorConfig, EditorFieldKind}; use serde_json::json; #[test] @@ -16,7 +16,7 @@ fn test_adaptive_config_defaults() { assert!(config.tool_parallelism.is_none()); assert_eq!( config.policy.unknown_component, - nemo_flow::plugin::UnsupportedBehavior::Warn + nemo_relay::plugin::UnsupportedBehavior::Warn ); } diff --git a/crates/adaptive/tests/unit/context_helpers_tests.rs b/crates/adaptive/tests/unit/context_helpers_tests.rs index 48a310e72..ced5a0399 100644 --- a/crates/adaptive/tests/unit/context_helpers_tests.rs +++ b/crates/adaptive/tests/unit/context_helpers_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for context helpers in the NeMo Flow adaptive crate. +//! Unit tests for context helpers in the NeMo Relay adaptive crate. use super::*; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; #[test] fn test_latency_sensitivity_pointer_is_valid_json_pointer() { diff --git a/crates/adaptive/tests/unit/drain_tests.rs b/crates/adaptive/tests/unit/drain_tests.rs index 8e8bfef01..63d434942 100644 --- a/crates/adaptive/tests/unit/drain_tests.rs +++ b/crates/adaptive/tests/unit/drain_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for drain in the NeMo Flow adaptive crate. +//! Unit tests for drain in the NeMo Relay adaptive crate. use super::*; use crate::storage::memory::InMemoryBackend; @@ -12,10 +12,10 @@ use crate::types::cache::HotCache; use crate::types::metadata::MetadataEnvelope; use crate::types::plan::{ExecutionPlan, ParallelGroup}; use crate::types::records::RunRecord; -use nemo_flow::api::event::{ +use nemo_relay::api::event::{ BaseEvent, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, }; -use nemo_flow::api::scope::ScopeType; +use nemo_relay::api::scope::ScopeType; use serde_json::json; use std::future::Future; use std::pin::Pin; @@ -805,7 +805,7 @@ fn make_llm_end_with_annotated( uuid: Uuid, parent_uuid: Option, name: &str, - annotated: nemo_flow::codec::response::AnnotatedLlmResponse, + annotated: nemo_relay::codec::response::AnnotatedLlmResponse, ) -> Event { Event::Scope(ScopeEvent::new( BaseEvent::builder() @@ -817,7 +817,7 @@ fn make_llm_end_with_annotated( Vec::new(), EventCategory::llm(), Some( - nemo_flow::api::event::CategoryProfile::builder() + nemo_relay::api::event::CategoryProfile::builder() .annotated_response(std::sync::Arc::new(annotated)) .build(), ), @@ -826,7 +826,7 @@ fn make_llm_end_with_annotated( #[test] fn test_accumulator_extracts_annotated_response() { - use nemo_flow::codec::response::{AnnotatedLlmResponse, ResponseToolCall, Usage}; + use nemo_relay::codec::response::{AnnotatedLlmResponse, ResponseToolCall, Usage}; let mut acc = RunAccumulator::new("agent-1".to_string()); @@ -962,7 +962,7 @@ fn test_accumulator_llm_end_no_annotated_response() { #[test] fn test_accumulator_annotated_response_partial_data() { - use nemo_flow::codec::response::AnnotatedLlmResponse; + use nemo_relay::codec::response::AnnotatedLlmResponse; let mut acc = RunAccumulator::new("agent-1".to_string()); diff --git a/crates/adaptive/tests/unit/intercepts_tests.rs b/crates/adaptive/tests/unit/intercepts_tests.rs index 1e5a64540..98fd16410 100644 --- a/crates/adaptive/tests/unit/intercepts_tests.rs +++ b/crates/adaptive/tests/unit/intercepts_tests.rs @@ -1,15 +1,15 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for intercepts in the NeMo Flow adaptive crate. +//! Unit tests for intercepts in the NeMo Relay adaptive crate. use super::*; use crate::acg::stability::StabilityAnalysisResult; use crate::types::cache::HotCache; use crate::types::metadata::{MetadataEnvelope, ParallelHint}; use crate::types::plan::{ExecutionPlan, ParallelGroup}; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; -use nemo_flow::api::scope::{ScopeHandle, ScopeType}; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::scope::{ScopeHandle, ScopeType}; use serde_json::json; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use tokio::sync::Mutex; diff --git a/crates/adaptive/tests/unit/learner_tests.rs b/crates/adaptive/tests/unit/learner_tests.rs index 6290361cc..f79501ff8 100644 --- a/crates/adaptive/tests/unit/learner_tests.rs +++ b/crates/adaptive/tests/unit/learner_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for learner in the NeMo Flow adaptive crate. +//! Unit tests for learner in the NeMo Relay adaptive crate. use std::collections::HashMap; use std::sync::{Arc, RwLock}; diff --git a/crates/adaptive/tests/unit/plugin_component_tests.rs b/crates/adaptive/tests/unit/plugin_component_tests.rs index 703bd5b50..03fe3f009 100644 --- a/crates/adaptive/tests/unit/plugin_component_tests.rs +++ b/crates/adaptive/tests/unit/plugin_component_tests.rs @@ -1,18 +1,18 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for plugin component in the NeMo Flow adaptive crate. +//! Unit tests for plugin component in the NeMo Relay adaptive crate. use super::*; use std::sync::{Mutex, OnceLock}; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::llm::llm_request_intercepts; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::plugin::{DiagnosticLevel, UnsupportedBehavior, clear_plugin_configuration}; -use nemo_flow::plugin::{Plugin, PluginRegistrationContext, rollback_registrations}; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::llm::llm_request_intercepts; +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::plugin::{DiagnosticLevel, UnsupportedBehavior, clear_plugin_configuration}; +use nemo_relay::plugin::{Plugin, PluginRegistrationContext, rollback_registrations}; use serde_json::json; use tokio::sync::Mutex as AsyncMutex; @@ -28,7 +28,7 @@ fn reset_global() { let _ = deregister_adaptive_component(); let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } #[test] @@ -259,32 +259,32 @@ fn validate_backend_config_fields_only_flags_known_backend_extras() { fn adaptive_to_plugin_error_maps_all_non_redis_variants() { assert!(matches!( adaptive_to_plugin_error(AdaptiveError::InvalidConfig("bad".into())), - nemo_flow::plugin::PluginError::InvalidConfig(message) if message == "bad" + nemo_relay::plugin::PluginError::InvalidConfig(message) if message == "bad" )); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::NotFound("missing".into())), - nemo_flow::plugin::PluginError::NotFound(message) if message == "missing" + nemo_relay::plugin::PluginError::NotFound(message) if message == "missing" )); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::Storage("store".into())), - nemo_flow::plugin::PluginError::Internal(message) if message == "store" + nemo_relay::plugin::PluginError::Internal(message) if message == "store" )); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::Internal("internal".into())), - nemo_flow::plugin::PluginError::Internal(message) if message == "internal" + nemo_relay::plugin::PluginError::Internal(message) if message == "internal" )); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::RegistrationFailed("register".into())), - nemo_flow::plugin::PluginError::RegistrationFailed(message) if message == "register" + nemo_relay::plugin::PluginError::RegistrationFailed(message) if message == "register" )); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::ChannelClosed("closed".into())), - nemo_flow::plugin::PluginError::Internal(message) if message == "closed" + nemo_relay::plugin::PluginError::Internal(message) if message == "closed" )); let serde_error = serde_json::from_str::("{").unwrap_err(); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::Serialization(serde_error)), - nemo_flow::plugin::PluginError::Serialization(_) + nemo_relay::plugin::PluginError::Serialization(_) )); } @@ -294,7 +294,7 @@ fn adaptive_to_plugin_error_maps_redis_variant() { let redis_error = redis::Client::open("redis://bad host").unwrap_err(); assert!(matches!( adaptive_to_plugin_error(AdaptiveError::Redis(redis_error)), - nemo_flow::plugin::PluginError::Internal(message) if message.contains("Redis URL") + nemo_relay::plugin::PluginError::Internal(message) if message.contains("Redis URL") )); } diff --git a/crates/adaptive/tests/unit/redis_tests.rs b/crates/adaptive/tests/unit/redis_tests.rs index 2226a9f64..a098c6636 100644 --- a/crates/adaptive/tests/unit/redis_tests.rs +++ b/crates/adaptive/tests/unit/redis_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for redis in the NeMo Flow adaptive crate. +//! Unit tests for redis in the NeMo Relay adaptive crate. use super::*; @@ -16,7 +16,7 @@ use crate::types::metadata::MetadataEnvelope; use crate::types::plan::ExecutionPlan; use crate::types::records::RunRecord; -const REDIS_TEST_ENV: &str = "NEMO_FLOW_RUN_REDIS_TESTS"; +const REDIS_TEST_ENV: &str = "NEMO_RELAY_RUN_REDIS_TESTS"; async fn get_test_redis() -> Option { if std::env::var_os(REDIS_TEST_ENV).is_none() { diff --git a/crates/adaptive/tests/unit/runtime_features_tests.rs b/crates/adaptive/tests/unit/runtime_features_tests.rs index 1c441381e..f60adb4ab 100644 --- a/crates/adaptive/tests/unit/runtime_features_tests.rs +++ b/crates/adaptive/tests/unit/runtime_features_tests.rs @@ -1,28 +1,28 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for runtime features in the NeMo Flow adaptive crate. +//! Unit tests for runtime features in the NeMo Relay adaptive crate. use super::*; use std::sync::Arc; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::llm::llm_request_intercepts; -use nemo_flow::api::registry::{ +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::llm::llm_request_intercepts; +use nemo_relay::api::registry::{ deregister_llm_execution_intercept, deregister_llm_request_intercept, deregister_llm_stream_execution_intercept, deregister_tool_execution_intercept, register_llm_execution_intercept, register_llm_request_intercept, register_llm_stream_execution_intercept, register_tool_execution_intercept, }; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::ToolExecutionNextFn; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::api::tool::tool_call_execute; -use nemo_flow::error::FlowError; -use nemo_flow::plugin::{ConfigPolicy, UnsupportedBehavior}; -use nemo_flow::plugin::{clear_plugin_configuration, rollback_registrations}; +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::ToolExecutionNextFn; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::tool::tool_call_execute; +use nemo_relay::error::FlowError; +use nemo_relay::plugin::{ConfigPolicy, UnsupportedBehavior}; +use nemo_relay::plugin::{clear_plugin_configuration, rollback_registrations}; use serde_json::json; use tokio::sync::Mutex; @@ -40,7 +40,7 @@ fn reset_global() { let _ = clear_plugin_configuration(); let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } fn sample_plan(agent_id: &str) -> ExecutionPlan { @@ -63,7 +63,7 @@ fn sample_plan(agent_id: &str) -> ExecutionPlan { } } -fn assert_already_registered(result: nemo_flow::error::Result<()>, name: &str) { +fn assert_already_registered(result: nemo_relay::error::Result<()>, name: &str) { match result { Err(FlowError::AlreadyExists(message)) => assert!(message.contains(name)), other => panic!("expected {name} to be registered, got {other:?}"), @@ -425,7 +425,7 @@ async fn tool_parallelism_feature_registers_execution_intercept() { let next: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("search") .args(json!({"query": "coverage"})) .func(next) @@ -565,7 +565,7 @@ async fn registration_context_registers_all_supported_callback_types() { as Pin< Box< dyn tokio_stream::Stream< - Item = nemo_flow::error::Result, + Item = nemo_relay::error::Result, > + Send, >, >) diff --git a/crates/adaptive/tests/unit/runtime_tests.rs b/crates/adaptive/tests/unit/runtime_tests.rs index a25ce2cef..5802a58a6 100644 --- a/crates/adaptive/tests/unit/runtime_tests.rs +++ b/crates/adaptive/tests/unit/runtime_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for runtime in the NeMo Flow adaptive crate. +//! Unit tests for runtime in the NeMo Relay adaptive crate. -use nemo_flow::api::llm::{LlmRequest, llm_request_intercepts}; -use nemo_flow::api::runtime::{ - NemoFlowContextState, create_scope_stack, global_context, set_thread_scope_stack, +use nemo_relay::api::llm::{LlmRequest, llm_request_intercepts}; +use nemo_relay::api::runtime::{ + NemoRelayContextState, create_scope_stack, global_context, set_thread_scope_stack, }; -use nemo_flow::api::scope::{PopScopeParams, PushScopeParams, ScopeType, pop_scope, push_scope}; +use nemo_relay::api::scope::{PopScopeParams, PushScopeParams, ScopeType, pop_scope, push_scope}; use serde_json::{Map, Value as Json}; use crate::config::{ @@ -18,16 +18,16 @@ use crate::error::AdaptiveError; use crate::runtime::backend::build_backend; use crate::runtime::features::AdaptiveRuntime; use crate::runtime::validation::validate_config; -use nemo_flow::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; -use nemo_flow::plugin::{ConfigPolicy, UnsupportedBehavior}; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay::plugin::{ConfigPolicy, UnsupportedBehavior}; #[cfg(feature = "redis-backend")] -const REDIS_TEST_ENV: &str = "NEMO_FLOW_RUN_REDIS_TESTS"; +const REDIS_TEST_ENV: &str = "NEMO_RELAY_RUN_REDIS_TESTS"; fn reset_runtime_context() { let context = global_context(); let mut state = context.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); set_thread_scope_stack(create_scope_stack()); } @@ -286,7 +286,7 @@ fn validate_config_reports_unknown_backend_and_acg_provider_per_policy() { .diagnostics .iter() .any(|diag| diag.code == "adaptive.unknown_backend" - && diag.level == nemo_flow::plugin::DiagnosticLevel::Warning) + && diag.level == nemo_relay::plugin::DiagnosticLevel::Warning) ); assert!( warn_report @@ -378,7 +378,7 @@ fn adaptive_owned_runtime_sources_use_canonical_acg_module_paths() { for (path, source, canonical_patterns) in owned_sources { assert!( - !source.contains("nemo_flow_acg::"), + !source.contains("nemo_relay_acg::"), "{path} should not fall back to the compatibility shim", ); for canonical_pattern in canonical_patterns { diff --git a/crates/adaptive/tests/unit/storage_memory_internal_tests.rs b/crates/adaptive/tests/unit/storage_memory_internal_tests.rs index 7af289a4d..311f007dc 100644 --- a/crates/adaptive/tests/unit/storage_memory_internal_tests.rs +++ b/crates/adaptive/tests/unit/storage_memory_internal_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for storage memory internal in the NeMo Flow adaptive crate. +//! Unit tests for storage memory internal in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/storage_tests.rs b/crates/adaptive/tests/unit/storage_tests.rs index 53036e049..955dc8c76 100644 --- a/crates/adaptive/tests/unit/storage_tests.rs +++ b/crates/adaptive/tests/unit/storage_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for storage in the NeMo Flow adaptive crate. +//! Unit tests for storage in the NeMo Relay adaptive crate. use chrono::Utc; use serde_json::json; diff --git a/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs b/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs index 2fb8e6d98..5d28bacc7 100644 --- a/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs +++ b/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for tool parallelism learner in the NeMo Flow adaptive crate. +//! Unit tests for tool parallelism learner in the NeMo Relay adaptive crate. use std::sync::{Arc, RwLock}; diff --git a/crates/adaptive/tests/unit/trie/accumulator_tests.rs b/crates/adaptive/tests/unit/trie/accumulator_tests.rs index af4fa48f5..b33fc43bd 100644 --- a/crates/adaptive/tests/unit/trie/accumulator_tests.rs +++ b/crates/adaptive/tests/unit/trie/accumulator_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for accumulator in the NeMo Flow adaptive crate. +//! Unit tests for accumulator in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/trie/builder_tests.rs b/crates/adaptive/tests/unit/trie/builder_tests.rs index 07a9eef9d..d47abc613 100644 --- a/crates/adaptive/tests/unit/trie/builder_tests.rs +++ b/crates/adaptive/tests/unit/trie/builder_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for builder in the NeMo Flow adaptive crate. +//! Unit tests for builder in the NeMo Relay adaptive crate. use super::*; use chrono::{Duration, Utc}; diff --git a/crates/adaptive/tests/unit/trie/data_models_tests.rs b/crates/adaptive/tests/unit/trie/data_models_tests.rs index a1058537c..f9ef1aa49 100644 --- a/crates/adaptive/tests/unit/trie/data_models_tests.rs +++ b/crates/adaptive/tests/unit/trie/data_models_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for data models in the NeMo Flow adaptive crate. +//! Unit tests for data models in the NeMo Relay adaptive crate. use super::*; diff --git a/crates/adaptive/tests/unit/trie/lookup_tests.rs b/crates/adaptive/tests/unit/trie/lookup_tests.rs index f210786db..3ae75bef5 100644 --- a/crates/adaptive/tests/unit/trie/lookup_tests.rs +++ b/crates/adaptive/tests/unit/trie/lookup_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for lookup in the NeMo Flow adaptive crate. +//! Unit tests for lookup in the NeMo Relay adaptive crate. use super::*; use crate::trie::data_models::PredictionMetrics; diff --git a/crates/adaptive/tests/unit/trie/serialization_tests.rs b/crates/adaptive/tests/unit/trie/serialization_tests.rs index 4b973b5c4..21743e160 100644 --- a/crates/adaptive/tests/unit/trie/serialization_tests.rs +++ b/crates/adaptive/tests/unit/trie/serialization_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for serialization in the NeMo Flow adaptive crate. +//! Unit tests for serialization in the NeMo Relay adaptive crate. use super::*; use crate::trie::data_models::{LlmCallPrediction, PredictionMetrics}; diff --git a/crates/adaptive/tests/unit/types_tests.rs b/crates/adaptive/tests/unit/types_tests.rs index 252337299..c31b0c58d 100644 --- a/crates/adaptive/tests/unit/types_tests.rs +++ b/crates/adaptive/tests/unit/types_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for types in the NeMo Flow adaptive crate. +//! Unit tests for types in the NeMo Relay adaptive crate. use std::collections::HashMap; @@ -159,7 +159,7 @@ fn acg_storage_and_hot_cache_sources_use_canonical_acg_types() { for (path, source, canonical_patterns) in canonical_sources { assert!( - !source.contains("nemo_flow_acg::"), + !source.contains("nemo_relay_acg::"), "{path} should not point back at the shim-owned namespace", ); for canonical_pattern in canonical_patterns { diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 0b6c9e5d2..ff21b39ae 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -2,15 +2,15 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-cli" +name = "nemo-relay-cli" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Coding-agent gateway CLI for NeMo Flow observability." +description = "Coding-agent gateway CLI for NeMo Relay observability." [[bin]] -name = "nemo-flow" +name = "nemo-relay" path = "src/main.rs" [package.metadata.binstall] @@ -21,8 +21,8 @@ pkg-fmt = "bin" workspace = true [dependencies] -nemo-flow = { workspace = true, features = ["openinference"] } -nemo-flow-adaptive = { workspace = true, features = ["redis-backend"] } +nemo-relay = { workspace = true, features = ["openinference"] } +nemo-relay-adaptive = { workspace = true, features = ["redis-backend"] } async-stream = "0.3" axum = "0.8" bytes = "1" diff --git a/crates/cli/README.md b/crates/cli/README.md index 848898aec..c1300bdbb 100644 --- a/crates/cli/README.md +++ b/crates/cli/README.md @@ -3,49 +3,49 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow-cli` installs the NeMo Flow CLI, the `nemo-flow` binary for local +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay-cli` installs the NeMo Relay CLI, the `nemo-relay` binary for local coding-agent observability. It can configure supported coding-agent hooks, run agents through an ephemeral gateway, and diagnose local agent and exporter readiness. The CLI is a Rust package in this repository, but most users should interact -with the installed `nemo-flow` command rather than link against the crate. +with the installed `nemo-relay` command rather than link against the crate. ## Why Use It? - 🧭 **Observe existing coding agents**: Run Claude Code, Codex, Cursor, or - Hermes Agent through a local NeMo Flow gateway without changing the agent + Hermes Agent through a local NeMo Relay gateway without changing the agent itself. - 🛠️ **Configure hooks interactively**: Use the setup wizard to write project or user config and install the hook files needed by supported agents. - 📡 **Export local sessions**: Write ATIF trajectory files, ATOF event JSONL streams, or OpenInference spans from one shared config model. - 🩺 **Diagnose the machine**: Check config layers, agent binaries, hook status, - observability outputs, and shell completions with `nemo-flow doctor`. + observability outputs, and shell completions with `nemo-relay doctor`. ## What You Get -- ✅ **`nemo-flow` binary**: The executable installed by the `nemo-flow-cli` +- ✅ **`nemo-relay` binary**: The executable installed by the `nemo-relay-cli` Cargo package. -- ✅ **First-run setup**: Bare `nemo-flow` launches setup when no config exists, +- ✅ **First-run setup**: Bare `nemo-relay` launches setup when no config exists, then runs doctor once config is present. -- ✅ **Agent shortcuts**: `nemo-flow claude`, `nemo-flow codex`, - `nemo-flow cursor`, and `nemo-flow hermes` start observed agent runs. -- ✅ **Config-driven launch**: `nemo-flow run` resolves config, environment, and +- ✅ **Agent shortcuts**: `nemo-relay claude`, `nemo-relay codex`, + `nemo-relay cursor`, and `nemo-relay hermes` start observed agent runs. +- ✅ **Config-driven launch**: `nemo-relay run` resolves config, environment, and CLI overrides for deterministic non-interactive use. - ✅ **Hook forwarding server**: A local gateway accepts agent hook events and provider-shaped OpenAI or Anthropic requests. @@ -55,13 +55,13 @@ with the installed `nemo-flow` command rather than link against the crate. Install the CLI: ```bash -cargo install nemo-flow-cli +cargo install nemo-relay-cli ``` That command installs the binary as: ```bash -nemo-flow --version +nemo-relay --version ``` ## Getting Started @@ -69,52 +69,52 @@ nemo-flow --version Run the first-time setup wizard: ```bash -nemo-flow +nemo-relay ``` After setup, inspect local readiness: ```bash -nemo-flow doctor +nemo-relay doctor ``` Run a supported agent through the gateway: ```bash -nemo-flow codex -nemo-flow claude -- "summarize this repository" +nemo-relay codex +nemo-relay claude -- "summarize this repository" ``` Use `run --dry-run` to inspect resolved config without spawning the agent: ```bash -nemo-flow run --agent codex --dry-run +nemo-relay run --agent codex --dry-run ``` ## Configuration -Project config lives at `./.nemo-flow/config.toml`; user config lives at -`~/.config/nemo-flow/config.toml` or `$XDG_CONFIG_HOME/nemo-flow/config.toml`. +Project config lives at `./.nemo-relay/config.toml`; user config lives at +`~/.config/nemo-relay/config.toml` or `$XDG_CONFIG_HOME/nemo-relay/config.toml`. The project layer overrides system config, and the user layer overrides the project layer. General options are configured through the top-level config. Edit the config with: ```bash -nemo-flow config +nemo-relay config ``` Observability exporters are configured through the plugin config. Edit the user plugin config with: ```bash -nemo-flow plugins edit +nemo-relay plugins edit ``` The canonical plugin file is `plugins.toml`; user config lives at -`~/.config/nemo-flow/plugins.toml` or -`$XDG_CONFIG_HOME/nemo-flow/plugins.toml`. Project config lives at -`.nemo-flow/plugins.toml`. +`~/.config/nemo-relay/plugins.toml` or +`$XDG_CONFIG_HOME/nemo-relay/plugins.toml`. Project config lives at +`.nemo-relay/plugins.toml`. Minimal ATIF example: @@ -132,4 +132,4 @@ output_directory = "./atif" ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow/ +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay/ diff --git a/crates/cli/src/adapters/hermes.rs b/crates/cli/src/adapters/hermes.rs index 743d0518f..23acbad81 100644 --- a/crates/cli/src/adapters/hermes.rs +++ b/crates/cli/src/adapters/hermes.rs @@ -131,7 +131,7 @@ fn hermes_api_call_id(payload: &Value, session_id: &str) -> String { fn hermes_llm_request(payload: &Value) -> Value { // Prefer first-party sanitized request bodies from newer Hermes telemetry hooks. This is still - // observer-only data: NeMo Flow is not intercepting or rewriting Hermes execution here. When the + // observer-only data: NeMo Relay is not intercepting or rewriting Hermes execution here. When the // exact payload is absent or was truncated by Hermes, fall back to the legacy summary shape. if let Some(request) = hermes_exact_request(payload) { return request; diff --git a/crates/cli/src/adapters/mod.rs b/crates/cli/src/adapters/mod.rs index c8a91a214..3b3d49b35 100644 --- a/crates/cli/src/adapters/mod.rs +++ b/crates/cli/src/adapters/mod.rs @@ -35,7 +35,7 @@ pub(super) struct ClassificationRules<'a> { // fields, and finally a v7 UUID. Header precedence lets gateway and hook-forward callers // correlate events even when agent payload schemas omit or rename their native session field. fn session_id(payload: &Value, headers: &HeaderMap) -> String { - header_string(headers, "x-nemo-flow-session-id") + header_string(headers, "x-nemo-relay-session-id") .or_else(|| header_string(headers, "x-claude-code-session-id")) .or_else(|| session_id_from_payload(payload)) .unwrap_or_else(|| format!("hook-{}", Uuid::now_v7())) @@ -85,7 +85,7 @@ fn metadata(payload: &Value, headers: &HeaderMap, kind: AgentKind, event_name: & let mut object = Map::new(); object.insert("agent_kind".into(), json!(kind.as_str())); object.insert("hook_event_name".into(), json!(event_name)); - if let Some(profile) = header_string(headers, "x-nemo-flow-config-profile") { + if let Some(profile) = header_string(headers, "x-nemo-relay-config-profile") { object.insert("gateway_config_profile".into(), json!(profile)); } for (key, value) in [ @@ -127,7 +127,7 @@ pub(crate) fn common_session_event( fn common_subagent_event(payload: &Value, headers: &HeaderMap, kind: AgentKind) -> SubagentEvent { let session = common_session_event(payload, headers, kind); let subagent_id = subagent_id(payload) - .or_else(|| header_string(headers, "x-nemo-flow-subagent-id")) + .or_else(|| header_string(headers, "x-nemo-relay-subagent-id")) .unwrap_or_else(|| "subagent".to_string()); SubagentEvent { session_id: session.session_id, @@ -223,7 +223,7 @@ fn first_string_at(payload: &Value, paths: &[&[&str]]) -> Option { // because it is the agent's native ownership signal; the header exists for gateway correlation and // sparse hook systems. fn hook_subagent_id(payload: &Value, headers: &HeaderMap) -> Option { - subagent_id(payload).or_else(|| header_string(headers, "x-nemo-flow-subagent-id")) + subagent_id(payload).or_else(|| header_string(headers, "x-nemo-relay-subagent-id")) } // Resolves a tool call identifier from all known agent payload conventions before synthesizing a diff --git a/crates/cli/src/alignment/claude_code.rs b/crates/cli/src/alignment/claude_code.rs index b85a821fb..e1abccccb 100644 --- a/crates/cli/src/alignment/claude_code.rs +++ b/crates/cli/src/alignment/claude_code.rs @@ -20,7 +20,7 @@ pub(crate) fn owns_gateway_provider(provider: &str) -> bool { matches!(provider, "anthropic.messages" | "anthropic.count_tokens") } -// Claude Code already has a stable session id header. Accept it after the explicit NeMo Flow +// Claude Code already has a stable session id header. Accept it after the explicit NeMo Relay // header so existing Claude environments correlate without extra gateway-specific configuration. pub(crate) fn session_id_from_headers(headers: &HeaderMap) -> Option { header_string(headers, "x-claude-code-session-id") diff --git a/crates/cli/src/alignment/mod.rs b/crates/cli/src/alignment/mod.rs index 7eb94feb5..78f805eb2 100644 --- a/crates/cli/src/alignment/mod.rs +++ b/crates/cli/src/alignment/mod.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; use axum::http::HeaderMap; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::{Map, Value, json}; use crate::config::header_string; @@ -209,7 +209,7 @@ impl SessionAlignmentState { } // Resolves the session id for a gateway request in precedence order: -// explicit NeMo Flow header, agent-native headers, then agent-specific body fallbacks. Keeping the +// explicit NeMo Relay header, agent-native headers, then agent-specific body fallbacks. Keeping the // provider fallbacks behind one function makes a new agent integration add one small alignment // adapter instead of threading bespoke checks through gateway request construction. pub(crate) fn gateway_session_id( @@ -217,7 +217,7 @@ pub(crate) fn gateway_session_id( body: &Value, route: GatewayRouteKind, ) -> Option { - header_string(headers, "x-nemo-flow-session-id") + header_string(headers, "x-nemo-relay-session-id") .or_else(|| claude_code::session_id_from_headers(headers)) .or_else(|| codex::prompt_cache_session_id(body, route)) } @@ -254,7 +254,7 @@ pub(crate) fn gateway_forward_headers( // the target worker scope. Unlike session ids, there is intentionally no body fallback here: // subagent body fields are provider-specific and easy to confuse with tool-call payload content. pub(crate) fn gateway_subagent_id(headers: &HeaderMap) -> Option { - header_string(headers, "x-nemo-flow-subagent-id") + header_string(headers, "x-nemo-relay-subagent-id") } // Resolves a correlation identifier from a dedicated header before trying known JSON body paths. diff --git a/crates/cli/src/banner.rs b/crates/cli/src/banner.rs index 978bb3e03..dec7f6bf6 100644 --- a/crates/cli/src/banner.rs +++ b/crates/cli/src/banner.rs @@ -1,20 +1,20 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Slanted ANSI-Shadow "NeMo Flow" banner. +//! Slanted ANSI-Shadow "NeMo Relay" banner. //! //! Static art: filled block letters in NVIDIA green, each row shifted one column right of the //! row above for an italic lean. The settled frame includes a small "vX.Y.Z" tag in green at //! the bottom-right. //! //! Three entry points: -//! - [`print_intro`] — wizard intro / bare `nemo-flow` +//! - [`print_intro`] — wizard intro / bare `nemo-relay` //! - [`print_doctor_header`] — settled static frame for `doctor` //! - [`render_frame`] — pure helper for tests use std::io::IsTerminal; -/// Filled-block NeMo Flow figlet with a per-row right shift so the letters lean italic. Six +/// Filled-block NeMo Relay figlet with a per-row right shift so the letters lean italic. Six /// content rows; the renderer prepends one blank row above and appends one below for spacing /// and the docked version tag. const BANNER_LINES: &[&str] = &[ @@ -265,7 +265,7 @@ pub(crate) fn print_doctor_header() { fn print_plain_header() { let version = env!("CARGO_PKG_VERSION"); println!(); - println!(" NeMo Flow v{version}"); + println!(" NeMo Relay v{version}"); println!(); } diff --git a/crates/cli/src/completions_install.rs b/crates/cli/src/completions_install.rs index e11b2bb2d..8c0ef63de 100644 --- a/crates/cli/src/completions_install.rs +++ b/crates/cli/src/completions_install.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! `nemo-flow completions install` — write a shell completion script to the standard fpath / +//! `nemo-relay completions install` — write a shell completion script to the standard fpath / //! completions directory for the user's current `$SHELL`. Mirrors the file layout used by //! `scripts/install.sh` so curl-pipe installs and `cargo install` installs land in the same //! place. @@ -31,7 +31,7 @@ pub(crate) fn install(shell: Option) -> Result { } let mut clap_command = ::command(); let mut buffer = Vec::new(); - clap_complete::generate(shell, &mut clap_command, "nemo-flow", &mut buffer); + clap_complete::generate(shell, &mut clap_command, "nemo-relay", &mut buffer); write_atomic(&target, &buffer)?; Ok(target) } @@ -49,23 +49,23 @@ fn completion_path( let base = zdotdir.or(home).ok_or_else(|| { CliError::Config("cannot resolve $ZDOTDIR or $HOME for zsh completion".into()) })?; - Ok(PathBuf::from(base).join(".zfunc/_nemo-flow")) + Ok(PathBuf::from(base).join(".zfunc/_nemo-relay")) } Shell::Bash => { let home = home.ok_or_else(|| { CliError::Config("cannot resolve $HOME for bash completion".into()) })?; - Ok(PathBuf::from(home).join(".bash_completion.d/nemo-flow")) + Ok(PathBuf::from(home).join(".bash_completion.d/nemo-relay")) } Shell::Fish => { let home = home.ok_or_else(|| { CliError::Config("cannot resolve $HOME for fish completion".into()) })?; - Ok(PathBuf::from(home).join(".config/fish/completions/nemo-flow.fish")) + Ok(PathBuf::from(home).join(".config/fish/completions/nemo-relay.fish")) } other => Err(CliError::Config(format!( - "`nemo-flow completions install` does not support {other} — \ - run `nemo-flow completions {other}` and redirect manually" + "`nemo-relay completions install` does not support {other} — \ + run `nemo-relay completions {other}` and redirect manually" ))), } } @@ -76,7 +76,7 @@ fn completion_path( fn detect_shell(shell_env: Option) -> Result { let raw = shell_env.ok_or_else(|| { CliError::Config( - "$SHELL is not set; pass an explicit shell, e.g. `nemo-flow completions install zsh`" + "$SHELL is not set; pass an explicit shell, e.g. `nemo-relay completions install zsh`" .into(), ) })?; @@ -90,7 +90,7 @@ fn detect_shell(shell_env: Option) -> Result { "fish" => Ok(Shell::Fish), _ => Err(CliError::Config(format!( "unsupported $SHELL `{name}` — \ - run `nemo-flow completions ` and redirect manually" + run `nemo-relay completions ` and redirect manually" ))), } } @@ -102,7 +102,7 @@ fn write_atomic(target: &Path, bytes: &[u8]) -> Result<(), CliError> { let file_name = target .file_name() .and_then(|value| value.to_str()) - .unwrap_or("nemo-flow"); + .unwrap_or("nemo-relay"); let temp = parent.join(format!(".{file_name}.tmp")); let mut handle = std::fs::File::create(&temp)?; handle.write_all(bytes)?; diff --git a/crates/cli/src/config.rs b/crates/cli/src/config.rs index 508a9a2c1..2307065fc 100644 --- a/crates/cli/src/config.rs +++ b/crates/cli/src/config.rs @@ -13,8 +13,8 @@ use serde_json::Value; use crate::error::CliError; #[derive(Debug, Clone, Parser)] -#[command(name = "nemo-flow")] -#[command(about = "Coding-agent gateway for NeMo Flow observability")] +#[command(name = "nemo-relay")] +#[command(about = "Coding-agent gateway for NeMo Relay observability")] #[command(version)] pub(crate) struct Cli { #[command(flatten)] @@ -27,55 +27,55 @@ pub(crate) struct Cli { pub(crate) enum Command { /// Run Claude Code with observability (setup on first use) #[command( - long_about = "Run Anthropic's `claude` CLI under an ephemeral NeMo Flow gateway. \ + long_about = "Run Anthropic's `claude` CLI under an ephemeral NeMo Relay gateway. \ Observability (ATIF + OpenInference) is wired in transparently via \ ANTHROPIC_BASE_URL. First-time use launches the setup wizard so the \ - `[agents.claude]` block lands in `.nemo-flow/config.toml` and observation \ + `[agents.claude]` block lands in `.nemo-relay/config.toml` and observation \ starts on the next invocation without prompts.", after_help = "Examples:\n \ - nemo-flow claude\n \ - nemo-flow claude -- chat \"refactor the launcher\"\n \ - nemo-flow claude -- --resume " + nemo-relay claude\n \ + nemo-relay claude -- chat \"refactor the launcher\"\n \ + nemo-relay claude -- --resume " )] Claude(EasyPathCommand), /// Run Codex with observability (setup on first use) #[command( - long_about = "Run OpenAI's `codex` CLI under an ephemeral NeMo Flow gateway. NeMo Flow \ - injects a `nemo-flow-openai` provider override so codex points at the \ + long_about = "Run OpenAI's `codex` CLI under an ephemeral NeMo Relay gateway. NeMo Relay \ + injects a `nemo-relay-openai` provider override so codex points at the \ gateway; the gateway then forwards to `--openai-base-url` (defaults to \ api.openai.com) with `OPENAI_API_KEY` injected on the codex route (see \ NMF-86 — codex's own auth.json JWT is stripped). Requires codex-cli >= \ 0.129.0.", after_help = "Examples:\n \ - nemo-flow codex\n \ - nemo-flow codex -- exec \"fix the bug in foo.rs\"\n \ - nemo-flow --openai-base-url https://inference-api.nvidia.com codex" + nemo-relay codex\n \ + nemo-relay codex -- exec \"fix the bug in foo.rs\"\n \ + nemo-relay --openai-base-url https://inference-api.nvidia.com codex" )] Codex(EasyPathCommand), /// Run Cursor with observability (setup on first use) #[command( - long_about = "Run Cursor's `cursor-agent` CLI under an ephemeral NeMo Flow gateway. The \ + long_about = "Run Cursor's `cursor-agent` CLI under an ephemeral NeMo Relay gateway. The \ launcher temporarily patches `.cursor/hooks.json` in the project root \ during the run and restores it on exit. Disable that via \ `[agents.cursor] patch_restore_hooks = false` in config.toml if you \ maintain `.cursor/hooks.json` yourself.", after_help = "Examples:\n \ - nemo-flow cursor\n \ - nemo-flow cursor -- agent --resume " + nemo-relay cursor\n \ + nemo-relay cursor -- agent --resume " )] Cursor(EasyPathCommand), /// Run Hermes with observability (setup on first use) #[command( - long_about = "Run NVIDIA's Hermes agent under a NeMo Flow gateway. Hermes reads hooks \ + long_about = "Run NVIDIA's Hermes agent under a NeMo Relay gateway. Hermes reads hooks \ from `.hermes/config.yaml`; first-run setup writes that file alongside \ - `.nemo-flow/config.toml` so every subsequent invocation traces \ - automatically. Re-run `nemo-flow config hermes` to refresh the hooks.", + `.nemo-relay/config.toml` so every subsequent invocation traces \ + automatically. Re-run `nemo-relay config hermes` to refresh the hooks.", after_help = "Examples:\n \ - nemo-flow hermes\n \ - nemo-flow hermes -- chat --provider custom" + nemo-relay hermes\n \ + nemo-relay hermes -- chat --provider custom" )] Hermes(EasyPathCommand), - /// Run the interactive setup (writes `.nemo-flow/config.toml`) + /// Run the interactive setup (writes `.nemo-relay/config.toml`) Config(ConfigCommand), /// Create or edit plugin configuration (writes `plugins.toml`) Plugins(PluginsCommand), @@ -83,7 +83,7 @@ pub(crate) enum Command { Doctor(DoctorCommand), /// List supported and locally-detected agents (use `--json` for machine output) Agents(AgentsCommand), - /// Print shell completion script (e.g. `nemo-flow completions zsh > ~/.zfunc/_nemo-flow`) + /// Print shell completion script (e.g. `nemo-relay completions zsh > ~/.zfunc/_nemo-relay`) Completions(CompletionsCommand), /// Run an agent deterministically (no wizard; errors if config is missing) Run(RunCommand), @@ -92,7 +92,7 @@ pub(crate) enum Command { HookForward(HookForwardCommand), } -/// Args for `nemo-flow doctor`. `--json` is on this command (rather than as a global flag) +/// Args for `nemo-relay doctor`. `--json` is on this command (rather than as a global flag) /// so it doesn't pollute the help output of subcommands where it has no meaning. #[derive(Debug, Clone, Args)] pub(crate) struct DoctorCommand { @@ -105,7 +105,7 @@ pub(crate) struct DoctorCommand { pub(crate) json: bool, } -/// Args for `nemo-flow agents`. Shares the `--json` shape with `nemo-flow doctor`'s +/// Args for `nemo-relay agents`. Shares the `--json` shape with `nemo-relay doctor`'s /// `agents` field so the two outputs can be unified by downstream consumers. #[derive(Debug, Clone, Args)] pub(crate) struct AgentsCommand { @@ -114,7 +114,7 @@ pub(crate) struct AgentsCommand { pub(crate) json: bool, } -/// Args for `nemo-flow completions ` (print to stdout) or `nemo-flow completions --install` +/// Args for `nemo-relay completions ` (print to stdout) or `nemo-relay completions --install` /// (auto-detect $SHELL and write to the standard fpath / completions directory). /// /// The Homebrew / curl-install flows drop completion scripts automatically; this subcommand is @@ -132,7 +132,7 @@ pub(crate) struct CompletionsCommand { pub(crate) install: bool, } -/// Args for `nemo-flow config`. The setup wizard runs by default; `--reset` short-circuits to +/// Args for `nemo-relay config`. The setup wizard runs by default; `--reset` short-circuits to /// a destructive clear. An optional positional agent name scopes both the wizard and `--reset` /// to a single agent's settings, leaving other agents' blocks untouched. #[derive(Debug, Clone, Args)] @@ -142,13 +142,13 @@ pub(crate) struct ConfigCommand { #[arg(value_enum)] pub(crate) agent: Option, /// Delete the project config file (or remove just the scoped agent's block when an agent - /// is named). The wizard does NOT run after a reset — invoke `nemo-flow config` again to + /// is named). The wizard does NOT run after a reset — invoke `nemo-relay config` again to /// re-create the file from scratch. #[arg(long)] pub(crate) reset: bool, } -/// Args for `nemo-flow plugins`. +/// Args for `nemo-relay plugins`. #[derive(Debug, Clone, Args)] pub(crate) struct PluginsCommand { #[command(subcommand)] @@ -162,7 +162,7 @@ pub(crate) enum PluginsSubcommand { Edit(PluginsEditCommand), } -/// Args for `nemo-flow plugins edit`. +/// Args for `nemo-relay plugins edit`. #[derive(Debug, Clone, Default, Args)] #[command(group( ArgGroup::new("scope") @@ -170,13 +170,13 @@ pub(crate) enum PluginsSubcommand { .multiple(false) ))] pub(crate) struct PluginsEditCommand { - /// Edit the user config at `$XDG_CONFIG_HOME/nemo-flow/plugins.toml`. + /// Edit the user config at `$XDG_CONFIG_HOME/nemo-relay/plugins.toml`. #[arg(long)] pub(crate) user: bool, - /// Edit the nearest project config at `.nemo-flow/plugins.toml`. + /// Edit the nearest project config at `.nemo-relay/plugins.toml`. #[arg(long)] pub(crate) project: bool, - /// Edit the system config at `/etc/nemo-flow/plugins.toml`. + /// Edit the system config at `/etc/nemo-relay/plugins.toml`. #[arg(long)] pub(crate) global: bool, } @@ -187,23 +187,23 @@ pub(crate) struct ServerArgs { #[arg(long)] pub(crate) config: Option, /// Address for the gateway to listen on in daemon mode (default 127.0.0.1:4040) - #[arg(long, env = "NEMO_FLOW_GATEWAY_BIND")] + #[arg(long, env = "NEMO_RELAY_GATEWAY_BIND")] pub(crate) bind: Option, /// Upstream OpenAI-compatible base URL (e.g. https://api.openai.com/v1, NVIDIA inference) - #[arg(long, env = "NEMO_FLOW_OPENAI_BASE_URL")] + #[arg(long, env = "NEMO_RELAY_OPENAI_BASE_URL")] pub(crate) openai_base_url: Option, /// Upstream Anthropic base URL (e.g. https://api.anthropic.com) - #[arg(long, env = "NEMO_FLOW_ANTHROPIC_BASE_URL")] + #[arg(long, env = "NEMO_RELAY_ANTHROPIC_BASE_URL")] pub(crate) anthropic_base_url: Option, /// Generic plugin configuration JSON for process-level gateway plugin activation. - #[arg(long, env = "NEMO_FLOW_PLUGIN_CONFIG")] + #[arg(long, env = "NEMO_RELAY_PLUGIN_CONFIG")] pub(crate) plugin_config: Option, } impl ServerArgs { /// True when the user passed any flag that signals "I want the gateway, not the wizard." Used - /// by the bare `nemo-flow` dispatch to choose between launching the long-running daemon and - /// dropping into setup. `--config` is included: someone running `nemo-flow --config ` + /// by the bare `nemo-relay` dispatch to choose between launching the long-running daemon and + /// dropping into setup. `--config` is included: someone running `nemo-relay --config ` /// with no subcommand has explicitly pointed at a config file, which is only meaningful for /// daemon startup — the wizard creates configs, it doesn't consume them. pub(crate) fn requested_daemon_mode(&self) -> bool { @@ -242,14 +242,14 @@ pub(crate) struct HookForwardCommand { pub(crate) fail_closed: bool, } -/// Args for the easy-path agent shortcut (`nemo-flow claude`, `nemo-flow codex`, etc.). +/// Args for the easy-path agent shortcut (`nemo-relay claude`, `nemo-relay codex`, etc.). /// Holds only pass-through agent args; the agent itself is selected by which subcommand variant /// is invoked, and upstream settings come from the resolved config file. If no config file is /// present, the dispatcher fires setup. #[derive(Debug, Clone, Args)] pub(crate) struct EasyPathCommand { /// Pass-through args forwarded to the underlying agent process. Use `--` to separate them - /// from `nemo-flow`'s own flags. See the `Examples` section below for agent-specific shapes. + /// from `nemo-relay`'s own flags. See the `Examples` section below for agent-specific shapes. #[arg(last = true)] pub(crate) command: Vec, } @@ -311,11 +311,11 @@ impl GatewayConfig { // because install and hook-forward validate generated header values before sending them. pub(crate) fn session_config_from_headers(&self, headers: &HeaderMap) -> SessionConfig { let metadata = - header_json(headers, "x-nemo-flow-session-metadata").or_else(|| self.metadata.clone()); - let plugin_config = header_json(headers, "x-nemo-flow-plugin-config") + header_json(headers, "x-nemo-relay-session-metadata").or_else(|| self.metadata.clone()); + let plugin_config = header_json(headers, "x-nemo-relay-plugin-config") .or_else(|| self.plugin_config.clone()); - let profile = header_string(headers, "x-nemo-flow-config-profile"); - let gateway_mode = header_string(headers, "x-nemo-flow-gateway-mode"); + let profile = header_string(headers, "x-nemo-relay-config-profile"); + let gateway_mode = header_string(headers, "x-nemo-relay-gateway-mode"); SessionConfig { metadata, plugin_config, @@ -342,7 +342,7 @@ pub(crate) struct AgentConfigs { #[derive(Debug, Clone, Default)] pub(crate) struct AgentCommandConfig { pub(crate) command: Option, - /// Recorded by `nemo-flow config` when it installs hermes shell hooks. Other agents leave + /// Recorded by `nemo-relay config` when it installs hermes shell hooks. Other agents leave /// this empty; the launcher reads it only to print a "hooks live here" pointer for hermes. pub(crate) hooks_path: Option, } @@ -544,7 +544,7 @@ fn load_shared_config(explicit: Option<&PathBuf>) -> Result) -> Vec { if let Some(path) = explicit { return vec![path.clone()]; } - let mut paths = vec![PathBuf::from("/etc/nemo-flow/config.toml")]; + let mut paths = vec![PathBuf::from("/etc/nemo-relay/config.toml")]; if let Ok(cwd) = std::env::current_dir() && let Some(project) = find_project_config(&cwd) { @@ -621,7 +621,7 @@ fn implicit_plugin_config_paths( ) -> Vec { // Ordered from lowest to highest precedence. User-level plugin config intentionally loads last // so an operator can override project-local plugin defaults without editing the checkout. - let mut paths = vec![PathBuf::from("/etc/nemo-flow").join(PLUGINS_TOML)]; + let mut paths = vec![PathBuf::from("/etc/nemo-relay").join(PLUGINS_TOML)]; if let Some(cwd) = cwd && let Some(project) = find_project_plugin_config(cwd) { @@ -637,7 +637,7 @@ fn implicit_plugin_config_paths( // The first hit wins so nested projects can override parent workspace defaults. fn find_project_config(start: &std::path::Path) -> Option { for ancestor in start.ancestors() { - let path = ancestor.join(".nemo-flow/config.toml"); + let path = ancestor.join(".nemo-relay/config.toml"); if path.exists() { return Some(path); } @@ -648,7 +648,7 @@ fn find_project_config(start: &std::path::Path) -> Option { // Walks upward from the current directory and returns the nearest project-local plugin config. fn find_project_plugin_config(start: &std::path::Path) -> Option { for ancestor in start.ancestors() { - let path = ancestor.join(".nemo-flow").join(PLUGINS_TOML); + let path = ancestor.join(".nemo-relay").join(PLUGINS_TOML); if path.exists() { return Some(path); } @@ -666,11 +666,11 @@ pub(crate) fn project_plugin_config_path(start: &std::path::Path) -> PathBuf { find_project_config(start) .and_then(|path| path.parent().map(|parent| parent.join(PLUGINS_TOML))) }) - .unwrap_or_else(|| start.join(".nemo-flow").join(PLUGINS_TOML)) + .unwrap_or_else(|| start.join(".nemo-relay").join(PLUGINS_TOML)) } pub(crate) fn global_plugin_config_path() -> PathBuf { - PathBuf::from("/etc/nemo-flow").join(PLUGINS_TOML) + PathBuf::from("/etc/nemo-relay").join(PLUGINS_TOML) } // Resolves the user config using XDG first and HOME/USERPROFILE second. Returning `None` keeps @@ -679,15 +679,15 @@ fn user_config_path() -> Option { user_config_dir().map(|dir| dir.join("config.toml")) } -/// Resolves the nemo-flow user config DIRECTORY (without trailing filename) using the same XDG +/// Resolves the nemo-relay user config DIRECTORY (without trailing filename) using the same XDG /// rules as `user_config_path`. Exposed so wizard/doctor code paths that write to or display /// the global location stay in sync with the loader — without this, hard-coded -/// `$HOME/.config/nemo-flow` references silently ignore `$XDG_CONFIG_HOME`. +/// `$HOME/.config/nemo-relay` references silently ignore `$XDG_CONFIG_HOME`. pub(crate) fn user_config_dir() -> Option { if let Some(base) = std::env::var_os("XDG_CONFIG_HOME") { - return Some(PathBuf::from(base).join("nemo-flow")); + return Some(PathBuf::from(base).join("nemo-relay")); } - home_dir().map(|home| home.join(".config/nemo-flow")) + home_dir().map(|home| home.join(".config/nemo-relay")) } // Applies the typed TOML config model to the resolved runtime config. Missing sections and fields @@ -828,15 +828,15 @@ fn apply_file_agents_config(agents: &mut AgentConfigs, file_agents: Option, ) -> ConfigurationInfo { let workspace_path = cwd - .map(|p| p.join(".nemo-flow").join("config.toml")) - .unwrap_or_else(|| PathBuf::from(".nemo-flow/config.toml")); + .map(|p| p.join(".nemo-relay").join("config.toml")) + .unwrap_or_else(|| PathBuf::from(".nemo-relay/config.toml")); // Use the same XDG-aware resolver the config loader uses, so doctor reports the path the - // runtime would actually read instead of a hard-coded `$HOME/.config/nemo-flow`. + // runtime would actually read instead of a hard-coded `$HOME/.config/nemo-relay`. let global_path = crate::config::user_config_dir() .map(|dir| dir.join("config.toml")) - .or_else(|| home.map(|h| h.join(".config").join("nemo-flow").join("config.toml"))) - .unwrap_or_else(|| PathBuf::from("~/.config/nemo-flow/config.toml")); - let system_path = PathBuf::from("/etc/nemo-flow/config.toml"); + .or_else(|| home.map(|h| h.join(".config").join("nemo-relay").join("config.toml"))) + .unwrap_or_else(|| PathBuf::from("~/.config/nemo-relay/config.toml")); + let system_path = PathBuf::from("/etc/nemo-relay/config.toml"); ConfigurationInfo { workspace: layer_status(&workspace_path), @@ -383,7 +383,7 @@ fn hook_status( ), None if readiness_required => ( Status::Fail, - "hooks: not installed; run `nemo-flow config hermes`".into(), + "hooks: not installed; run `nemo-relay config hermes`".into(), ), None => (Status::Info, "hooks: not configured".into()), }, @@ -415,11 +415,11 @@ fn hook_file_status( ), Ok(_) if readiness_required => ( Status::Fail, - format!("{label}: missing NeMo Flow hook in {}", path.display()), + format!("{label}: missing NeMo Relay hook in {}", path.display()), ), Ok(_) => ( Status::Info, - format!("{label}: no NeMo Flow hook in {}", path.display()), + format!("{label}: no NeMo Relay hook in {}", path.display()), ), Err(error) if error.kind() == std::io::ErrorKind::NotFound && readiness_required => { (Status::Fail, format!("{label}: missing {}", path.display())) @@ -445,12 +445,12 @@ fn cursor_hook_file_status( if readiness_required { return ( Status::Fail, - format!("{label}: missing NeMo Flow hook in {}", path.display()), + format!("{label}: missing NeMo Relay hook in {}", path.display()), ); } return ( Status::Info, - format!("{label}: no NeMo Flow hook in {}", path.display()), + format!("{label}: no NeMo Relay hook in {}", path.display()), ); } @@ -500,7 +500,7 @@ fn cursor_hook_file_status( return ( Status::Fail, format!( - "{label}: Cursor hook file {} has no direct NeMo Flow command entries", + "{label}: Cursor hook file {} has no direct NeMo Relay command entries", path.display() ), ); @@ -807,13 +807,13 @@ fn collect_completions(home: Option<&std::path::Path>) -> Vec { return checks; }; let likely_path = match shell_name.as_str() { - "zsh" => Some(home.join(".zfunc").join("_nemo-flow")), - "bash" => Some(home.join(".bash_completion.d").join("nemo-flow")), + "zsh" => Some(home.join(".zfunc").join("_nemo-relay")), + "bash" => Some(home.join(".bash_completion.d").join("nemo-relay")), "fish" => Some( home.join(".config") .join("fish") .join("completions") - .join("nemo-flow.fish"), + .join("nemo-relay.fish"), ), _ => None, }; @@ -827,14 +827,14 @@ fn collect_completions(home: Option<&std::path::Path>) -> Vec { name: "Completions", status: Status::Info, details: format!( - "{shell_name}: not installed (run `nemo-flow completions {shell_name} > {}`)", + "{shell_name}: not installed (run `nemo-relay completions {shell_name} > {}`)", path.display() ), }), None => checks.push(Check { name: "Completions", status: Status::Info, - details: format!("{shell_name}: no known completion path; run `nemo-flow completions ` to generate"), + details: format!("{shell_name}: no known completion path; run `nemo-relay completions ` to generate"), }), } checks @@ -889,7 +889,7 @@ fn report_has_warn(report: &DoctorReport) -> bool { /// pure formatter stays banner-free for tests. pub(crate) fn format_human(report: &DoctorReport) -> String { let mut out = String::new(); - out.push_str(&format!("\n NeMo Flow {}\n", report.binary_version)); + out.push_str(&format!("\n NeMo Relay {}\n", report.binary_version)); out.push_str(" ─────────────────────────────────────────────\n"); if let Some(agent) = &report.target_agent { out.push_str(&format!(" Target agent {agent}\n\n")); @@ -1051,7 +1051,7 @@ pub(crate) fn format_agents_json(agents: &[AgentInfo]) -> Result, @@ -1072,7 +1072,7 @@ pub(crate) async fn run_doctor( } } -/// Top-level entry point invoked by `nemo-flow agents`. Always exits 0; the data drives caller +/// Top-level entry point invoked by `nemo-relay agents`. Always exits 0; the data drives caller /// decisions (e.g., CI gating on JSON output). pub(crate) async fn run_agents(json: bool) -> Result { let agents = agents_report().await; diff --git a/crates/cli/src/error.rs b/crates/cli/src/error.rs index 7a4752568..fdaa9053e 100644 --- a/crates/cli/src/error.rs +++ b/crates/cli/src/error.rs @@ -4,7 +4,7 @@ use axum::Json; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; -use nemo_flow::error::FlowError; +use nemo_relay::error::FlowError; use serde_json::{Map, Value, json}; #[derive(Debug, thiserror::Error)] @@ -25,10 +25,10 @@ pub(crate) enum CliError { Config(String), #[error("launcher error: {0}")] Launch(String), - #[error("NeMo Flow runtime error: {0}")] - Flow(#[from] nemo_flow::error::FlowError), + #[error("NeMo Relay runtime error: {0}")] + Flow(#[from] nemo_relay::error::FlowError), #[error("openinference error: {0}")] - OpenInference(#[from] nemo_flow::observability::openinference::OpenInferenceError), + OpenInference(#[from] nemo_relay::observability::openinference::OpenInferenceError), } impl CliError { @@ -65,9 +65,9 @@ impl IntoResponse for CliError { (false, _) => StatusCode::INTERNAL_SERVER_ERROR, }; let error_type = if guardrail_reason.is_some() { - "nemo_flow_guardrail_rejected" + "nemo_relay_guardrail_rejected" } else { - "nemo_flow_gateway_error" + "nemo_relay_gateway_error" }; let mut error = Map::from_iter([ ("message".to_string(), json!(message)), diff --git a/crates/cli/src/gateway.rs b/crates/cli/src/gateway.rs index 91df81796..56154ad85 100644 --- a/crates/cli/src/gateway.rs +++ b/crates/cli/src/gateway.rs @@ -8,19 +8,19 @@ use axum::body::{Body, Bytes}; use axum::extract::State; use axum::http::{HeaderMap, HeaderName, HeaderValue, Method, Request, Response, StatusCode}; use futures_util::StreamExt; -use nemo_flow::api::llm::{ +use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmRequest, LlmStreamCallExecuteParams, llm_call_execute, llm_stream_call_execute, }; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ LlmExecutionNextFn, LlmJsonStream, LlmStreamExecutionNextFn, TASK_SCOPE_STACK, }; -use nemo_flow::codec::anthropic::{AnthropicMessagesCodec, AnthropicMessagesStreamingCodec}; -use nemo_flow::codec::openai_chat::{OpenAIChatCodec, OpenAIChatStreamingCodec}; -use nemo_flow::codec::openai_responses::{OpenAIResponsesCodec, OpenAIResponsesStreamingCodec}; -use nemo_flow::codec::streaming::StreamingCodec; -use nemo_flow::codec::traits::LlmResponseCodec; -use nemo_flow::error::FlowError; +use nemo_relay::codec::anthropic::{AnthropicMessagesCodec, AnthropicMessagesStreamingCodec}; +use nemo_relay::codec::openai_chat::{OpenAIChatCodec, OpenAIChatStreamingCodec}; +use nemo_relay::codec::openai_responses::{OpenAIResponsesCodec, OpenAIResponsesStreamingCodec}; +use nemo_relay::codec::streaming::StreamingCodec; +use nemo_relay::codec::traits::LlmResponseCodec; +use nemo_relay::error::FlowError; use serde_json::{Map, Value, json}; use crate::alignment::{self, GatewayRouteKind}; @@ -31,7 +31,7 @@ use crate::session::{GatewayCallPrep, LlmGatewayStart, SessionManager}; const MAX_BODY_BYTES: usize = 100 * 1024 * 1024; -/// Proxies supported LLM API requests through NeMo Flow's managed execution pipeline. +/// Proxies supported LLM API requests through NeMo Relay's managed execution pipeline. /// /// The gateway buffers the inbound body once, opens a managed LLM call against the resolved /// session, and lets the runtime own the start/end events. Provider routes that have a built-in @@ -68,7 +68,7 @@ struct PreparedGatewayRequest { } // Validates the gateway route, buffers the request body exactly once, and derives the metadata used -// for both upstream forwarding and NeMo Flow LLM start events. Provider JSON parse failures are not +// for both upstream forwarding and NeMo Relay LLM start events. Provider JSON parse failures are not // request failures because the gateway still forwards raw bytes unchanged. async fn prepare_gateway_request( config: &crate::config::GatewayConfig, @@ -111,7 +111,7 @@ async fn prepare_gateway_request( // because the later runtime-managed LLM call only sees this normalized start payload. fn build_llm_gateway_start(request: &PreparedGatewayRequest) -> LlmGatewayStart { LlmGatewayStart { - // Explicit NeMo Flow headers still win, but alignment can recover agent-native session + // Explicit NeMo Relay headers still win, but alignment can recover agent-native session // signals when available. Applies to Claude Code's session header and Codex's Responses // prompt-cache thread id today. session_id: gateway_session_id(&request.headers, &request.request_json, request.provider), @@ -128,7 +128,7 @@ fn build_llm_gateway_start(request: &PreparedGatewayRequest) -> LlmGatewayStart conversation_id: gateway_identifier( &request.headers, &request.request_json, - "x-nemo-flow-conversation-id", + "x-nemo-relay-conversation-id", &[ &["conversation_id"], &["conversationId"], @@ -138,13 +138,13 @@ fn build_llm_gateway_start(request: &PreparedGatewayRequest) -> LlmGatewayStart generation_id: gateway_identifier( &request.headers, &request.request_json, - "x-nemo-flow-generation-id", + "x-nemo-relay-generation-id", &[&["generation_id"], &["generationId"], &["generation", "id"]], ), request_id: gateway_identifier( &request.headers, &request.request_json, - "x-nemo-flow-request-id", + "x-nemo-relay-request-id", &[ &["request_id"], &["requestId"], @@ -503,7 +503,7 @@ fn build_streaming_func( // shared `SseEventDecoder`. Trailing partial frames are surfaced to the runtime so the collector // observes whatever the upstream sent before disconnect. fn sse_json_stream(response: reqwest::Response) -> LlmJsonStream { - use nemo_flow::codec::streaming::SseEventDecoder; + use nemo_relay::codec::streaming::SseEventDecoder; let mut decoder = SseEventDecoder::new(); let mut bytes = response.bytes_stream(); let stream = stream! { @@ -702,7 +702,7 @@ fn effective_upstream_request( Ok(serialized) => Bytes::from(serialized), Err(error) => { eprintln!( - "nemo-flow CLI gateway: failed to serialize rewritten LLM request body; forwarding original request: {error}" + "nemo-relay CLI gateway: failed to serialize rewritten LLM request body; forwarding original request: {error}" ); return (body_bytes.clone(), headers.clone()); } diff --git a/crates/cli/src/installer.rs b/crates/cli/src/installer.rs index 9aec733c0..9cdf98b09 100644 --- a/crates/cli/src/installer.rs +++ b/crates/cli/src/installer.rs @@ -104,14 +104,14 @@ fn hook_forward_url(command: &HookForwardCommand) -> Result, CliE let Some(gateway_url) = resolve_hook_gateway_url( command.agent, command.gateway_url.clone(), - std::env::var("NEMO_FLOW_GATEWAY_URL").ok(), + std::env::var("NEMO_RELAY_GATEWAY_URL").ok(), ) else { eprintln!( - "nemo-flow hook forward failed: missing gateway URL; pass --gateway-url or set NEMO_FLOW_GATEWAY_URL" + "nemo-relay hook forward failed: missing gateway URL; pass --gateway-url or set NEMO_RELAY_GATEWAY_URL" ); if command.fail_closed { return Err(CliError::Install( - "missing gateway URL; pass --gateway-url or set NEMO_FLOW_GATEWAY_URL".into(), + "missing gateway URL; pass --gateway-url or set NEMO_RELAY_GATEWAY_URL".into(), )); } return Ok(None); @@ -161,7 +161,7 @@ async fn handle_hook_forward_response( if let Some(reason) = guardrail_rejection_reason(&body) { return Err(CliError::GuardrailRejected(reason)); } - eprintln!("nemo-flow hook forward failed with HTTP {status}"); + eprintln!("nemo-relay hook forward failed with HTTP {status}"); if fail_closed { return Err(CliError::Install(format!( "hook forward failed with HTTP {status}" @@ -175,7 +175,7 @@ async fn handle_hook_forward_response( Ok(()) } Err(error) => { - eprintln!("nemo-flow hook forward failed: {error}"); + eprintln!("nemo-relay hook forward failed: {error}"); if fail_closed { Err(CliError::Upstream(error)) } else { @@ -188,7 +188,7 @@ async fn handle_hook_forward_response( fn guardrail_rejection_reason(body: &str) -> Option { let value: Value = serde_json::from_str(body).ok()?; let error = value.get("error")?; - (error.get("type").and_then(Value::as_str) == Some("nemo_flow_guardrail_rejected")) + (error.get("type").and_then(Value::as_str) == Some("nemo_relay_guardrail_rejected")) .then(|| { error .get("reason") @@ -200,7 +200,7 @@ fn guardrail_rejection_reason(body: &str) -> Option { } // Chooses the gateway URL for hook-forward. Hermes prefers the runtime environment URL because -// its hooks are installed persistently by setup but reused under `nemo-flow hermes` with an +// its hooks are installed persistently by setup but reused under `nemo-relay hermes` with an // ephemeral gateway; other agents prefer the installed command URL for stable configuration. fn resolve_hook_gateway_url( agent: CodingAgent, @@ -231,7 +231,7 @@ pub(crate) fn generated_hooks(agent: CodingAgent, command: &str) -> Value { // path of the currently running gateway binary so spawned hook subprocesses do not depend on the // user's `PATH` (which Codex/Claude/Cursor inherit but which typically does not include // `target/debug` or other dev locations); persistent-install callers can pass the bare name -// `"nemo-flow"` because the user is expected to have the binary on `PATH` after install. +// `"nemo-relay"` because the user is expected to have the binary on `PATH` after install. pub(crate) fn hook_forward_command(executable: &str, agent: CodingAgent) -> String { format!("{executable} hook-forward {}", agent.as_arg()) } @@ -439,16 +439,16 @@ fn gateway_headers( gateway_mode: Option, ) -> Result { let mut headers = HeaderMap::new(); - insert_header(&mut headers, "x-nemo-flow-config-profile", profile)?; + insert_header(&mut headers, "x-nemo-relay-config-profile", profile)?; insert_header( &mut headers, - "x-nemo-flow-session-metadata", + "x-nemo-relay-session-metadata", session_metadata, )?; - insert_header(&mut headers, "x-nemo-flow-plugin-config", plugin_config)?; + insert_header(&mut headers, "x-nemo-relay-plugin-config", plugin_config)?; insert_header( &mut headers, - "x-nemo-flow-gateway-mode", + "x-nemo-relay-gateway-mode", gateway_mode.map(GatewayMode::as_arg), )?; Ok(headers) diff --git a/crates/cli/src/launcher.rs b/crates/cli/src/launcher.rs index 065ff0ffb..b9b3048ce 100644 --- a/crates/cli/src/launcher.rs +++ b/crates/cli/src/launcher.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use std::process::ExitCode; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use nemo_flow::observability::plugin_component::{OBSERVABILITY_PLUGIN_KIND, ObservabilityConfig}; -use nemo_flow::plugin::PluginConfig; +use nemo_relay::observability::plugin_component::{OBSERVABILITY_PLUGIN_KIND, ObservabilityConfig}; +use nemo_relay::plugin::PluginConfig; use reqwest::Client; use serde_json::{Value, json}; use tokio::net::TcpListener; @@ -37,12 +37,12 @@ pub(crate) async fn run( run.execute().await } -/// Runs the easy-path bare-agent shortcut (`nemo-flow claude`, `nemo-flow codex`, etc.). +/// Runs the easy-path bare-agent shortcut (`nemo-relay claude`, `nemo-relay codex`, etc.). /// /// If no config file is present at any discovery layer, this fires the interactive setup inline /// (`crate::setup::run`) which writes a `config.toml`, then proceeds to launch the agent. When /// config IS present, the easy path constructs a synthetic `RunCommand` and delegates to the -/// same transparent-run pipeline `nemo-flow run` uses — same observability wiring, same agent +/// same transparent-run pipeline `nemo-relay run` uses — same observability wiring, same agent /// argv resolution, same lifecycle management. pub(crate) async fn easy_path( agent: CodingAgent, @@ -179,7 +179,7 @@ fn resolve_agent_and_argv( // Resolves the full argv to spawn. When `--agent` is set (the easy-path and explicit `--agent` // flows both go through this case), the configured agent command is the base argv and anything // after `--` is appended as pass-through args. When `--agent` is absent, `command.command` IS -// the full argv (e.g., `nemo-flow run -- codex --model X` runs that exact command and infers +// the full argv (e.g., `nemo-relay run -- codex --model X` runs that exact command and infers // the agent from argv[0]). fn resolved_argv(command: &RunCommand, agents: &AgentConfigs) -> Result, CliError> { if let Some(agent) = command.agent { @@ -288,7 +288,7 @@ impl PreparedRun { ) -> Result { let mut run = Self { argv, - env: vec![("NEMO_FLOW_GATEWAY_URL".into(), gateway_url.into())], + env: vec![("NEMO_RELAY_GATEWAY_URL".into(), gateway_url.into())], temp_dirs: Vec::new(), cursor_restore: None, notes: Vec::new(), @@ -339,15 +339,15 @@ impl PreparedRun { // Creates a temporary Claude Code plugin containing gateway hooks and points Claude at both // that plugin directory and the gateway Anthropic-compatible gateway URL. fn prepare_claude(&mut self, gateway_url: &str) -> Result<(), CliError> { - let root = temp_dir("nemo-flow-claude-plugin")?; + let root = temp_dir("nemo-relay-claude-plugin")?; std::fs::create_dir_all(root.join(".claude-plugin"))?; std::fs::create_dir_all(root.join("hooks"))?; std::fs::write( root.join(".claude-plugin/plugin.json"), serde_json::to_vec_pretty(&json!({ - "name": "nemo-flow-cli", + "name": "nemo-relay-cli", "version": env!("CARGO_PKG_VERSION"), - "description": "Temporary NeMo Flow gateway hooks" + "description": "Temporary NeMo Relay gateway hooks" })) .map_err(|error| CliError::Launch(error.to_string()))?, )?; @@ -406,7 +406,7 @@ impl PreparedRun { "--config".to_string(), "features.hooks=true".to_string(), "--config".to_string(), - "model_provider=\"nemo-flow-openai\"".to_string(), + "model_provider=\"nemo-relay-openai\"".to_string(), "--config".to_string(), codex_gateway_provider_config(gateway_url), ]; @@ -441,22 +441,22 @@ impl PreparedRun { fn prepare_cursor_dry(&mut self) -> Result<(), CliError> { let path = cursor_hooks_path()?; self.notes.push(format!( - "would temporarily merge NeMo Flow hooks into {}", + "would temporarily merge NeMo Relay hooks into {}", path.display() )); Ok(()) } - // Surfaces where hermes' shell hooks live so users know what `nemo-flow config hermes` wrote. + // Surfaces where hermes' shell hooks live so users know what `nemo-relay config hermes` wrote. // Hermes reads hooks from .hermes/config.yaml on its own; this launcher only exports the live - // gateway URL via NEMO_FLOW_GATEWAY_URL so installed hooks reach the ephemeral gateway. + // gateway URL via NEMO_RELAY_GATEWAY_URL so installed hooks reach the ephemeral gateway. fn prepare_hermes(&mut self, hooks_path: Option<&std::path::Path>) { let note = match hooks_path { Some(path) => format!( - "Hermes hooks at {} — re-run `nemo-flow config hermes` to refresh.", + "Hermes hooks at {} — re-run `nemo-relay config hermes` to refresh.", path.display() ), - None => "Hermes hooks not yet installed — run `nemo-flow config hermes` once so hermes traces under this gateway.".into(), + None => "Hermes hooks not yet installed — run `nemo-relay config hermes` once so hermes traces under this gateway.".into(), }; self.notes.push(note); } @@ -520,7 +520,7 @@ impl PreparedRun { } let mut lines: Vec = Vec::new(); - lines.push(format!("NeMo Flow → {}", agent.as_arg())); + lines.push(format!("NeMo Relay → {}", agent.as_arg())); lines.push(format!(" Gateway {gateway_url}")); let destinations = exporter_destinations(&resolved.gateway); if destinations.is_empty() { @@ -634,7 +634,7 @@ fn observability_exporter_destinations(config: &ObservabilityConfig) -> Vec.jsonl".into()), + .unwrap_or_else(|| "nemo-relay-events-.jsonl".into()), ); destinations.push(format!("ATOF {}", path.display())); } @@ -724,7 +724,7 @@ fn codex_gateway_provider_config(gateway_url: &str) -> String { // environment the JWT is replaced (see `gateway.rs::strip_chatgpt_oauth_for_openai_route` // and `inject_provider_auth`); otherwise the JWT is forwarded to the ChatGPT backend. format!( - "model_providers.nemo-flow-openai={{name=\"NeMo Flow OpenAI\",base_url={},wire_api=\"responses\",requires_openai_auth=true,supports_websockets=false}}", + "model_providers.nemo-relay-openai={{name=\"NeMo Relay OpenAI\",base_url={},wire_api=\"responses\",requires_openai_auth=true,supports_websockets=false}}", toml_string(gateway_url) ) } @@ -751,12 +751,12 @@ fn transparent_hook_executable() -> String { std::env::current_exe() .ok() .and_then(|path| path.to_str().map(str::to_owned)) - .unwrap_or_else(|| "nemo-flow".to_string()) + .unwrap_or_else(|| "nemo-relay".to_string()) } // Appends the running gateway binary's directory to the child agent PATH. Transparent hooks use // the absolute executable path when possible, but adding the directory also covers hook loaders or -// user-managed hook commands that resolve `nemo-flow` through PATH inside the launched agent. Keep +// user-managed hook commands that resolve `nemo-relay` through PATH inside the launched agent. Keep // user PATH precedence intact so normal agent tool resolution does not change. fn path_with_transparent_hook_dir() -> Option { let dir = std::env::current_exe() @@ -810,7 +810,7 @@ fn backup_existing_cursor_hooks(path: &Path) -> Result<(bool, Option), if !had_original { return Ok((false, None)); } - let backup = path.with_extension(format!("json.nemo-flow-run.bak.{}", timestamp()?)); + let backup = path.with_extension(format!("json.nemo-relay-run.bak.{}", timestamp()?)); std::fs::copy(path, &backup)?; Ok((true, Some(backup))) } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 82d260ccc..91a2eaa3a 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! NeMo Flow coding-agent gateway CLI. +//! NeMo Relay coding-agent gateway CLI. mod adapters; mod alignment; @@ -99,21 +99,21 @@ async fn run() -> Result { clap_complete::generate( shell, &mut clap_command, - "nemo-flow", + "nemo-relay", &mut std::io::stdout(), ); } Ok(ExitCode::SUCCESS) } None => { - // Bare `nemo-flow` with no subcommand: + // Bare `nemo-relay` with no subcommand: // - If the user passed any daemon-specific flag (`--bind`, upstream URLs, ATIF dir, // OpenInference endpoint), they obviously want the long-running gateway daemon — // keep that path so existing scripts that explicitly invoke daemon mode stay // compatible. // - Otherwise — no flags, no subcommand — use the first-run path only when no config - // exists. Once configured, bare `nemo-flow` becomes a quick health check; explicit - // `nemo-flow config` remains the reconfiguration path. + // exists. Once configured, bare `nemo-relay` becomes a quick health check; explicit + // `nemo-relay config` remains the reconfiguration path. if cli.server.requested_daemon_mode() { let config = config::resolve_server_config(&cli.server)?; server::serve(config.gateway).await?; diff --git a/crates/cli/src/plugins.rs b/crates/cli/src/plugins.rs index 9b2f69e9a..f732e2039 100644 --- a/crates/cli/src/plugins.rs +++ b/crates/cli/src/plugins.rs @@ -13,9 +13,9 @@ use std::path::Path; use console::{Key, Term, style}; use dialoguer::theme::ColorfulTheme; use dialoguer::{Input, Select}; -use nemo_flow::config_editor::{EditorConfig, EditorFieldKind, EditorFieldSpec}; -use nemo_flow::observability::plugin_component::ObservabilityConfig; -use nemo_flow_adaptive::AdaptiveConfig; +use nemo_relay::config_editor::{EditorConfig, EditorFieldKind, EditorFieldSpec}; +use nemo_relay::observability::plugin_component::ObservabilityConfig; +use nemo_relay_adaptive::AdaptiveConfig; use serde_json::{Value, json}; use crate::config::PluginsEditCommand; @@ -733,7 +733,7 @@ fn edit_value_section( theme: &ColorfulTheme, prompt: &str, value: &mut Value, - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, default: Option, ) -> Result { ensure_object(value); @@ -776,7 +776,7 @@ fn edit_value_section( fn value_section_menu_items( value: &Value, - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, default: Option<&Value>, ) -> Result, CliError> { let mut items = schema @@ -813,7 +813,7 @@ fn edit_selected_value_item( theme: &ColorfulTheme, prompt: &str, value: &mut Value, - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, default: Option<&Value>, selection: usize, ) -> Result { @@ -903,7 +903,7 @@ fn edit_value_field( fn reset_value_section_item( value: &mut Value, - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, default: Option<&Value>, selected: usize, ) { @@ -917,7 +917,7 @@ fn reset_value_section_item( fn clear_value_field( value: &mut Value, - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, selected: usize, ) -> bool { let Some(field) = schema.fields.get(selected) else { diff --git a/crates/cli/src/plugins/config_io.rs b/crates/cli/src/plugins/config_io.rs index a759dde78..c256dc8a0 100644 --- a/crates/cli/src/plugins/config_io.rs +++ b/crates/cli/src/plugins/config_io.rs @@ -6,8 +6,8 @@ use std::path::{Path, PathBuf}; use console::style; -use nemo_flow::plugin::{ConfigPolicy, PluginConfig, validate_plugin_config}; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay::plugin::{ConfigPolicy, PluginConfig, validate_plugin_config}; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use serde_json::{Map, Value}; use crate::config::{ @@ -124,7 +124,7 @@ pub(super) fn validate_config(config: &PluginConfig) -> Result<(), CliError> { let messages = report .diagnostics .into_iter() - .filter(|diagnostic| diagnostic.level == nemo_flow::plugin::DiagnosticLevel::Error) + .filter(|diagnostic| diagnostic.level == nemo_relay::plugin::DiagnosticLevel::Error) .map(|diagnostic| diagnostic.message) .collect::>() .join("; "); diff --git a/crates/cli/src/plugins/editor_model.rs b/crates/cli/src/plugins/editor_model.rs index 7ad4a593c..628601dac 100644 --- a/crates/cli/src/plugins/editor_model.rs +++ b/crates/cli/src/plugins/editor_model.rs @@ -3,11 +3,11 @@ //! Testable plugin editor state helpers. -use nemo_flow::config_editor::{EditorConfig, EditorFieldKind, EditorFieldSpec}; -use nemo_flow::observability::plugin_component::{OBSERVABILITY_PLUGIN_KIND, ObservabilityConfig}; -use nemo_flow::plugin::{PluginComponentSpec, PluginConfig}; -use nemo_flow_adaptive::AdaptiveConfig; -use nemo_flow_adaptive::plugin_component::ADAPTIVE_PLUGIN_KIND; +use nemo_relay::config_editor::{EditorConfig, EditorFieldKind, EditorFieldSpec}; +use nemo_relay::observability::plugin_component::{OBSERVABILITY_PLUGIN_KIND, ObservabilityConfig}; +use nemo_relay::plugin::{PluginComponentSpec, PluginConfig}; +use nemo_relay_adaptive::AdaptiveConfig; +use nemo_relay_adaptive::plugin_component::ADAPTIVE_PLUGIN_KIND; use serde::Serialize; use serde::de::DeserializeOwned; use serde_json::{Map, Value, json}; @@ -480,7 +480,7 @@ pub(super) fn merge_known_editor_object( existing: &mut Map, edited: Map, known_keys: &[&str], - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, ) { for key in known_keys { let Some(edited_value) = edited.get(*key) else { @@ -519,7 +519,7 @@ pub(super) fn observability_editor_fields_with_version() -> Vec<&'static str> { } pub(super) fn nested_editor_keys( - schema: &nemo_flow::config_editor::EditorSchema, + schema: &nemo_relay::config_editor::EditorSchema, ) -> Vec<&'static str> { schema.fields.iter().map(|field| field.name).collect() } diff --git a/crates/cli/src/server.rs b/crates/cli/src/server.rs index 11b77064d..fef92e1d1 100644 --- a/crates/cli/src/server.rs +++ b/crates/cli/src/server.rs @@ -7,8 +7,8 @@ use axum::extract::State; use axum::http::HeaderMap; use axum::routing::{get, post}; use axum::{Json, Router}; -use nemo_flow::plugin::{PluginConfig, clear_plugin_configuration, initialize_plugins}; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay::plugin::{PluginConfig, clear_plugin_configuration, initialize_plugins}; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use reqwest::Client; use serde_json::Value; use tokio::net::TcpListener; @@ -43,11 +43,11 @@ pub(crate) async fn serve(config: GatewayConfig) -> Result<(), CliError> { if err.kind() == std::io::ErrorKind::AddrInUse { CliError::Launch(format!( "cannot bind {} — port is already in use. Most likely cause: another \ - `nemo-flow` daemon is already running. Fix one of:\n \ - • stop the running daemon (Unix: `pkill -f nemo-flow`, Windows: \ - `taskkill /IM nemo-flow.exe`)\n \ - • use an ephemeral port: `nemo-flow --bind 127.0.0.1:0`\n \ - • pick a free port: `nemo-flow --bind 127.0.0.1:4041`", + `nemo-relay` daemon is already running. Fix one of:\n \ + • stop the running daemon (Unix: `pkill -f nemo-relay`, Windows: \ + `taskkill /IM nemo-relay.exe`)\n \ + • use an ephemeral port: `nemo-relay --bind 127.0.0.1:0`\n \ + • pick a free port: `nemo-relay --bind 127.0.0.1:4041`", config.bind )) } else { diff --git a/crates/cli/src/session.rs b/crates/cli/src/session.rs index 4cc18fa36..6cbb56197 100644 --- a/crates/cli/src/session.rs +++ b/crates/cli/src/session.rs @@ -6,17 +6,17 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use axum::http::HeaderMap; -use nemo_flow::api::llm::{ +use nemo_relay::api::llm::{ LlmAttributes, LlmCallEndParams, LlmCallParams, LlmHandle, LlmRequest, llm_call, llm_call_end, }; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ ScopeStackHandle, TASK_SCOPE_STACK, create_scope_stack, task_scope_push, }; -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeHandle, ScopeType, event as emit_mark_event, get_handle, pop_scope, push_scope, }; -use nemo_flow::api::tool::{ +use nemo_relay::api::tool::{ ToolCallEndParams, ToolCallParams, ToolHandle, tool_call, tool_call_end, tool_conditional_execution, }; @@ -238,7 +238,7 @@ impl SessionManager { ) .await { - eprintln!("nemo-flow CLI gateway: idle session teardown failed: {error}"); + eprintln!("nemo-relay CLI gateway: idle session teardown failed: {error}"); } } }); @@ -966,7 +966,7 @@ impl Session { let _root = get_handle()?; let metadata = merge_metadata( self.scope_metadata(event_metadata), - json!({ "nemo_flow_scope_role": "session" }), + json!({ "nemo_relay_scope_role": "session" }), ); let scope = push_scope( PushScopeParams::builder() @@ -1014,7 +1014,7 @@ impl Session { let metadata = merge_metadata( self.scope_metadata(event_metadata), json!({ - "nemo_flow_scope_role": "turn", + "nemo_relay_scope_role": "turn", "turn_index": self.turn_index, "turn_source": turn_source, }), @@ -1221,7 +1221,7 @@ impl Session { let subagent_name = format!("subagent:{subagent_id}"); let metadata = merge_metadata( event.metadata, - json!({ "nemo_flow_scope_role": "subagent" }), + json!({ "nemo_relay_scope_role": "subagent" }), ); let subagent_stack = create_scope_stack(); let scope = TASK_SCOPE_STACK @@ -1263,7 +1263,7 @@ impl Session { self.ensure_turn_started(event.metadata.clone())?; if !self.subagents.contains_key(&event.subagent_id) { eprintln!( - "nemo-flow CLI gateway: received {} for subagent {} without a matching start", + "nemo-relay CLI gateway: received {} for subagent {} without a matching start", event.event_name, event.subagent_id ); return self.mark( diff --git a/crates/cli/src/setup.rs b/crates/cli/src/setup.rs index 2d127c298..3fad3662c 100644 --- a/crates/cli/src/setup.rs +++ b/crates/cli/src/setup.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! First-run setup for `nemo-flow` configuration. +//! First-run setup for `nemo-relay` configuration. //! //! Drives the required scope and agent prompts, then writes a `config.toml` to the chosen scope. Pure //! helpers (`detect_installed_agents`, `build_config`, `save_config`) are split out from the @@ -38,8 +38,8 @@ use self::model::detect_installed_agents_in; /// /// When `agent_hint` is `Some`, the agent multi-select is skipped — the user already declared -/// intent by typing `nemo-flow claude` (or another agent name), so respect that and only ask -/// scope and agents. To set up multiple agents, the user re-runs `nemo-flow config` later. +/// intent by typing `nemo-relay claude` (or another agent name), so respect that and only ask +/// scope and agents. To set up multiple agents, the user re-runs `nemo-relay config` later. pub(crate) fn prompt_user( detected_agents: &[CodingAgent], agent_hint: Option, @@ -51,16 +51,16 @@ pub(crate) fn prompt_user( Some(agent) => { let (name, _) = agent_key_and_command(agent); println!(" Setting up {name}."); - println!(" Re-run `nemo-flow config` later to configure additional agents."); + println!(" Re-run `nemo-relay config` later to configure additional agents."); } None => { println!(" Let's set up your coding agent."); - println!(" This runs once. Re-run later with `nemo-flow config`."); + println!(" This runs once. Re-run later with `nemo-relay config`."); } } - // Only print the detected-agents listing for the unscoped wizard (`nemo-flow config`), + // Only print the detected-agents listing for the unscoped wizard (`nemo-relay config`), // where the user is about to pick from the multi-select. When the agent was already chosen - // via the easy-path shortcut (`nemo-flow codex`), listing the other three agents is noise. + // via the easy-path shortcut (`nemo-relay codex`), listing the other three agents is noise. if agent_hint.is_none() { println!(); print_detected_agents(detected_agents); @@ -95,12 +95,12 @@ pub(crate) fn prompt_user( }) } -/// Top-level setup entry point used by `nemo-flow config` and the easy-path fallback. +/// Top-level setup entry point used by `nemo-relay config` and the easy-path fallback. /// Detects agents, prompts the user, writes the config, prints a final summary. /// -/// `agent_hint` carries the agent the user typed on the easy path (`nemo-flow claude`); when +/// `agent_hint` carries the agent the user typed on the easy path (`nemo-relay claude`); when /// `Some`, the agent multi-select is skipped because intent is already declared. `None` from -/// `nemo-flow config` asks the full set so users can configure multiple agents at once. +/// `nemo-relay config` asks the full set so users can configure multiple agents at once. pub(crate) async fn run(agent_hint: Option) -> Result<(), CliError> { let detected = detect_installed_agents(); let mut answers = prompt_user(&detected, agent_hint)?; @@ -133,7 +133,7 @@ pub(crate) async fn run(agent_hint: Option) -> Result<(), CliError> for path in &written { println!(" {}", path.display()); } - println!(" Configure plugins with `nemo-flow plugins edit`."); + println!(" Configure plugins with `nemo-relay plugins edit`."); println!(); Ok(()) } @@ -158,7 +158,7 @@ fn ensure_tty() -> Result<(), CliError> { if !std::io::stdin().is_terminal() { return Err(CliError::Config( "interactive setup requires a TTY; pass `--config ` or set up \ - `.nemo-flow/config.toml` manually" + `.nemo-relay/config.toml` manually" .into(), )); } diff --git a/crates/cli/src/setup/model.rs b/crates/cli/src/setup/model.rs index 0fed32280..108afd0a6 100644 --- a/crates/cli/src/setup/model.rs +++ b/crates/cli/src/setup/model.rs @@ -14,9 +14,9 @@ use crate::installer::{hermes_hooks, hook_forward_command, merge_hermes_config}; /// Where the setup saves its output. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum ConfigScope { - /// `./.nemo-flow/config.toml` (walked-up workspace dir). + /// `./.nemo-relay/config.toml` (walked-up workspace dir). Project, - /// `~/.config/nemo-flow/config.toml` (or `$XDG_CONFIG_HOME/nemo-flow/config.toml`). + /// `~/.config/nemo-relay/config.toml` (or `$XDG_CONFIG_HOME/nemo-relay/config.toml`). Global, /// Both project and global; project takes precedence per merge order. Both, @@ -25,8 +25,8 @@ pub(crate) enum ConfigScope { impl ConfigScope { pub(super) fn label(self) -> &'static str { match self { - Self::Project => "project ./.nemo-flow/config.toml (recommended)", - Self::Global => "global ~/.config/nemo-flow/config.toml", + Self::Project => "project ./.nemo-relay/config.toml (recommended)", + Self::Global => "global ~/.config/nemo-relay/config.toml", Self::Both => "both project overrides global", } } @@ -129,7 +129,7 @@ pub(crate) fn save_config( ) -> Result, CliError> { let mut written = Vec::new(); if matches!(scope, ConfigScope::Project | ConfigScope::Both) { - let project_dir = cwd.join(".nemo-flow"); + let project_dir = cwd.join(".nemo-relay"); std::fs::create_dir_all(&project_dir)?; let path = project_dir.join("config.toml"); write_or_merge(&path, doc, merge_scope)?; @@ -145,14 +145,14 @@ pub(crate) fn save_config( Ok(written) } -// Resolves the global nemo-flow config directory. Prefers `$XDG_CONFIG_HOME/nemo-flow` (matches -// `config::user_config_dir`), falling back to `/.config/nemo-flow`. Tests that pass a +// Resolves the global nemo-relay config directory. Prefers `$XDG_CONFIG_HOME/nemo-relay` (matches +// `config::user_config_dir`), falling back to `/.config/nemo-relay`. Tests that pass a // tempdir for `home` get hermetic paths unless they set XDG_CONFIG_HOME explicitly. pub(super) fn global_config_dir(home: &Path) -> PathBuf { if let Some(base) = std::env::var_os("XDG_CONFIG_HOME") { - return PathBuf::from(base).join("nemo-flow"); + return PathBuf::from(base).join("nemo-relay"); } - home.join(".config").join("nemo-flow") + home.join(".config").join("nemo-relay") } // Writes the wizard-built `doc` to `path`. When `merge_scope` is `Some(agent)` and the file @@ -225,7 +225,7 @@ pub(super) fn merge_agents_entry(dst: &mut DocumentMut, src: &DocumentMut, agent /// editing because they typically aren't owned by the wizard. pub(crate) fn reset(agent_hint: Option) -> Result<(), CliError> { let cwd = std::env::current_dir()?; - let path = cwd.join(".nemo-flow").join("config.toml"); + let path = cwd.join(".nemo-relay").join("config.toml"); if !path.exists() { println!(" No project config to reset at {}", path.display()); return Ok(()); @@ -234,7 +234,7 @@ pub(crate) fn reset(agent_hint: Option) -> Result<(), CliError> { None => { std::fs::remove_file(&path)?; println!(" ✓ Removed {}", path.display()); - println!(" Run `nemo-flow config` to set up again."); + println!(" Run `nemo-relay config` to set up again."); } Some(agent) => { let agent_key = agent_key_and_command(agent).0; @@ -289,7 +289,7 @@ pub(crate) fn hermes_hooks_path_for_scope( } /// Writes/merges `.hermes/config.yaml` hook config for every scope-applicable location so hermes -/// fires `nemo-flow hook-forward hermes` on every hook event after setup. Idempotent: existing +/// fires `nemo-relay hook-forward hermes` on every hook event after setup. Idempotent: existing /// hook entries are preserved and our generated groups are appended only when missing. /// /// Returns the list of paths actually written so callers can surface them to the user. @@ -298,7 +298,7 @@ pub(crate) fn install_hermes_hooks( cwd: &Path, home: &Path, ) -> Result, CliError> { - let generated = hermes_hooks(&hook_forward_command("nemo-flow", CodingAgent::Hermes)); + let generated = hermes_hooks(&hook_forward_command("nemo-relay", CodingAgent::Hermes)); let mut written = Vec::new(); for path in hermes_hook_targets(scope, cwd, home) { let existing = match std::fs::read_to_string(&path) { @@ -348,7 +348,7 @@ pub(super) fn read_existing_defaults() -> Option { let cwd = std::env::current_dir().ok()?; let home = home_dir(); - let workspace_path = cwd.join(".nemo-flow").join("config.toml"); + let workspace_path = cwd.join(".nemo-relay").join("config.toml"); let global_path = home .as_ref() .map(|h| global_config_dir(h).join("config.toml")); @@ -410,7 +410,7 @@ pub(super) fn agent_key_and_command(agent: CodingAgent) -> (&'static str, &'stat pub(super) fn preview_paths(scope: ConfigScope, cwd: &Path, home: &Path) -> Vec { let mut paths = Vec::new(); if matches!(scope, ConfigScope::Project | ConfigScope::Both) { - paths.push(cwd.join(".nemo-flow").join("config.toml")); + paths.push(cwd.join(".nemo-relay").join("config.toml")); } if matches!(scope, ConfigScope::Global | ConfigScope::Both) { paths.push(global_config_dir(home).join("config.toml")); diff --git a/crates/cli/tests/cli_tests.rs b/crates/cli/tests/cli_tests.rs index dd627afe7..a3533022e 100644 --- a/crates/cli/tests/cli_tests.rs +++ b/crates/cli/tests/cli_tests.rs @@ -10,7 +10,7 @@ use std::sync::mpsc; use std::thread; fn gateway_bin() -> &'static str { - env!("CARGO_BIN_EXE_nemo-flow") + env!("CARGO_BIN_EXE_nemo-relay") } #[test] @@ -29,7 +29,7 @@ fn cli_version_exits_successfully() { .unwrap(); assert!(output.status.success()); - assert!(String::from_utf8_lossy(&output.stdout).contains("nemo-flow ")); + assert!(String::from_utf8_lossy(&output.stdout).contains("nemo-relay ")); } #[test] @@ -76,7 +76,7 @@ fn cli_completions_prints_script_for_requested_shell() { assert!(output.status.success()); let stdout = String::from_utf8_lossy(&output.stdout); - assert!(stdout.contains("#compdef nemo-flow") || stdout.contains("_nemo-flow")); + assert!(stdout.contains("#compdef nemo-relay") || stdout.contains("_nemo-relay")); } #[test] @@ -173,8 +173,8 @@ fn cli_bare_invocation_runs_doctor_when_config_exists() { let xdg = temp.path().join("xdg"); std::fs::create_dir_all(&xdg).unwrap(); let cwd = temp.path().join("workdir"); - std::fs::create_dir_all(cwd.join(".nemo-flow")).unwrap(); - std::fs::write(cwd.join(".nemo-flow/config.toml"), "[upstream]\n").unwrap(); + std::fs::create_dir_all(cwd.join(".nemo-relay")).unwrap(); + std::fs::write(cwd.join(".nemo-relay/config.toml"), "[upstream]\n").unwrap(); let output = Command::new(gateway_bin()) .current_dir(&cwd) @@ -200,9 +200,9 @@ fn cli_bare_invocation_reports_invalid_config_resolution() { let xdg = temp.path().join("xdg"); std::fs::create_dir_all(&xdg).unwrap(); let cwd = temp.path().join("workdir"); - std::fs::create_dir_all(cwd.join(".nemo-flow")).unwrap(); - std::fs::write(cwd.join(".nemo-flow/config.toml"), "[upstream]\n").unwrap(); - std::fs::write(cwd.join(".nemo-flow/plugins.toml"), "components = [\n").unwrap(); + std::fs::create_dir_all(cwd.join(".nemo-relay")).unwrap(); + std::fs::write(cwd.join(".nemo-relay/config.toml"), "[upstream]\n").unwrap(); + std::fs::write(cwd.join(".nemo-relay/plugins.toml"), "components = [\n").unwrap(); let output = Command::new(gateway_bin()) .current_dir(&cwd) @@ -262,12 +262,12 @@ fn cli_run_dry_run_uses_project_user_and_env_config_layers() { let temp = tempfile::tempdir().unwrap(); let project = temp.path().join("project"); let nested = project.join("nested"); - let xdg = temp.path().join("xdg/nemo-flow"); - std::fs::create_dir_all(project.join(".nemo-flow")).unwrap(); + let xdg = temp.path().join("xdg/nemo-relay"); + std::fs::create_dir_all(project.join(".nemo-relay")).unwrap(); std::fs::create_dir_all(&nested).unwrap(); std::fs::create_dir_all(&xdg).unwrap(); std::fs::write( - project.join(".nemo-flow/config.toml"), + project.join(".nemo-relay/config.toml"), r#" [upstream] openai_base_url = "http://project-openai" @@ -289,9 +289,9 @@ command = "codex --full-auto" let output = Command::new(gateway_bin()) .current_dir(&nested) .env("XDG_CONFIG_HOME", temp.path().join("xdg")) - .env("NEMO_FLOW_GATEWAY_BIND", "127.0.0.1:0") - .env("NEMO_FLOW_OPENAI_BASE_URL", "http://env-openai") - .env("NEMO_FLOW_ANTHROPIC_BASE_URL", "http://env-anthropic") + .env("NEMO_RELAY_GATEWAY_BIND", "127.0.0.1:0") + .env("NEMO_RELAY_OPENAI_BASE_URL", "http://env-openai") + .env("NEMO_RELAY_ANTHROPIC_BASE_URL", "http://env-anthropic") .args(["run", "--agent", "codex", "--dry-run"]) .output() .unwrap(); @@ -308,7 +308,7 @@ command = "codex --full-auto" #[test] fn cli_hook_forward_fails_open_without_gateway_url() { let mut child = Command::new(gateway_bin()) - .env_remove("NEMO_FLOW_GATEWAY_URL") + .env_remove("NEMO_RELAY_GATEWAY_URL") .args(["hook-forward", "codex"]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -325,7 +325,7 @@ fn cli_hook_forward_fails_open_without_gateway_url() { #[test] fn cli_hook_forward_fails_closed_without_gateway_url() { let mut child = Command::new(gateway_bin()) - .env_remove("NEMO_FLOW_GATEWAY_URL") + .env_remove("NEMO_RELAY_GATEWAY_URL") .args(["hook-forward", "codex", "--fail-closed"]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -378,8 +378,8 @@ fn cli_hook_forward_posts_payload_headers_and_prints_response() { r#"{"continue":true}"# ); assert!(request.contains("POST /hooks/codex HTTP/1.1")); - assert!(request.contains("x-nemo-flow-config-profile: coverage")); - assert!(request.contains("x-nemo-flow-gateway-mode: passthrough")); + assert!(request.contains("x-nemo-relay-config-profile: coverage")); + assert!(request.contains("x-nemo-relay-gateway-mode: passthrough")); assert!(request.contains(r#"{"hook_event_name":"sessionStart"}"#)); } @@ -412,7 +412,7 @@ fn cli_hook_forward_reports_http_failure_when_fail_closed() { fn cli_hook_forward_exits_two_for_guardrail_rejection() { let (server_url, received) = spawn_single_request_server( 403, - r#"{"error":{"message":"guardrail rejected: blocked by policy","type":"nemo_flow_guardrail_rejected","reason":"blocked by policy"}}"#, + r#"{"error":{"message":"guardrail rejected: blocked by policy","type":"nemo_relay_guardrail_rejected","reason":"blocked by policy"}}"#, ); let mut child = Command::new(gateway_bin()) .args(["hook-forward", "codex", "--gateway-url", &server_url]) diff --git a/crates/cli/tests/coverage/adapters_tests.rs b/crates/cli/tests/coverage/adapters_tests.rs index fac410dbb..256404f74 100644 --- a/crates/cli/tests/coverage/adapters_tests.rs +++ b/crates/cli/tests/coverage/adapters_tests.rs @@ -600,8 +600,8 @@ fn maps_hermes_null_request_as_lossy_summary() { #[test] fn normalizes_mark_style_events_and_header_session_ids() { let mut headers = HeaderMap::new(); - headers.insert("x-nemo-flow-session-id", "header-session".parse().unwrap()); - headers.insert("x-nemo-flow-config-profile", "coverage".parse().unwrap()); + headers.insert("x-nemo-relay-session-id", "header-session".parse().unwrap()); + headers.insert("x-nemo-relay-config-profile", "coverage".parse().unwrap()); for (event_name, expected) in [ ("UserPromptSubmit", "prompt"), diff --git a/crates/cli/tests/coverage/alignment_tests.rs b/crates/cli/tests/coverage/alignment_tests.rs index bd1eb097d..c8077f50b 100644 --- a/crates/cli/tests/coverage/alignment_tests.rs +++ b/crates/cli/tests/coverage/alignment_tests.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use axum::http::HeaderValue; -use nemo_flow::api::llm::LlmRequest; +use nemo_relay::api::llm::LlmRequest; use serde_json::Map; use super::*; @@ -110,7 +110,7 @@ fn gateway_session_id_uses_explicit_claude_then_codex_fallbacks() { ); headers.insert( - "x-nemo-flow-session-id", + "x-nemo-relay-session-id", HeaderValue::from_static("explicit-thread"), ); assert_eq!( @@ -123,11 +123,11 @@ fn gateway_session_id_uses_explicit_claude_then_codex_fallbacks() { fn gateway_subagent_and_identifier_helpers_respect_header_precedence() { let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-subagent-id", + "x-nemo-relay-subagent-id", HeaderValue::from_static("worker-1"), ); headers.insert( - "x-nemo-flow-request-id", + "x-nemo-relay-request-id", HeaderValue::from_static("request-header"), ); let body = json!({ @@ -141,7 +141,7 @@ fn gateway_subagent_and_identifier_helpers_respect_header_precedence() { gateway_identifier( &headers, &body, - "x-nemo-flow-request-id", + "x-nemo-relay-request-id", &[&["request", "id"]] ) .as_deref(), diff --git a/crates/cli/tests/coverage/completions_install_tests.rs b/crates/cli/tests/coverage/completions_install_tests.rs index 807a59fc7..c8dea8c2c 100644 --- a/crates/cli/tests/coverage/completions_install_tests.rs +++ b/crates/cli/tests/coverage/completions_install_tests.rs @@ -18,19 +18,19 @@ fn zsh_uses_zdotdir_when_set() { Some(OsString::from("/home/u/dot")), ) .unwrap(); - assert_eq!(path, PathBuf::from("/home/u/dot/.zfunc/_nemo-flow")); + assert_eq!(path, PathBuf::from("/home/u/dot/.zfunc/_nemo-relay")); } #[test] fn zsh_falls_back_to_home_without_zdotdir() { let path = completion_path(Shell::Zsh, Some(OsString::from("/home/u")), None).unwrap(); - assert_eq!(path, PathBuf::from("/home/u/.zfunc/_nemo-flow")); + assert_eq!(path, PathBuf::from("/home/u/.zfunc/_nemo-relay")); } #[test] fn bash_uses_home_dot_bash_completion_d() { let path = completion_path(Shell::Bash, Some(OsString::from("/home/u")), None).unwrap(); - assert_eq!(path, PathBuf::from("/home/u/.bash_completion.d/nemo-flow")); + assert_eq!(path, PathBuf::from("/home/u/.bash_completion.d/nemo-relay")); } #[test] @@ -38,7 +38,7 @@ fn fish_uses_xdg_config_fish_completions() { let path = completion_path(Shell::Fish, Some(OsString::from("/home/u")), None).unwrap(); assert_eq!( path, - PathBuf::from("/home/u/.config/fish/completions/nemo-flow.fish") + PathBuf::from("/home/u/.config/fish/completions/nemo-relay.fish") ); } @@ -83,12 +83,12 @@ fn detect_shell_rejects_missing_shell_env() { #[test] fn write_atomic_creates_target_and_removes_temp_file() { let temp = tempfile::tempdir().unwrap(); - let target = temp.path().join("nemo-flow"); + let target = temp.path().join("nemo-relay"); - write_atomic(&target, b"complete -c nemo-flow").unwrap(); + write_atomic(&target, b"complete -c nemo-relay").unwrap(); - assert_eq!(std::fs::read(&target).unwrap(), b"complete -c nemo-flow"); - assert!(!target.with_file_name(".nemo-flow.tmp").exists()); + assert_eq!(std::fs::read(&target).unwrap(), b"complete -c nemo-relay"); + assert!(!target.with_file_name(".nemo-relay.tmp").exists()); } #[test] @@ -111,9 +111,9 @@ fn install_writes_detected_shell_completion() { restore_env("ZDOTDIR", old_zdotdir); restore_env("SHELL", old_shell); - assert_eq!(path, temp.path().join(".zfunc/_nemo-flow")); + assert_eq!(path, temp.path().join(".zfunc/_nemo-relay")); let script = std::fs::read_to_string(path).unwrap(); - assert!(script.contains("nemo-flow")); + assert!(script.contains("nemo-relay")); } fn restore_env(key: &str, value: Option) { diff --git a/crates/cli/tests/coverage/config_tests.rs b/crates/cli/tests/coverage/config_tests.rs index f7f8bc9be..d7426da41 100644 --- a/crates/cli/tests/coverage/config_tests.rs +++ b/crates/cli/tests/coverage/config_tests.rs @@ -24,19 +24,19 @@ fn isolated_config_path(temp: &tempfile::TempDir) -> std::path::PathBuf { fn session_config_prefers_headers_and_parses_json() { let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-config-profile", + "x-nemo-relay-config-profile", HeaderValue::from_static("profile-a"), ); headers.insert( - "x-nemo-flow-session-metadata", + "x-nemo-relay-session-metadata", HeaderValue::from_static(r#"{"team":"obs"}"#), ); headers.insert( - "x-nemo-flow-plugin-config", + "x-nemo-relay-plugin-config", HeaderValue::from_static(r#"{"components":[]}"#), ); headers.insert( - "x-nemo-flow-gateway-mode", + "x-nemo-relay-gateway-mode", HeaderValue::from_static("required"), ); @@ -52,7 +52,7 @@ fn session_config_prefers_headers_and_parses_json() { fn session_config_uses_defaults_and_ignores_bad_json() { let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-session-metadata", + "x-nemo-relay-session-metadata", HeaderValue::from_static("not-json"), ); headers.insert("x-empty", HeaderValue::from_static("")); @@ -190,7 +190,7 @@ fn legacy_observability_config_sections_fail_clearly() { assert!(error.contains("legacy observability config")); assert!(error.contains(expected)); assert!(error.contains("plugins.toml")); - assert!(error.contains("nemo-flow plugins edit")); + assert!(error.contains("nemo-relay plugins edit")); } } @@ -274,32 +274,32 @@ fn plugins_toml_path_resolution_tracks_config_scope() { let project = temp.path().join("workspace"); let nested = project.join("a/b/c"); - std::fs::create_dir_all(project.join(".nemo-flow")).unwrap(); + std::fs::create_dir_all(project.join(".nemo-relay")).unwrap(); std::fs::create_dir_all(&nested).unwrap(); - let plugin_path = project.join(".nemo-flow/plugins.toml"); + let plugin_path = project.join(".nemo-relay/plugins.toml"); std::fs::write(&plugin_path, "version = 1").unwrap(); - let user_config = temp.path().join("xdg/nemo-flow"); + let user_config = temp.path().join("xdg/nemo-relay"); assert_eq!(find_project_plugin_config(&nested), Some(plugin_path)); assert_eq!( project_plugin_config_path(&nested), - project.join(".nemo-flow/plugins.toml") + project.join(".nemo-relay/plugins.toml") ); assert_eq!( implicit_plugin_config_paths(Some(&nested), Some(user_config.clone())), vec![ - PathBuf::from("/etc/nemo-flow/plugins.toml"), - project.join(".nemo-flow/plugins.toml"), + PathBuf::from("/etc/nemo-relay/plugins.toml"), + project.join(".nemo-relay/plugins.toml"), user_config.join("plugins.toml"), ] ); - std::fs::remove_file(project.join(".nemo-flow/plugins.toml")).unwrap(); - std::fs::write(project.join(".nemo-flow/config.toml"), "").unwrap(); + std::fs::remove_file(project.join(".nemo-relay/plugins.toml")).unwrap(); + std::fs::write(project.join(".nemo-relay/config.toml"), "").unwrap(); assert_eq!(find_project_plugin_config(&nested), None); assert_eq!( project_plugin_config_path(&nested), - project.join(".nemo-flow/plugins.toml") + project.join(".nemo-relay/plugins.toml") ); } diff --git a/crates/cli/tests/coverage/doctor_tests.rs b/crates/cli/tests/coverage/doctor_tests.rs index 05f192262..b924d74c8 100644 --- a/crates/cli/tests/coverage/doctor_tests.rs +++ b/crates/cli/tests/coverage/doctor_tests.rs @@ -55,19 +55,19 @@ fn empty_report() -> DoctorReport { }, configuration: ConfigurationInfo { workspace: ConfigLayer { - path: PathBuf::from("/x/.nemo-flow/config.toml"), + path: PathBuf::from("/x/.nemo-relay/config.toml"), status: Status::Info, active: false, details: "not present".into(), }, global: ConfigLayer { - path: PathBuf::from("/x/.config/nemo-flow/config.toml"), + path: PathBuf::from("/x/.config/nemo-relay/config.toml"), status: Status::Info, active: false, details: "not present".into(), }, system: ConfigLayer { - path: PathBuf::from("/etc/nemo-flow/config.toml"), + path: PathBuf::from("/etc/nemo-relay/config.toml"), status: Status::Info, active: false, details: "not present".into(), @@ -326,7 +326,7 @@ fn agent_helper_statuses_cover_configured_target_and_hook_paths() { let temp = tempfile::tempdir().unwrap(); let hook = temp.path().join("hooks.yaml"); - std::fs::write(&hook, "cmd: nemo-flow hook-forward hermes\n").unwrap(); + std::fs::write(&hook, "cmd: nemo-relay hook-forward hermes\n").unwrap(); let (status, details) = hook_file_status(Ok(hook.clone()), CodingAgent::Hermes, true, "hooks"); assert_eq!(status, Status::Pass); assert!(details.contains(hook.to_str().unwrap())); @@ -334,7 +334,7 @@ fn agent_helper_statuses_cover_configured_target_and_hook_paths() { std::fs::write(&hook, "cmd: custom\n").unwrap(); let (status, details) = hook_file_status(Ok(hook.clone()), CodingAgent::Hermes, true, "hooks"); assert_eq!(status, Status::Fail); - assert!(details.contains("missing NeMo Flow hook")); + assert!(details.contains("missing NeMo Relay hook")); let (status, _) = hook_file_status(Ok(hook), CodingAgent::Hermes, false, "hooks"); assert_eq!(status, Status::Info); } @@ -343,20 +343,20 @@ fn agent_helper_statuses_cover_configured_target_and_hook_paths() { fn collect_completions_reports_shell_specific_paths() { let _guard = ENV_LOCK.lock().unwrap(); let temp = tempfile::tempdir().unwrap(); - let zsh_completion = temp.path().join(".zfunc/_nemo-flow"); + let zsh_completion = temp.path().join(".zfunc/_nemo-relay"); std::fs::create_dir_all(zsh_completion.parent().unwrap()).unwrap(); - std::fs::write(&zsh_completion, "#compdef nemo-flow\n").unwrap(); + std::fs::write(&zsh_completion, "#compdef nemo-relay\n").unwrap(); let _env = EnvScope::set(&[("SHELL", Some(std::ffi::OsStr::new("/bin/zsh")))]); let checks = collect_completions(Some(temp.path())); assert_eq!(checks[0].status, Status::Pass); - assert!(checks[0].details.contains("_nemo-flow")); + assert!(checks[0].details.contains("_nemo-relay")); drop(_env); let _env = EnvScope::set(&[("SHELL", Some(std::ffi::OsStr::new("/bin/fish")))]); let checks = collect_completions(Some(temp.path())); assert_eq!(checks[0].status, Status::Info); - assert!(checks[0].details.contains("nemo-flow.fish")); + assert!(checks[0].details.contains("nemo-relay.fish")); drop(_env); let _env = EnvScope::set(&[("SHELL", None)]); @@ -427,7 +427,7 @@ fn cursor_hook_status_rejects_grouped_entries() { "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ] @@ -461,7 +461,7 @@ fn cursor_hook_status_rejects_any_grouped_entries_when_nemo_hook_is_direct() { "hooks": { "sessionStart": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], @@ -504,7 +504,7 @@ fn cursor_hook_status_requires_version_one() { "hooks": { "beforeShellExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ] @@ -536,7 +536,7 @@ fn cursor_hook_status_rejects_non_one_version() { "hooks": { "beforeShellExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ] @@ -568,7 +568,7 @@ fn cursor_hook_status_accepts_direct_versioned_entries() { "hooks": { "beforeShellExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ] diff --git a/crates/cli/tests/coverage/gateway_tests.rs b/crates/cli/tests/coverage/gateway_tests.rs index 7c0f75c93..71b471e0d 100644 --- a/crates/cli/tests/coverage/gateway_tests.rs +++ b/crates/cli/tests/coverage/gateway_tests.rs @@ -286,7 +286,7 @@ fn gateway_session_id_prefers_headers_and_has_fallbacks() { ); headers.insert( - "x-nemo-flow-session-id", + "x-nemo-relay-session-id", HeaderValue::from_static("explicit-session"), ); assert_eq!( @@ -325,7 +325,7 @@ fn gateway_session_id_prefers_headers_and_has_fallbacks() { fn gateway_identifiers_accept_headers_and_scalar_body_values() { let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-request-id", + "x-nemo-relay-request-id", HeaderValue::from_static("req-header"), ); let body = json!({ @@ -339,7 +339,7 @@ fn gateway_identifiers_accept_headers_and_scalar_body_values() { gateway_identifier( &headers, &body, - "x-nemo-flow-request-id", + "x-nemo-relay-request-id", &[&["request", "id"]] ) .as_deref(), @@ -375,7 +375,7 @@ fn gateway_identifiers_accept_headers_and_scalar_body_values() { fn build_llm_gateway_start_uses_alignment_identifiers_and_metadata() { let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-subagent-id", + "x-nemo-relay-subagent-id", HeaderValue::from_static("worker-1"), ); headers.insert("x-request-id", HeaderValue::from_static("transport-req")); @@ -821,13 +821,13 @@ async fn streaming_gateway_call_guard_finishes_when_body_is_dropped() { #[tokio::test] async fn streaming_body_records_final_response_for_turn_output() { let subscriber_name = "gateway-stream-final-response-turn-output-test"; - let _ = nemo_flow::api::subscriber::deregister_subscriber(subscriber_name); + let _ = nemo_relay::api::subscriber::deregister_subscriber(subscriber_name); let captured_output = Arc::new(Mutex::new(None::)); let captured = captured_output.clone(); - nemo_flow::api::subscriber::register_subscriber( + nemo_relay::api::subscriber::register_subscriber( subscriber_name, Arc::new(move |event| { - if event.scope_category() == Some(nemo_flow::api::event::ScopeCategory::End) + if event.scope_category() == Some(nemo_relay::api::event::ScopeCategory::End) && event.name() == "codex-turn" && event .metadata() @@ -891,7 +891,7 @@ async fn streaming_body_records_final_response_for_turn_output() { .unwrap(); assert_eq!(*captured_output.lock().unwrap(), Some(final_response)); - nemo_flow::api::subscriber::deregister_subscriber(subscriber_name).unwrap(); + nemo_relay::api::subscriber::deregister_subscriber(subscriber_name).unwrap(); } // `stream_response_records_preview_and_truncation` was removed when the gateway moved to diff --git a/crates/cli/tests/coverage/installer_tests.rs b/crates/cli/tests/coverage/installer_tests.rs index a3262b767..8ca7fdae7 100644 --- a/crates/cli/tests/coverage/installer_tests.rs +++ b/crates/cli/tests/coverage/installer_tests.rs @@ -13,7 +13,7 @@ hooks: - command: ~/.hermes/agent-hooks/audit.sh "#; let merged = - merge_hermes_config(existing, hermes_hooks("nemo-flow hook-forward hermes")).unwrap(); + merge_hermes_config(existing, hermes_hooks("nemo-relay hook-forward hermes")).unwrap(); let yaml: Value = serde_yaml::from_str(&merged).unwrap(); assert_eq!(yaml["model"]["provider"], json!("auto")); @@ -31,7 +31,7 @@ hooks: fn hermes_config_merge_rejects_invalid_yaml() { let error = merge_hermes_config( "hooks: [not valid", - hermes_hooks("nemo-flow hook-forward hermes"), + hermes_hooks("nemo-relay hook-forward hermes"), ) .unwrap_err() .to_string(); @@ -73,7 +73,7 @@ fn merge_hooks_is_idempotent_and_preserves_existing_entries() { "Stop": [{ "hooks": [{ "type": "command", "command": "existing" }] }] } }); - let generated = codex_hooks("nemo-flow hook-forward codex"); + let generated = codex_hooks("nemo-relay hook-forward codex"); let once = merge_hooks(existing, generated.clone()).unwrap(); let twice = merge_hooks(once.clone(), generated).unwrap(); assert_eq!(once, twice); @@ -102,14 +102,14 @@ fn helper_formatting_and_headers_cover_optional_paths() { .unwrap(); assert_eq!( headers - .get("x-nemo-flow-gateway-mode") + .get("x-nemo-relay-gateway-mode") .and_then(|value| value.to_str().ok()), Some("passthrough") ); assert!( insert_header( &mut HeaderMap::new(), - "x-nemo-flow-config-profile", + "x-nemo-relay-config-profile", Some("bad\nvalue") ) .is_err() @@ -130,24 +130,24 @@ fn generated_hook_dispatch_covers_all_agents() { assert!(generated_hooks(agent, "cmd")["hooks"].is_object()); } assert_eq!( - hook_forward_command("nemo-flow", CodingAgent::Hermes), - "nemo-flow hook-forward hermes" + hook_forward_command("nemo-relay", CodingAgent::Hermes), + "nemo-relay hook-forward hermes" ); assert_eq!( - hook_forward_command("/abs/path/to/nemo-flow", CodingAgent::Codex), - "/abs/path/to/nemo-flow hook-forward codex" + hook_forward_command("/abs/path/to/nemo-relay", CodingAgent::Codex), + "/abs/path/to/nemo-relay hook-forward codex" ); } #[test] fn cursor_hooks_use_direct_command_entries() { - let hooks = cursor_hooks("nemo-flow hook-forward cursor"); + let hooks = cursor_hooks("nemo-relay hook-forward cursor"); let before_shell = &hooks["hooks"]["beforeShellExecution"][0]; assert_eq!(hooks["version"], json!(1)); assert_eq!( before_shell["command"], - json!("nemo-flow hook-forward cursor") + json!("nemo-relay hook-forward cursor") ); assert_eq!(before_shell["timeout"], json!(30)); assert!(before_shell.get("hooks").is_none()); diff --git a/crates/cli/tests/coverage/launcher_tests.rs b/crates/cli/tests/coverage/launcher_tests.rs index 1f9ef1298..c079e2277 100644 --- a/crates/cli/tests/coverage/launcher_tests.rs +++ b/crates/cli/tests/coverage/launcher_tests.rs @@ -113,7 +113,7 @@ fn inference_failure_has_actionable_message() { #[test] fn missing_command_without_agent_errors() { - // Bare `nemo-flow run` (no command, no --agent) errors — we have nothing to spawn and no + // Bare `nemo-relay run` (no command, no --agent) errors — we have nothing to spawn and no // argv[0] to infer an agent from. With --agent set, we fall back to the agent's default // binary name (e.g., `cursor-agent`), so that branch is exercised in the resolution test // below rather than here. @@ -159,7 +159,7 @@ fn agent_without_configured_command_falls_back_to_default_binary() { #[test] fn agent_with_passthrough_args_appends_to_configured_command() { - // The easy-path uses this code path: `nemo-flow codex -- --model X` resolves to the + // The easy-path uses this code path: `nemo-relay codex -- --model X` resolves to the // configured (or default) codex command with `--model X` appended. let command = RunCommand { agent: Some(CodingAgent::Codex), @@ -200,13 +200,13 @@ fn prepares_codex_config_overrides() { prepared .argv .iter() - .any(|arg| arg == "model_provider=\"nemo-flow-openai\"") + .any(|arg| arg == "model_provider=\"nemo-relay-openai\"") ); assert!( prepared .argv .iter() - .any(|arg| arg.contains("model_providers.nemo-flow-openai") + .any(|arg| arg.contains("model_providers.nemo-relay-openai") && arg.contains("base_url=\"http://127.0.0.1:1234\"") // Codex sends its own credentials (ChatGPT-Plus OAuth or OPENAI_API_KEY). // When OPENAI_API_KEY is in the environment the gateway substitutes it; @@ -381,7 +381,7 @@ fn prepares_hermes_hook_environment() { assert_eq!(prepared.argv, vec!["hermes", "chat"]); assert!(prepared.env.contains(&( - "NEMO_FLOW_GATEWAY_URL".into(), + "NEMO_RELAY_GATEWAY_URL".into(), "http://127.0.0.1:1234".into() ))); assert!( @@ -390,7 +390,7 @@ fn prepares_hermes_hook_environment() { .iter() .any(|(name, _)| name == "HERMES_ACCEPT_HOOKS") ); - assert!(prepared.notes[0].contains("nemo-flow config hermes")); + assert!(prepared.notes[0].contains("nemo-relay config hermes")); } #[test] @@ -668,7 +668,7 @@ fn fake_agent_command(temp: &Path, output: &Path) -> Vec { std::fs::write( &script, format!( - "#!/bin/sh\nprintf '%s' \"$NEMO_FLOW_GATEWAY_URL\" > \"{}\"\nexit 7\n", + "#!/bin/sh\nprintf '%s' \"$NEMO_RELAY_GATEWAY_URL\" > \"{}\"\nexit 7\n", output.display() ), ) diff --git a/crates/cli/tests/coverage/plugins_tests.rs b/crates/cli/tests/coverage/plugins_tests.rs index 9ca3fd357..917e8afb4 100644 --- a/crates/cli/tests/coverage/plugins_tests.rs +++ b/crates/cli/tests/coverage/plugins_tests.rs @@ -3,10 +3,10 @@ use super::*; use crate::config::{global_plugin_config_path, project_plugin_config_path}; -use nemo_flow::observability::plugin_component::OBSERVABILITY_PLUGIN_KIND; -use nemo_flow::plugin::{ConfigPolicy, PluginComponentSpec, PluginConfig}; -use nemo_flow_adaptive::AdaptiveConfig; -use nemo_flow_adaptive::plugin_component::ADAPTIVE_PLUGIN_KIND; +use nemo_relay::observability::plugin_component::OBSERVABILITY_PLUGIN_KIND; +use nemo_relay::plugin::{ConfigPolicy, PluginComponentSpec, PluginConfig}; +use nemo_relay_adaptive::AdaptiveConfig; +use nemo_relay_adaptive::plugin_component::ADAPTIVE_PLUGIN_KIND; fn adaptive_component_config(agent_id: &str) -> serde_json::Map { json!({ @@ -221,7 +221,7 @@ fn typed_editor_serializes_disabled_section_override() { assert_eq!(atif.get("enabled"), Some(&Value::Bool(false))); assert_eq!( atif.get("filename_template"), - Some(&json!("nemo-flow-atif-{session_id}.json")) + Some(&json!("nemo-relay-atif-{session_id}.json")) ); } diff --git a/crates/cli/tests/coverage/server_tests.rs b/crates/cli/tests/coverage/server_tests.rs index 39368d079..12caff1f1 100644 --- a/crates/cli/tests/coverage/server_tests.rs +++ b/crates/cli/tests/coverage/server_tests.rs @@ -12,10 +12,10 @@ use axum::response::IntoResponse; use bytes::Bytes; use futures_util::stream; use http_body_util::BodyExt; -use nemo_flow::api::registry::{ +use nemo_relay::api::registry::{ deregister_tool_conditional_execution_guardrail, register_tool_conditional_execution_guardrail, }; -use nemo_flow::plugin::{ +use nemo_relay::plugin::{ ConfigDiagnostic, Plugin, PluginRegistration, PluginRegistrationContext, deregister_plugin, register_plugin, }; @@ -61,7 +61,7 @@ impl Plugin for GenericTestPlugin { &'a self, _plugin_config: &Map, ctx: &'a mut PluginRegistrationContext, - ) -> Pin> + Send + 'a>> { + ) -> Pin> + Send + 'a>> { Box::pin(async move { GENERIC_TEST_PLUGIN_REGISTRATIONS.fetch_add(1, Ordering::SeqCst); ctx.add_registration(PluginRegistration::new( @@ -154,7 +154,7 @@ async fn healthz_returns_ok() { #[tokio::test] async fn serve_listener_activates_plugin_config_and_clears_on_shutdown() { let _guard = PLUGIN_TEST_LOCK.lock().await; - let _ = nemo_flow::plugin::clear_plugin_configuration(); + let _ = nemo_relay::plugin::clear_plugin_configuration(); let temp = tempfile::tempdir().unwrap(); let atof_dir = temp.path().join("atof"); @@ -194,7 +194,7 @@ async fn serve_listener_activates_plugin_config_and_clears_on_shutdown() { tokio::spawn(async move { serve_listener(listener, config, Some(shutdown_rx)).await }); wait_for_gateway(&url).await; - assert!(nemo_flow::plugin::active_plugin_report().is_some()); + assert!(nemo_relay::plugin::active_plugin_report().is_some()); let client = test_http_client(); for hook_event_name in ["on_session_start", "on_session_finalize"] { @@ -212,7 +212,7 @@ async fn serve_listener_activates_plugin_config_and_clears_on_shutdown() { shutdown_tx.send(()).unwrap(); handle.await.unwrap().unwrap(); - assert!(nemo_flow::plugin::active_plugin_report().is_none()); + assert!(nemo_relay::plugin::active_plugin_report().is_none()); let events = std::fs::read_to_string(temp.path().join("atof/events.jsonl")).unwrap(); assert!( @@ -236,7 +236,7 @@ async fn serve_listener_activates_plugin_config_and_clears_on_shutdown() { #[tokio::test] async fn serve_listener_observability_plugin_records_non_hermes_hooks() { let _guard = PLUGIN_TEST_LOCK.lock().await; - let _ = nemo_flow::plugin::clear_plugin_configuration(); + let _ = nemo_relay::plugin::clear_plugin_configuration(); let temp = tempfile::tempdir().unwrap(); let atof_dir = temp.path().join("atof"); @@ -301,7 +301,7 @@ async fn serve_listener_observability_plugin_records_non_hermes_hooks() { shutdown_tx.send(()).unwrap(); handle.await.unwrap().unwrap(); - assert!(nemo_flow::plugin::active_plugin_report().is_none()); + assert!(nemo_relay::plugin::active_plugin_report().is_none()); let events = std::fs::read_to_string(temp.path().join("atof/events.jsonl")).unwrap(); let agent_starts = events @@ -322,7 +322,7 @@ async fn serve_listener_observability_plugin_records_non_hermes_hooks() { #[tokio::test] async fn serve_listener_activates_any_registered_plugin_kind() { let _guard = PLUGIN_TEST_LOCK.lock().await; - let _ = nemo_flow::plugin::clear_plugin_configuration(); + let _ = nemo_relay::plugin::clear_plugin_configuration(); let _ = deregister_plugin(GENERIC_TEST_PLUGIN_KIND); GENERIC_TEST_PLUGIN_REGISTRATIONS.store(0, Ordering::SeqCst); GENERIC_TEST_PLUGIN_DEREGISTRATIONS.store(0, Ordering::SeqCst); @@ -367,14 +367,14 @@ async fn serve_listener_activates_any_registered_plugin_kind() { GENERIC_TEST_PLUGIN_DEREGISTRATIONS.load(Ordering::SeqCst), 1 ); - assert!(nemo_flow::plugin::active_plugin_report().is_none()); + assert!(nemo_relay::plugin::active_plugin_report().is_none()); let _ = deregister_plugin(GENERIC_TEST_PLUGIN_KIND); } #[tokio::test] async fn serve_listener_activates_adaptive_plugin_config() { let _guard = PLUGIN_TEST_LOCK.lock().await; - let _ = nemo_flow::plugin::clear_plugin_configuration(); + let _ = nemo_relay::plugin::clear_plugin_configuration(); let mut config = test_config(); config.plugin_config = Some(json!({ @@ -405,18 +405,18 @@ async fn serve_listener_activates_adaptive_plugin_config() { tokio::spawn(async move { serve_listener(listener, config, Some(shutdown_rx)).await }); wait_for_gateway(&url).await; - let report = nemo_flow::plugin::active_plugin_report().unwrap(); + let report = nemo_relay::plugin::active_plugin_report().unwrap(); assert!(report.diagnostics.is_empty()); shutdown_tx.send(()).unwrap(); handle.await.unwrap().unwrap(); - assert!(nemo_flow::plugin::active_plugin_report().is_none()); + assert!(nemo_relay::plugin::active_plugin_report().is_none()); } #[tokio::test] async fn serve_listener_rejects_invalid_plugin_config() { let _guard = PLUGIN_TEST_LOCK.lock().await; - let _ = nemo_flow::plugin::clear_plugin_configuration(); + let _ = nemo_relay::plugin::clear_plugin_configuration(); let mut config = test_config(); config.plugin_config = Some(json!({ @@ -442,7 +442,7 @@ async fn serve_listener_rejects_invalid_plugin_config() { .unwrap_err(); assert!(error.to_string().contains("ATOF mode")); - assert!(nemo_flow::plugin::active_plugin_report().is_none()); + assert!(nemo_relay::plugin::active_plugin_report().is_none()); } #[tokio::test] @@ -452,7 +452,7 @@ async fn gateway_errors_render_structured_json_responses() { assert_eq!(response.status(), StatusCode::BAD_REQUEST); let bytes = response.into_body().collect().await.unwrap().to_bytes(); let body: Value = serde_json::from_slice(&bytes).unwrap(); - assert_eq!(body["error"]["type"], json!("nemo_flow_gateway_error")); + assert_eq!(body["error"]["type"], json!("nemo_relay_gateway_error")); assert!( body["error"]["message"] .as_str() @@ -563,7 +563,10 @@ async fn pre_tool_hook_rejects_when_conditional_guardrail_blocks() { assert_eq!(response.status(), StatusCode::FORBIDDEN); let bytes = response.into_body().collect().await.unwrap().to_bytes(); let body: Value = serde_json::from_slice(&bytes).unwrap(); - assert_eq!(body["error"]["type"], json!("nemo_flow_guardrail_rejected")); + assert_eq!( + body["error"]["type"], + json!("nemo_relay_guardrail_rejected") + ); assert_eq!(body["error"]["reason"], json!("blocked by policy")); } diff --git a/crates/cli/tests/coverage/session_tests.rs b/crates/cli/tests/coverage/session_tests.rs index 003db5d6d..274e94b01 100644 --- a/crates/cli/tests/coverage/session_tests.rs +++ b/crates/cli/tests/coverage/session_tests.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use axum::http::HeaderMap; -use nemo_flow::api::event::ScopeCategory; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::plugin::{PluginConfig, clear_plugin_configuration, initialize_plugins}; +use nemo_relay::api::event::ScopeCategory; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::plugin::{PluginConfig, clear_plugin_configuration, initialize_plugins}; use serde_json::json; use std::path::Path; use std::sync::{Arc, Mutex as StdMutex}; @@ -211,7 +211,7 @@ async fn parallel_subagents_are_siblings_under_turn_scope() { .unwrap() .metadata .as_ref() - .unwrap()["nemo_flow_scope_role"], + .unwrap()["nemo_relay_scope_role"], json!("subagent") ); assert_eq!( @@ -255,7 +255,7 @@ async fn codex_turn_is_agent_scope_with_turn_role_metadata() { assert_eq!(turn.name, "codex-turn"); assert_eq!(turn.scope_type, ScopeType::Agent); assert_eq!( - turn.metadata.as_ref().unwrap()["nemo_flow_scope_role"], + turn.metadata.as_ref().unwrap()["nemo_relay_scope_role"], json!("turn") ); } @@ -1175,10 +1175,10 @@ async fn writes_atif_on_session_end_from_plugin_config() { let manager = SessionManager::new(config); let mut headers = HeaderMap::new(); headers.insert( - "x-nemo-flow-session-metadata", + "x-nemo-relay-session-metadata", r#"{"team":"coverage"}"#.parse().unwrap(), ); - headers.insert("x-nemo-flow-gateway-mode", "required".parse().unwrap()); + headers.insert("x-nemo-relay-gateway-mode", "required".parse().unwrap()); manager .apply_events( @@ -2503,7 +2503,7 @@ async fn request_affinity_pairs_parallel_subagents_across_provider_formats() { subagent_id: Some("python-worker".into()), ..llm_start_with_responses_task( "parallel-affinity", - "Very thorough analysis of the python/nemo_flow package.", + "Very thorough analysis of the python/nemo_relay package.", ) }, ) @@ -2521,7 +2521,7 @@ async fn request_affinity_pairs_parallel_subagents_across_provider_formats() { subagent_id: Some("go-worker".into()), ..llm_start_with_messages_task( "parallel-affinity", - "Very thorough analysis of the go/nemo_flow binding.", + "Very thorough analysis of the go/nemo_relay binding.", ) }, ) @@ -2543,7 +2543,7 @@ async fn request_affinity_pairs_parallel_subagents_across_provider_formats() { tool_call_id: "go-tool".into(), tool_name: "Read".into(), subagent_id: Some("go-worker".into()), - arguments: json!({ "file_path": "go/nemo_flow/nemo_flow.go" }), + arguments: json!({ "file_path": "go/nemo_relay/nemo_relay.go" }), result: Value::Null, status: None, payload: json!({}), @@ -2582,7 +2582,7 @@ async fn request_affinity_pairs_parallel_subagents_across_provider_formats() { &HeaderMap::new(), llm_start_with_chat_completion_task( "parallel-affinity", - "Very thorough analysis of the python/nemo_flow package.", + "Very thorough analysis of the python/nemo_relay package.", ), ) .await diff --git a/crates/cli/tests/coverage/setup_tests.rs b/crates/cli/tests/coverage/setup_tests.rs index ef41798eb..e7683458e 100644 --- a/crates/cli/tests/coverage/setup_tests.rs +++ b/crates/cli/tests/coverage/setup_tests.rs @@ -164,7 +164,7 @@ fn save_config_writes_project_scope_to_workspace_dir() { let written = save_config(&doc, ConfigScope::Project, temp.path(), home.path(), None).unwrap(); assert_eq!(written.len(), 1); - assert_eq!(written[0], temp.path().join(".nemo-flow/config.toml")); + assert_eq!(written[0], temp.path().join(".nemo-relay/config.toml")); let contents = std::fs::read_to_string(&written[0]).unwrap(); assert!(!contents.contains("[exporters]")); assert!(contents.contains("[agents.claude]")); @@ -177,7 +177,7 @@ fn save_config_scoped_merge_preserves_other_agents() { // upstream survive while claude is updated and observability is written fresh. let temp = tempfile::tempdir().unwrap(); let home = tempfile::tempdir().unwrap(); - let project_dir = temp.path().join(".nemo-flow"); + let project_dir = temp.path().join(".nemo-relay"); std::fs::create_dir_all(&project_dir).unwrap(); let existing_path = project_dir.join("config.toml"); std::fs::write( @@ -270,12 +270,12 @@ fn config_scope_labels_are_user_facing_and_stable() { assert!( ConfigScope::Project .label() - .contains(".nemo-flow/config.toml") + .contains(".nemo-relay/config.toml") ); assert!( ConfigScope::Global .label() - .contains(".config/nemo-flow/config.toml") + .contains(".config/nemo-relay/config.toml") ); assert!( ConfigScope::Both @@ -367,14 +367,14 @@ fn install_hermes_hooks_writes_yaml_and_merges_existing() { assert_eq!(written.len(), 2); let project_yaml = std::fs::read_to_string(cwd.path().join(".hermes/config.yaml")).unwrap(); - assert!(project_yaml.contains("nemo-flow hook-forward hermes")); + assert!(project_yaml.contains("nemo-relay hook-forward hermes")); assert!(project_yaml.contains("api_request_error")); assert!( project_yaml.contains("provider: auto"), "existing model block must survive merge" ); let home_yaml = std::fs::read_to_string(home.path().join(".hermes/config.yaml")).unwrap(); - assert!(home_yaml.contains("nemo-flow hook-forward hermes")); + assert!(home_yaml.contains("nemo-relay hook-forward hermes")); } #[test] @@ -409,7 +409,7 @@ enabled = true fn reset_removes_whole_project_config_or_one_agent() { let temp = tempfile::tempdir().unwrap(); let _cwd = CwdScope::enter(temp.path()); - let config_dir = temp.path().join(".nemo-flow"); + let config_dir = temp.path().join(".nemo-relay"); std::fs::create_dir_all(&config_dir).unwrap(); let path = config_dir.join("config.toml"); std::fs::write( @@ -439,7 +439,7 @@ command = "codex" fn reset_reports_missing_or_malformed_agent_blocks_without_rewriting() { let temp = tempfile::tempdir().unwrap(); let _cwd = CwdScope::enter(temp.path()); - let config_dir = temp.path().join(".nemo-flow"); + let config_dir = temp.path().join(".nemo-relay"); std::fs::create_dir_all(&config_dir).unwrap(); let path = config_dir.join("config.toml"); std::fs::write(&path, "agents = \"not-a-table\"\n").unwrap(); diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 3501448d4..898b16144 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -2,12 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow" +name = "nemo-relay" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Core Rust SDK for NeMo Flow observability, scope management, and runtime instrumentation." +description = "Core Rust SDK for NeMo Relay observability, scope management, and runtime instrumentation." readme = "README.md" [lints] diff --git a/crates/core/README.md b/crates/core/README.md index b0ec834c5..362d2c65d 100644 --- a/crates/core/README.md +++ b/crates/core/README.md @@ -3,26 +3,26 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow` is the core Rust SDK for NeMo Flow, a portable execution +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay` is the core Rust SDK for NeMo Relay, a portable execution runtime for agent systems. Use it when a Rust application, framework adapter, or service needs one consistent way to scope, control, and observe tool and LLM calls. -Rust is the source of truth for NeMo Flow runtime behavior. The Python and +Rust is the source of truth for NeMo Relay runtime behavior. The Python and Node.js bindings mirror the semantics exposed by this crate. ## Why Use It? @@ -59,21 +59,21 @@ Node.js bindings mirror the semantics exposed by this crate. Install the published crate in a Rust application: ```bash -cargo add nemo-flow serde_json +cargo add nemo-relay serde_json ``` To add adaptive runtime behavior, install the companion crate too: ```bash -cargo add nemo-flow-adaptive +cargo add nemo-relay-adaptive ``` When consuming a local checkout, use path dependencies: ```toml [dependencies] -nemo-flow = { path = "../NeMo-Flow/crates/core" } -nemo-flow-adaptive = { path = "../NeMo-Flow/crates/adaptive" } +nemo-relay = { path = "../NeMo-Relay/crates/core" } +nemo-relay-adaptive = { path = "../NeMo-Relay/crates/adaptive" } serde_json = "1" ``` @@ -83,7 +83,7 @@ The smallest useful workflow is to create a scope, emit a mark event, and close the scope: ```rust -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ self, EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType, }; use serde_json::json; @@ -113,4 +113,4 @@ fn main() -> Result<(), Box> { ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/core/src/api/llm.rs b/crates/core/src/api/llm.rs index c7b894e2a..91c149e63 100644 --- a/crates/core/src/api/llm.rs +++ b/crates/core/src/api/llm.rs @@ -10,7 +10,7 @@ use serde_json::json; use typed_builder::TypedBuilder; use uuid::Uuid; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::current_scope_stack; use crate::api::runtime::global_context; use crate::api::runtime::{ @@ -79,7 +79,7 @@ pub struct LlmRequest { pub content: Json, } -/// Builder parameters for [`NemoFlowContextState::create_llm_handle`]. +/// Builder parameters for [`NemoRelayContextState::create_llm_handle`]. #[derive(Debug, Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct CreateLlmHandleParams<'a> { @@ -106,7 +106,7 @@ pub struct CreateLlmHandleParams<'a> { pub timestamp: Option>, } -/// Builder parameters for [`NemoFlowContextState::build_llm_end_event`]. +/// Builder parameters for [`NemoRelayContextState::build_llm_end_event`]. #[derive(Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct EndLlmHandleParams<'a> { @@ -296,7 +296,7 @@ fn emit_llm_start( let event = state.build_llm_start_event(handle, Some(input), annotated_request); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } @@ -431,7 +431,7 @@ pub fn llm_call_end(params: LlmCallEndParams<'_>) -> Result<()> { ); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); if let Some(error) = decode_error { Err(error) } else { @@ -453,7 +453,7 @@ fn emit_llm_end_without_output(handle: &LlmHandle, metadata: Option) -> Re let event = state.end_llm_handle(handle, handle.data.clone(), metadata, None); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } @@ -530,7 +530,7 @@ pub async fn llm_call_execute(params: LlmCallExecuteParams) -> Result { metadata.clone(), ) }; - if let Some(error) = NemoFlowContextState::llm_conditional_execution_snapshot_chain( + if let Some(error) = NemoRelayContextState::llm_conditional_execution_snapshot_chain( &request, &entries, &subscribers, @@ -678,7 +678,7 @@ pub async fn llm_stream_call_execute(params: LlmStreamCallExecuteParams) -> Resu metadata.clone(), ) }; - if let Some(error) = NemoFlowContextState::llm_conditional_execution_snapshot_chain( + if let Some(error) = NemoRelayContextState::llm_conditional_execution_snapshot_chain( &request, &entries, &subscribers, @@ -820,7 +820,7 @@ pub fn llm_conditional_execution(request: &LlmRequest) -> Result<()> { let subscribers = state.collect_event_subscribers(&scope_subscribers); (entries, subscribers, resolve_parent_uuid(None)) }; - if let Some(error) = NemoFlowContextState::llm_conditional_execution_snapshot_chain( + if let Some(error) = NemoRelayContextState::llm_conditional_execution_snapshot_chain( request, &entries, &subscribers, diff --git a/crates/core/src/api/mod.rs b/crates/core/src/api/mod.rs index f79665c67..c0f9cc09a 100644 --- a/crates/core/src/api/mod.rs +++ b/crates/core/src/api/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Public API for the NeMo Flow runtime. +//! Public API for the NeMo Relay runtime. /// Lifecycle event types and builder-backed event constructors. pub mod event; diff --git a/crates/core/src/api/runtime.rs b/crates/core/src/api/runtime.rs index 28b83db63..371fd6dc9 100644 --- a/crates/core/src/api/runtime.rs +++ b/crates/core/src/api/runtime.rs @@ -21,4 +21,4 @@ pub use scope_stack::{ restore_thread_scope_stack, scope_stack_active, set_thread_scope_stack, sync_thread_scope_stack, task_scope_push, task_scope_remove, task_scope_top, }; -pub use state::NemoFlowContextState; +pub use state::NemoRelayContextState; diff --git a/crates/core/src/api/runtime/global.rs b/crates/core/src/api/runtime/global.rs index 91f0001b3..6ae77217f 100644 --- a/crates/core/src/api/runtime/global.rs +++ b/crates/core/src/api/runtime/global.rs @@ -4,19 +4,19 @@ //! Process-global access to the shared runtime context state. //! //! The public API layer uses this module to resolve the single -//! [`NemoFlowContextState`] instance that owns middleware registrations and +//! [`NemoRelayContextState`] instance that owns middleware registrations and //! runtime extensions for the current process. use std::sync::{Arc, RwLock}; -use crate::api::runtime::state::NemoFlowContextState; +use crate::api::runtime::state::NemoRelayContextState; -static GLOBAL_CONTEXT: std::sync::OnceLock>> = +static GLOBAL_CONTEXT: std::sync::OnceLock>> = std::sync::OnceLock::new(); /// Return the process-global runtime context state handle. /// -/// This lazily initializes the shared [`NemoFlowContextState`] on first use and +/// This lazily initializes the shared [`NemoRelayContextState`] on first use and /// returns a cloned [`Arc`] handle to the same underlying [`RwLock`] on every /// subsequent call. /// @@ -27,8 +27,8 @@ static GLOBAL_CONTEXT: std::sync::OnceLock>> = /// # Notes /// All callers share the same underlying state. Mutations made through one /// handle are visible through every other handle returned by this function. -pub fn global_context() -> Arc> { +pub fn global_context() -> Arc> { GLOBAL_CONTEXT - .get_or_init(|| Arc::new(RwLock::new(NemoFlowContextState::new()))) + .get_or_init(|| Arc::new(RwLock::new(NemoRelayContextState::new()))) .clone() } diff --git a/crates/core/src/api/runtime/state.rs b/crates/core/src/api/runtime/state.rs index 943ab198e..45398668b 100644 --- a/crates/core/src/api/runtime/state.rs +++ b/crates/core/src/api/runtime/state.rs @@ -3,7 +3,7 @@ //! Process-global runtime state and middleware-chain builders. //! -//! [`NemoFlowContextState`] owns the registries and helper methods that power +//! [`NemoRelayContextState`] owns the registries and helper methods that power //! the public scope, tool, and LLM APIs. Advanced integrations can use this //! type directly to register middleware, attach runtime extensions, and build //! the resolved callback chains that the higher-level API layer executes. @@ -44,7 +44,7 @@ use uuid::Uuid; /// The public API layer stores one shared instance of this type for the /// process. It contains global middleware registries, lifecycle subscribers, /// and arbitrary extension slots used by bindings or integrations. -pub struct NemoFlowContextState { +pub struct NemoRelayContextState { /// Global tool request sanitizers applied to emitted tool-start payloads. pub(crate) tool_sanitize_request_guardrails: SortedRegistry>, /// Global tool response sanitizers applied to emitted tool-end payloads. @@ -74,11 +74,11 @@ pub struct NemoFlowContextState { pub(crate) extensions: HashMap>, } -impl NemoFlowContextState { +impl NemoRelayContextState { /// Create an empty runtime state with no registered middleware. /// /// # Returns - /// A [`NemoFlowContextState`] with empty registries, no subscribers, and no + /// A [`NemoRelayContextState`] with empty registries, no subscribers, and no /// extensions. pub fn new() -> Self { Self { @@ -1027,7 +1027,7 @@ fn end_timestamp_after(started_at: chrono::DateTime) -> chrono::DateTime Self { Self::new() } diff --git a/crates/core/src/api/scope.rs b/crates/core/src/api/scope.rs index dc8c75f05..51700d35b 100644 --- a/crates/core/src/api/scope.rs +++ b/crates/core/src/api/scope.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::api::event::{BaseEvent, MarkEvent}; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::runtime::{ current_scope_stack, task_scope_push, task_scope_remove, task_scope_top, @@ -145,7 +145,7 @@ pub struct PushScopeParams<'a> { pub timestamp: Option>, } -/// Builder parameters for [`NemoFlowContextState::create_scope_handle`]. +/// Builder parameters for [`NemoRelayContextState::create_scope_handle`]. #[derive(Debug, Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct CreateScopeHandleParams<'a> { @@ -171,7 +171,7 @@ pub struct CreateScopeHandleParams<'a> { pub timestamp: Option>, } -/// Builder parameters for [`NemoFlowContextState::build_scope_end_event`]. +/// Builder parameters for [`NemoRelayContextState::build_scope_end_event`]. #[derive(Debug, Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct EndScopeHandleParams<'a> { @@ -295,7 +295,7 @@ pub fn push_scope(params: PushScopeParams<'_>) -> Result { (handle, event, subscribers) }; task_scope_push(handle.clone()); - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(handle) } @@ -353,7 +353,7 @@ pub fn pop_scope(params: PopScopeParams<'_>) -> Result<()> { }; let removed = task_scope_remove(params.handle_uuid)?; debug_assert_eq!(removed.uuid, scope.uuid); - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } @@ -406,6 +406,6 @@ pub fn event(params: EmitMarkEventParams<'_>) -> Result<()> { )); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } diff --git a/crates/core/src/api/tool.rs b/crates/core/src/api/tool.rs index fc6495bde..fd38658bb 100644 --- a/crates/core/src/api/tool.rs +++ b/crates/core/src/api/tool.rs @@ -3,7 +3,7 @@ use serde_json::json; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::ToolExecutionNextFn; use crate::api::runtime::current_scope_stack; use crate::api::runtime::global_context; @@ -57,7 +57,7 @@ pub struct ToolHandle { pub tool_call_id: Option, } -/// Builder parameters for [`NemoFlowContextState::create_tool_handle`]. +/// Builder parameters for [`NemoRelayContextState::create_tool_handle`]. #[derive(Debug, Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct CreateToolHandleParams<'a> { @@ -84,7 +84,7 @@ pub struct CreateToolHandleParams<'a> { pub timestamp: Option>, } -/// Builder parameters for [`NemoFlowContextState::build_tool_end_event`]. +/// Builder parameters for [`NemoRelayContextState::build_tool_end_event`]. #[derive(Debug, Clone, TypedBuilder)] #[builder(field_defaults(setter(strip_option(ignore_invalid, fallback_suffix = "_opt"))))] pub struct EndToolHandleParams<'a> { @@ -239,7 +239,7 @@ pub fn tool_call(params: ToolCallParams<'_>) -> Result { let event = state.build_tool_start_event(&handle, Some(sanitized_args)); (handle, event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(handle) } @@ -301,7 +301,7 @@ pub fn tool_call_end(params: ToolCallEndParams<'_>) -> Result<()> { ); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } @@ -319,7 +319,7 @@ fn emit_tool_end_without_output(handle: &ToolHandle, metadata: Option) -> let event = state.end_tool_handle(handle, handle.data.clone(), metadata); (event, subscribers) }; - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); Ok(()) } @@ -383,7 +383,7 @@ pub async fn tool_call_execute(params: ToolCallExecuteParams) -> Result { metadata.clone(), ) }; - if let Some(error) = NemoFlowContextState::tool_conditional_execution_snapshot_chain( + if let Some(error) = NemoRelayContextState::tool_conditional_execution_snapshot_chain( &name, &args, &entries, @@ -530,7 +530,7 @@ pub fn tool_conditional_execution(name: &str, args: &Json) -> Result<()> { let subscribers = state.collect_event_subscribers(&scope_subscribers); (entries, subscribers, resolve_parent_uuid(None)) }; - if let Some(error) = NemoFlowContextState::tool_conditional_execution_snapshot_chain( + if let Some(error) = NemoRelayContextState::tool_conditional_execution_snapshot_chain( name, args, &entries, diff --git a/crates/core/src/codec/traits.rs b/crates/core/src/codec/traits.rs index a4236409f..6fe5d1899 100644 --- a/crates/core/src/codec/traits.rs +++ b/crates/core/src/codec/traits.rs @@ -26,7 +26,7 @@ use super::response::AnnotatedLlmResponse; /// - **Synchronous**: `decode`/`encode` are pure data transforms (JSON /// restructuring), not I/O operations. This matches existing guardrails /// and request intercepts. -/// - **`Send + Sync`**: Required because [`NemoFlowContextState`](crate::api::runtime::NemoFlowContextState) +/// - **`Send + Sync`**: Required because [`NemoRelayContextState`](crate::api::runtime::NemoRelayContextState) /// is behind `Arc>` and accessed from async contexts. /// - **Trait object**: Codecs are registered at runtime (e.g., by Python /// patches), so the Rust core cannot know concrete types at compile time. diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 13c2ebd93..8c7e24f9c 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Error types for the NeMo Flow runtime. +//! Error types for the NeMo Relay runtime. //! //! All fallible operations in the runtime return [`Result`], which uses //! [`FlowError`] as the error type. Errors are categorized by cause @@ -9,7 +9,7 @@ use thiserror::Error; -/// The error type for all NeMo Flow runtime operations. +/// The error type for all NeMo Relay runtime operations. /// /// Each variant represents a distinct failure mode that callers can match on /// to determine the appropriate recovery strategy. @@ -58,7 +58,7 @@ pub enum FlowError { Internal(String), } -/// A specialized [`Result`](std::result::Result) type for NeMo Flow operations. +/// A specialized [`Result`](std::result::Result) type for NeMo Relay operations. pub type Result = std::result::Result; #[cfg(test)] diff --git a/crates/core/src/json.rs b/crates/core/src/json.rs index dd8ee424c..ec42a1f1c 100644 --- a/crates/core/src/json.rs +++ b/crates/core/src/json.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! JSON utilities for the NeMo Flow runtime. +//! JSON utilities for the NeMo Relay runtime. //! //! This module provides a [`Json`] type alias for [`serde_json::Value`] used //! throughout the crate, and a [`merge_json`] helper for shallow-merging //! optional JSON values. /// Type alias for [`serde_json::Value`], used as the universal JSON -/// representation throughout the NeMo Flow runtime. +/// representation throughout the NeMo Relay runtime. pub type Json = serde_json::Value; /// Shallow-merge two optional JSON values. diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 13aed13c8..ffd03a4dd 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -3,16 +3,16 @@ #![deny(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)] -//! # NeMo Flow Core +//! # NeMo Relay Core //! -//! The core runtime library for the NeMo Flow multi-language agent framework. This crate +//! The core runtime library for the NeMo Relay multi-language agent framework. This crate //! provides execution scope management, lifecycle event tracking, and middleware pipelines //! (guardrails and intercepts) for tool and LLM calls. //! //! ## Architecture //! //! The runtime is organized around a **global context** -//! ([`api::runtime::NemoFlowContextState`]) that holds all registered middleware +//! ([`api::runtime::NemoRelayContextState`]) that holds all registered middleware //! (guardrails, intercepts, subscribers) and a **scope stack** //! ([`api::runtime::ScopeStack`]) that tracks the hierarchical execution context //! via task-local or thread-local storage. diff --git a/crates/core/src/observability/atif.rs b/crates/core/src/observability/atif.rs index ed2a1ec4a..df47532c5 100644 --- a/crates/core/src/observability/atif.rs +++ b/crates/core/src/observability/atif.rs @@ -4,7 +4,7 @@ //! Agent Trajectory Interchange Format (ATIF) exporter. //! //! This module provides types and an exporter that collects lifecycle events -//! from the NeMo Flow runtime and converts them into ATIF trajectories conforming +//! from the NeMo Relay runtime and converts them into ATIF trajectories conforming //! to the ATIF v1.6 schema. //! //! # Overview @@ -14,9 +14,9 @@ //! //! # Event-to-Step Mapping //! -//! The core conversion from NeMo Flow events to ATIF steps follows these rules: +//! The core conversion from NeMo Relay events to ATIF steps follows these rules: //! -//! | NeMo Flow Event | ATIF Step | Notes | +//! | NeMo Relay Event | ATIF Step | Notes | //! |-----------------|-------------------------|--------------------------------------| //! | LLM Start | `user` step | Messages extracted from LlmRequest | //! | LLM End | `agent` step | Response content, tool_calls promoted| @@ -306,7 +306,7 @@ impl AtifExporter { } } - /// Return an event subscriber function that records NeMo Flow events. + /// Return an event subscriber function that records NeMo Relay events. /// /// The returned callback can be registered with /// [`register_subscriber`](crate::api::subscriber::register_subscriber). @@ -366,7 +366,7 @@ impl AtifExporter { /// If `input` looks like an `LlmRequest` envelope (`{"content": ..., "headers": ...}`), /// return the inner `content` value. Otherwise return the input unchanged. /// -/// This avoids leaking the NeMo Flow transport wrapper into the trajectory. +/// This avoids leaking the NeMo Relay transport wrapper into the trajectory. fn unwrap_llm_request(input: &Json) -> Json { if let Some(obj) = input.as_object() && obj.contains_key("content") @@ -430,7 +430,7 @@ const TOKEN_USAGE_KNOWN_KEYS: &[&str] = &[ /// Try to extract `AtifMetrics` from a `token_usage` object in the LLM response. /// -/// Supports NeMo Flow `token_usage` and provider-native `usage` payloads. +/// Supports NeMo Relay `token_usage` and provider-native `usage` payloads. /// Populates `extra` with any unknown usage keys (e.g. reasoning_tokens or total_tokens). /// Returns `None` if the response has no recognized token counts. fn extract_metrics(output: &Json) -> Option { @@ -567,7 +567,7 @@ fn extract_user_messages(input: &Json) -> Json { /// "tool_calls": [{ "id": "...", "type": "function", "function": { "name": "...", "arguments": "..." } }] /// ``` /// -/// String `arguments` are parsed into JSON for consistency with NeMo Flow tool events +/// String `arguments` are parsed into JSON for consistency with NeMo Relay tool events /// which always provide parsed arguments. /// /// Returns `None` if there are no tool calls or the structure is unrecognized. @@ -661,7 +661,7 @@ fn compute_final_metrics(steps: &[AtifStep]) -> Option { // AtifStepExtra helpers // --------------------------------------------------------------------------- -/// Build an [`AtifAncestry`] from a NeMo Flow [`Event`]. +/// Build an [`AtifAncestry`] from a NeMo Relay [`Event`]. /// /// `name_map` is a pre-pass uuid → name lookup used to resolve `parent_name`. fn build_ancestry( @@ -884,7 +884,7 @@ impl StepConversionState { start_ts, *event.timestamp(), Some(event.uuid().to_string()), - "nemo_flow", + "nemo_relay", ); self.steps.push(AtifStep { @@ -934,7 +934,7 @@ impl StepConversionState { .tool_call_id() .map(ToOwned::to_owned) .or_else(|| Some(event.uuid().to_string())), - "nemo_flow", + "nemo_relay", ); self.current_agent .push_tool_metadata(build_ancestry(event, &lookups.name_map), invocation); @@ -955,7 +955,7 @@ impl StepConversionState { end_timestamp: None, invocation_id: Some(mark.uuid().to_string()), status: Some("completed".to_string()), - framework: Some("nemo_flow".to_string()), + framework: Some("nemo_relay".to_string()), }), llm_request: None, tool_ancestry: Vec::new(), diff --git a/crates/core/src/observability/atof.rs b/crates/core/src/observability/atof.rs index a51b87245..d1bca1d22 100644 --- a/crates/core/src/observability/atof.rs +++ b/crates/core/src/observability/atof.rs @@ -5,7 +5,7 @@ //! Flow. //! //! The [`AtofExporter`] registers as an event subscriber and writes each -//! canonical NeMo Flow Agent Trajectory Observability Format (ATOF) event as +//! canonical NeMo Relay Agent Trajectory Observability Format (ATOF) event as //! one JSON object per JSONL line. use std::fs::{File, OpenOptions}; @@ -227,7 +227,7 @@ impl AtofExporter { fn default_filename() -> String { format!( - "nemo-flow-events-{}.jsonl", + "nemo-relay-events-{}.jsonl", Utc::now().format("%Y-%m-%d-%H.%M.%S") ) } diff --git a/crates/core/src/observability/mod.rs b/crates/core/src/observability/mod.rs index d7caf2f32..9e0f46dcc 100644 --- a/crates/core/src/observability/mod.rs +++ b/crates/core/src/observability/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Optional observability integrations for NeMo Flow Core. +//! Optional observability integrations for NeMo Relay Core. #[cfg(test)] use std::sync::Mutex; diff --git a/crates/core/src/observability/openinference.rs b/crates/core/src/observability/openinference.rs index 5c3e11ec8..f713219bf 100644 --- a/crates/core/src/observability/openinference.rs +++ b/crates/core/src/observability/openinference.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! OpenInference subscriber support for NeMo Flow. +//! OpenInference subscriber support for NeMo Relay. //! -//! This crate adapts NeMo Flow lifecycle events into OpenInference trace spans: +//! This crate adapts NeMo Relay lifecycle events into OpenInference trace spans: //! //! - scope/tool/LLM `Start` events open spans //! - matching `End` events close spans @@ -13,7 +13,7 @@ //! The public API is intentionally small: //! //! - [`OpenInferenceConfig`] configures the OTLP exporter and OpenInference metadata -//! - [`OpenInferenceSubscriber`] exposes a NeMo Flow [`EventSubscriberFn`] and +//! - [`OpenInferenceSubscriber`] exposes a NeMo Relay [`EventSubscriberFn`] and //! convenience `register` / `deregister` / `force_flush` / `shutdown` methods use std::collections::HashMap; @@ -123,10 +123,10 @@ impl Default for OpenInferenceConfig { endpoint: None, headers: HashMap::new(), resource_attributes: HashMap::new(), - service_name: "nemo-flow".to_string(), + service_name: "nemo-relay".to_string(), service_namespace: None, service_version: None, - instrumentation_scope: "nemo-flow-openinference".to_string(), + instrumentation_scope: "nemo-relay-openinference".to_string(), timeout: Duration::from_secs(3), transport: OtlpTransport::HttpBinary, } @@ -198,7 +198,7 @@ impl OpenInferenceConfig { } } -/// OpenInference-backed NeMo Flow subscriber. +/// OpenInference-backed NeMo Relay subscriber. #[derive(Clone)] pub struct OpenInferenceSubscriber { inner: Arc, @@ -263,12 +263,12 @@ impl OpenInferenceSubscriber { } } - /// Returns the raw NeMo Flow subscriber callback for custom registration flows. + /// Returns the raw NeMo Relay subscriber callback for custom registration flows. pub fn subscriber(&self) -> EventSubscriberFn { Arc::clone(&self.inner.subscriber) } - /// Registers this subscriber globally with the NeMo Flow runtime. + /// Registers this subscriber globally with the NeMo Relay runtime. pub fn register(&self, name: &str) -> Result<()> { register_subscriber(name, self.subscriber()).map_err(Into::into) } @@ -288,7 +288,7 @@ impl OpenInferenceSubscriber { /// Shuts down the underlying tracer provider. /// - /// Call `deregister(...)` first if the subscriber is still registered with NeMo Flow. + /// Call `deregister(...)` first if the subscriber is still registered with NeMo Relay. pub fn shutdown(&self) -> Result<()> { let guard = self.inner.processor.lock().map_err(|_| { OpenInferenceError::Provider("the subscriber state lock was poisoned".to_string()) @@ -573,7 +573,7 @@ impl OpenInferenceEventProcessor { oi::OPENINFERENCE_SPAN_KIND, OpenInferenceSpanKind::Chain, )); - span_attributes.push(KeyValue::new("nemo_flow.mark.orphan", true)); + span_attributes.push(KeyValue::new("nemo_relay.mark.orphan", true)); span.set_attributes(span_attributes); span.end_with_timestamp(timestamp); } @@ -643,7 +643,7 @@ fn start_attributes(event: &Event) -> Vec { if handle_attributes.is_some_and(|attributes| !attributes.is_empty()) { push_serialized( &mut attributes, - "nemo_flow.handle_attributes_json", + "nemo_relay.handle_attributes_json", handle_attributes, ); } @@ -651,7 +651,11 @@ fn start_attributes(event: &Event) -> Vec { .category() .is_none_or(|category| category.as_str() != "llm") { - push_serialized(&mut attributes, "nemo_flow.start.input_json", event.input()); + push_serialized( + &mut attributes, + "nemo_relay.start.input_json", + event.input(), + ); } if event .category() @@ -681,7 +685,11 @@ fn start_attributes(event: &Event) -> Vec { fn end_attributes(event: &Event) -> Vec { let mut attributes = Vec::new(); - push_serialized(&mut attributes, "nemo_flow.end.output_json", event.output()); + push_serialized( + &mut attributes, + "nemo_relay.end.output_json", + event.output(), + ); if let Some((output, mime_type)) = openinference_output_value(event) { attributes.push(KeyValue::new(oi::output::VALUE, output)); attributes.push(KeyValue::new(oi::output::MIME_TYPE, mime_type)); @@ -836,9 +844,9 @@ fn first_u64(usage: &serde_json::Map, keys: &[&str]) -> Option Vec { let handle_attributes = event.attributes(); let mut attributes = vec![ - KeyValue::new("nemo_flow.mark.uuid", event.uuid().to_string()), + KeyValue::new("nemo_relay.mark.uuid", event.uuid().to_string()), KeyValue::new( - "nemo_flow.mark.parent_uuid", + "nemo_relay.mark.parent_uuid", event .parent_uuid() .map(|uuid| uuid.to_string()) @@ -847,13 +855,13 @@ fn mark_attributes(event: &Event) -> Vec { ]; push_serialized( &mut attributes, - "nemo_flow.mark.attributes_json", + "nemo_relay.mark.attributes_json", handle_attributes, ); - push_serialized(&mut attributes, "nemo_flow.mark.data_json", event.data()); + push_serialized(&mut attributes, "nemo_relay.mark.data_json", event.data()); push_serialized( &mut attributes, - "nemo_flow.mark.metadata_json", + "nemo_relay.mark.metadata_json", event.metadata(), ); attributes @@ -865,16 +873,16 @@ fn common_attributes(event: &Event) -> Vec { oi::OPENINFERENCE_SPAN_KIND, openinference_span_kind(semantic_scope_type(event)), ), - KeyValue::new("nemo_flow.uuid", event.uuid().to_string()), + KeyValue::new("nemo_relay.uuid", event.uuid().to_string()), KeyValue::new( - "nemo_flow.parent_uuid", + "nemo_relay.parent_uuid", event .parent_uuid() .map(|uuid| uuid.to_string()) .unwrap_or_default(), ), KeyValue::new( - "nemo_flow.scope_type", + "nemo_relay.scope_type", scope_type_name(semantic_scope_type(event)), ), ]; diff --git a/crates/core/src/observability/otel.rs b/crates/core/src/observability/otel.rs index 96a28b3ee..cd0d58133 100644 --- a/crates/core/src/observability/otel.rs +++ b/crates/core/src/observability/otel.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! OpenTelemetry subscriber support for NeMo Flow. +//! OpenTelemetry subscriber support for NeMo Relay. //! -//! This crate adapts NeMo Flow lifecycle events into OpenTelemetry trace spans: +//! This crate adapts NeMo Relay lifecycle events into OpenTelemetry trace spans: //! //! - scope/tool/LLM `Start` events open spans //! - matching `End` events close spans @@ -13,7 +13,7 @@ //! The public API is intentionally small: //! //! - [`OpenTelemetryConfig`] configures the OTLP exporter and resource metadata -//! - [`OpenTelemetrySubscriber`] exposes a NeMo Flow [`EventSubscriberFn`] and +//! - [`OpenTelemetrySubscriber`] exposes a NeMo Relay [`EventSubscriberFn`] and //! convenience `register` / `deregister` / `force_flush` / `shutdown` methods use std::collections::HashMap; @@ -120,10 +120,10 @@ impl Default for OpenTelemetryConfig { endpoint: None, headers: HashMap::new(), resource_attributes: HashMap::new(), - service_name: "nemo-flow".to_string(), + service_name: "nemo-relay".to_string(), service_namespace: None, service_version: None, - instrumentation_scope: "nemo-flow-otel".to_string(), + instrumentation_scope: "nemo-relay-otel".to_string(), timeout: Duration::from_secs(3), transport: OtlpTransport::HttpBinary, } @@ -196,7 +196,7 @@ impl OpenTelemetryConfig { } } -/// OpenTelemetry-backed NeMo Flow subscriber. +/// OpenTelemetry-backed NeMo Relay subscriber. #[derive(Clone)] pub struct OpenTelemetrySubscriber { inner: Arc, @@ -261,12 +261,12 @@ impl OpenTelemetrySubscriber { } } - /// Returns the raw NeMo Flow subscriber callback for custom registration flows. + /// Returns the raw NeMo Relay subscriber callback for custom registration flows. pub fn subscriber(&self) -> EventSubscriberFn { Arc::clone(&self.inner.subscriber) } - /// Registers this subscriber globally with the NeMo Flow runtime. + /// Registers this subscriber globally with the NeMo Relay runtime. pub fn register(&self, name: &str) -> Result<()> { register_subscriber(name, self.subscriber()).map_err(Into::into) } @@ -286,7 +286,7 @@ impl OpenTelemetrySubscriber { /// Shuts down the underlying tracer provider. /// - /// Call `deregister(...)` first if the subscriber is still registered with NeMo Flow. + /// Call `deregister(...)` first if the subscriber is still registered with NeMo Relay. pub fn shutdown(&self) -> Result<()> { let guard = self.inner.processor.lock().map_err(|_| { OpenTelemetryError::Provider("the subscriber state lock was poisoned".to_string()) @@ -566,7 +566,7 @@ impl OtelEventProcessor { .with_start_time(timestamp) .start_with_context(&self.tracer, &self.parent_context(event)); let mut span_attributes = attributes; - span_attributes.push(KeyValue::new("nemo_flow.mark.orphan", true)); + span_attributes.push(KeyValue::new("nemo_relay.mark.orphan", true)); span.set_attributes(span_attributes); span.end_with_timestamp(timestamp); } @@ -635,37 +635,45 @@ fn start_attributes(event: &Event) -> Vec { let handle_attributes = event.attributes(); push_serialized( &mut attributes, - "nemo_flow.handle_attributes_json", + "nemo_relay.handle_attributes_json", handle_attributes, ); - push_serialized(&mut attributes, "nemo_flow.start.data_json", event.data()); + push_serialized(&mut attributes, "nemo_relay.start.data_json", event.data()); push_serialized( &mut attributes, - "nemo_flow.start.metadata_json", + "nemo_relay.start.metadata_json", event.metadata(), ); - push_serialized(&mut attributes, "nemo_flow.start.input_json", event.input()); + push_serialized( + &mut attributes, + "nemo_relay.start.input_json", + event.input(), + ); attributes } fn end_attributes(event: &Event) -> Vec { let mut attributes = Vec::new(); - push_serialized(&mut attributes, "nemo_flow.end.data_json", event.data()); + push_serialized(&mut attributes, "nemo_relay.end.data_json", event.data()); push_serialized( &mut attributes, - "nemo_flow.end.metadata_json", + "nemo_relay.end.metadata_json", event.metadata(), ); - push_serialized(&mut attributes, "nemo_flow.end.output_json", event.output()); + push_serialized( + &mut attributes, + "nemo_relay.end.output_json", + event.output(), + ); attributes } fn mark_attributes(event: &Event) -> Vec { let handle_attributes = event.attributes(); let mut attributes = vec![ - KeyValue::new("nemo_flow.mark.uuid", event.uuid().to_string()), + KeyValue::new("nemo_relay.mark.uuid", event.uuid().to_string()), KeyValue::new( - "nemo_flow.mark.parent_uuid", + "nemo_relay.mark.parent_uuid", event .parent_uuid() .map(|uuid| uuid.to_string()) @@ -674,13 +682,13 @@ fn mark_attributes(event: &Event) -> Vec { ]; push_serialized( &mut attributes, - "nemo_flow.mark.attributes_json", + "nemo_relay.mark.attributes_json", handle_attributes, ); - push_serialized(&mut attributes, "nemo_flow.mark.data_json", event.data()); + push_serialized(&mut attributes, "nemo_relay.mark.data_json", event.data()); push_serialized( &mut attributes, - "nemo_flow.mark.metadata_json", + "nemo_relay.mark.metadata_json", event.metadata(), ); attributes @@ -688,29 +696,29 @@ fn mark_attributes(event: &Event) -> Vec { fn common_attributes(event: &Event) -> Vec { let mut attributes = vec![ - KeyValue::new("nemo_flow.uuid", event.uuid().to_string()), + KeyValue::new("nemo_relay.uuid", event.uuid().to_string()), KeyValue::new( - "nemo_flow.parent_uuid", + "nemo_relay.parent_uuid", event .parent_uuid() .map(|uuid| uuid.to_string()) .unwrap_or_default(), ), KeyValue::new( - "nemo_flow.scope_type", + "nemo_relay.scope_type", scope_type_name(semantic_scope_type(event)), ), ]; if let Some(model_name) = event.model_name() { attributes.push(KeyValue::new( - "nemo_flow.model_name", + "nemo_relay.model_name", model_name.to_string(), )); } if let Some(tool_call_id) = event.tool_call_id() { attributes.push(KeyValue::new( - "nemo_flow.tool_call_id", + "nemo_relay.tool_call_id", tool_call_id.to_string(), )); } diff --git a/crates/core/src/observability/plugin_component.rs b/crates/core/src/observability/plugin_component.rs index 09e9fd43e..b5ba7c984 100644 --- a/crates/core/src/observability/plugin_component.rs +++ b/crates/core/src/observability/plugin_component.rs @@ -3,7 +3,7 @@ //! Built-in observability plugin component. //! -//! This module packages NeMo Flow's first-party observability exporters behind +//! This module packages NeMo Relay's first-party observability exporters behind //! the shared plugin configuration system. Each exporter section is opt-in: //! omitted sections and sections with `enabled = false` validate but do not //! register subscribers or construct exporters. @@ -1268,7 +1268,7 @@ fn default_atof_mode() -> String { } fn default_agent_name() -> String { - "NeMo Flow".to_string() + "NeMo Relay".to_string() } fn default_agent_version() -> String { @@ -1280,7 +1280,7 @@ fn default_model_name() -> String { } fn default_atif_filename_template() -> String { - "nemo-flow-atif-{session_id}.json".to_string() + "nemo-relay-atif-{session_id}.json".to_string() } fn default_otlp_transport() -> String { @@ -1288,7 +1288,7 @@ fn default_otlp_transport() -> String { } fn default_service_name() -> String { - "nemo-flow".to_string() + "nemo-relay".to_string() } fn default_timeout_millis() -> u64 { diff --git a/crates/core/src/plugin.rs b/crates/core/src/plugin.rs index b1c4d9392..1b48b2676 100644 --- a/crates/core/src/plugin.rs +++ b/crates/core/src/plugin.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Generic plugin infrastructure for NeMo Flow runtimes. +//! Generic plugin infrastructure for NeMo Relay runtimes. //! //! This module owns: //! - config diagnostics and policy enums used by plugin systems @@ -284,7 +284,7 @@ impl PluginRegistration { /// Context provided to plugin handlers during runtime registration. /// /// Each `register_*` call both installs the middleware/subscriber into the -/// NeMo Flow runtime and records the inverse deregistration closure so the host +/// NeMo Relay runtime and records the inverse deregistration closure so the host /// can roll back partial setup on failure. #[derive(Default)] pub struct PluginRegistrationContext { @@ -1097,9 +1097,9 @@ fn plugin_component_totals(config: &PluginConfig) -> HashMap<&str, usize> { fn component_namespace(kind: &str, ordinal: usize, total: usize) -> String { if total > 1 { - format!("__nemo_flow_plugin__{kind}__{ordinal}__") + format!("__nemo_relay_plugin__{kind}__{ordinal}__") } else { - format!("__nemo_flow_plugin__{kind}__") + format!("__nemo_relay_plugin__{kind}__") } } diff --git a/crates/core/src/plugins/mod.rs b/crates/core/src/plugins/mod.rs index f6cae7d7e..de69a84f7 100644 --- a/crates/core/src/plugins/mod.rs +++ b/crates/core/src/plugins/mod.rs @@ -1,6 +1,6 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! First-party plugin implementations for NeMo Flow Core. +//! First-party plugin implementations for NeMo Relay Core. pub mod nemo_guardrails; diff --git a/crates/core/src/plugins/nemo_guardrails/mod.rs b/crates/core/src/plugins/nemo_guardrails/mod.rs index 01af752f3..9a7689d88 100644 --- a/crates/core/src/plugins/nemo_guardrails/mod.rs +++ b/crates/core/src/plugins/nemo_guardrails/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Planned NeMo Guardrails plugin integrations for NeMo Flow Core. +//! Planned NeMo Guardrails plugin integrations for NeMo Relay Core. #[cfg(test)] use std::sync::Mutex; diff --git a/crates/core/src/plugins/nemo_guardrails/plugin_component.rs b/crates/core/src/plugins/nemo_guardrails/plugin_component.rs index 3a4404098..5617a7439 100644 --- a/crates/core/src/plugins/nemo_guardrails/plugin_component.rs +++ b/crates/core/src/plugins/nemo_guardrails/plugin_component.rs @@ -201,7 +201,7 @@ pub struct RequestDefaultsConfig { /// Request-time rail selection for Guardrails generation. /// -/// These are backend request options, not top-level NeMo Flow interception +/// These are backend request options, not top-level NeMo Relay interception /// surfaces. #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] diff --git a/crates/core/src/registry.rs b/crates/core/src/registry.rs index 3712aaf06..2d85c78f0 100644 --- a/crates/core/src/registry.rs +++ b/crates/core/src/registry.rs @@ -4,7 +4,7 @@ //! Priority-sorted named registry. //! //! [`SortedRegistry`] is the backbone data structure for all guardrail and -//! intercept registries in the NeMo Flow runtime. It stores self-describing +//! intercept registries in the NeMo Relay runtime. It stores self-describing //! entries by unique name and provides iteration in ascending priority order, //! with eager re-sorting on every mutation. diff --git a/crates/core/src/shared_runtime.rs b/crates/core/src/shared_runtime.rs index 6f325c597..4ef7cccdf 100644 --- a/crates/core/src/shared_runtime.rs +++ b/crates/core/src/shared_runtime.rs @@ -3,7 +3,7 @@ //! Process-wide runtime ownership guard. //! -//! NeMo Flow does not support multiple bindings claiming the runtime in the +//! NeMo Relay does not support multiple bindings claiming the runtime in the //! same OS process. This module provides a minimal process-wide owner token so //! the first binding (or direct Rust caller) claims ownership and later //! incompatible bindings fail fast instead of silently creating a second @@ -21,9 +21,9 @@ use crate::error::FlowError; use crate::error::Result; #[cfg(not(target_arch = "wasm32"))] -const BINDING_KIND_ENV: &str = "NEMO_FLOW_BINDING_KIND"; +const BINDING_KIND_ENV: &str = "NEMO_RELAY_BINDING_KIND"; #[cfg(not(target_arch = "wasm32"))] -const OWNER_TOKEN_ENV: &str = "NEMO_FLOW_RUNTIME_OWNER"; +const OWNER_TOKEN_ENV: &str = "NEMO_RELAY_RUNTIME_OWNER"; #[cfg(not(target_arch = "wasm32"))] #[derive(Debug, Clone, PartialEq, Eq)] @@ -51,14 +51,14 @@ impl RuntimeOwner { for field in token.split(';') { if let Some(value) = field.strip_prefix("pid=") { pid = Some(value.parse::().map_err(|e| { - FlowError::Internal( - format!("invalid NeMo Flow owner token pid {value:?}: {e}",), - ) + FlowError::Internal(format!( + "invalid NeMo Relay owner token pid {value:?}: {e}", + )) })?); } else if let Some(value) = field.strip_prefix("binding=") { if value.is_empty() { return Err(FlowError::Internal( - "invalid NeMo Flow owner token: binding kind is empty".into(), + "invalid NeMo Relay owner token: binding kind is empty".into(), )); } binding_kind = Some(value.to_string()); @@ -69,13 +69,13 @@ impl RuntimeOwner { Ok(Self { pid: pid.ok_or_else(|| { - FlowError::Internal("invalid NeMo Flow owner token: missing pid".into()) + FlowError::Internal("invalid NeMo Relay owner token: missing pid".into()) })?, binding_kind: binding_kind.ok_or_else(|| { - FlowError::Internal("invalid NeMo Flow owner token: missing binding".into()) + FlowError::Internal("invalid NeMo Relay owner token: missing binding".into()) })?, major_version: version.ok_or_else(|| { - FlowError::Internal("invalid NeMo Flow owner token: missing version".into()) + FlowError::Internal("invalid NeMo Relay owner token: missing version".into()) })?, }) } @@ -127,7 +127,7 @@ fn compatibility_major_version(version: &str) -> Result<&str> { .filter(|value| !value.is_empty() && value.chars().all(|c| c.is_ascii_digit())) .ok_or_else(|| { FlowError::Internal(format!( - "invalid NeMo Flow version {version:?}: expected a semver-compatible major", + "invalid NeMo Relay version {version:?}: expected a semver-compatible major", )) }) } @@ -186,7 +186,7 @@ pub fn initialize_shared_runtime_binding(binding_kind: &str) -> Result<()> { && existing != binding_kind { return Err(FlowError::InvalidArgument(format!( - "NeMo Flow binding identity is already initialized as {existing}; attempted={binding_kind}", + "NeMo Relay binding identity is already initialized as {existing}; attempted={binding_kind}", ))); } let previous = guard.binding_kind.clone(); @@ -236,7 +236,7 @@ pub(crate) fn ensure_process_runtime_owner() -> Result<()> { Ok(()) } Some(existing) => Err(FlowError::InvalidArgument(format!( - "NeMo Flow does not support multiple bindings in one process; existing owner={} attempted={}", + "NeMo Relay does not support multiple bindings in one process; existing owner={} attempted={}", existing, current ))), None => { diff --git a/crates/core/src/stream.rs b/crates/core/src/stream.rs index f4e410cdf..18eeb3264 100644 --- a/crates/core/src/stream.rs +++ b/crates/core/src/stream.rs @@ -33,7 +33,7 @@ use tokio_stream::Stream; use crate::api::event::{BaseEvent, MarkEvent}; use crate::api::llm::LlmHandle; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::runtime::{ScopeStackHandle, current_scope_stack}; use crate::codec::response::AnnotatedLlmResponse; @@ -175,7 +175,7 @@ impl LlmStreamWrapper { } }; if let Some((event, subscribers)) = event_snapshot { - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); } } @@ -207,7 +207,7 @@ impl LlmStreamWrapper { } }; if let Some((event, subscribers)) = event_snapshot { - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); } } } diff --git a/crates/core/tests/coverage/error_tests.rs b/crates/core/tests/coverage/error_tests.rs index 1f95ac44b..ef88ebde9 100644 --- a/crates/core/tests/coverage/error_tests.rs +++ b/crates/core/tests/coverage/error_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for error in the NeMo Flow core crate. +//! Coverage tests for error in the NeMo Relay core crate. use super::*; diff --git a/crates/core/tests/coverage/shared_runtime_tests.rs b/crates/core/tests/coverage/shared_runtime_tests.rs index 42afe812a..3fc034a41 100644 --- a/crates/core/tests/coverage/shared_runtime_tests.rs +++ b/crates/core/tests/coverage/shared_runtime_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for shared runtime in the NeMo Flow core crate. +//! Coverage tests for shared runtime in the NeMo Relay core crate. use super::*; @@ -74,7 +74,7 @@ fn test_conflicting_binding_is_rejected() { let error = initialize_shared_runtime_binding("node").unwrap_err(); let message = error.to_string(); - assert!(message.contains("NeMo Flow does not support multiple bindings in one process")); + assert!(message.contains("NeMo Relay does not support multiple bindings in one process")); assert!(message.contains("existing owner=python@")); assert!(message.contains("attempted=node@")); } @@ -132,7 +132,7 @@ fn test_api_use_rejects_conflicting_owner() { let error = get_handle().unwrap_err(); let message = error.to_string(); - assert!(message.contains("NeMo Flow does not support multiple bindings in one process")); + assert!(message.contains("NeMo Relay does not support multiple bindings in one process")); assert!(message.contains("existing owner=python@")); assert!(message.contains("attempted=rust@")); } @@ -151,7 +151,7 @@ fn test_runtime_owner_parse_and_display_cover_invalid_tokens() { assert!( invalid_pid .to_string() - .contains("invalid NeMo Flow owner token pid") + .contains("invalid NeMo Relay owner token pid") ); let empty_binding = RuntimeOwner::parse("pid=1;binding=;version=1.2.3").unwrap_err(); diff --git a/crates/core/tests/integration/api_surface_tests.rs b/crates/core/tests/integration/api_surface_tests.rs index b65339114..3054be477 100644 --- a/crates/core/tests/integration/api_surface_tests.rs +++ b/crates/core/tests/integration/api_surface_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for api surface in the NeMo Flow core crate. +//! Integration tests for api surface in the NeMo Relay core crate. #![allow(clippy::await_holding_lock)] @@ -10,13 +10,13 @@ use std::sync::{Arc, Mutex}; use chrono::{DateTime, TimeDelta, Utc}; use futures::StreamExt; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::llm::{LlmAttributes, LlmRequest}; -use nemo_flow::api::llm::{ +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::llm::{LlmAttributes, LlmRequest}; +use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmCallParams, LlmStreamCallExecuteParams, llm_call, llm_call_end, llm_call_execute, llm_conditional_execution, llm_request_intercepts, llm_stream_call_execute, }; -use nemo_flow::api::registry::{ +use nemo_relay::api::registry::{ deregister_llm_conditional_execution_guardrail, deregister_llm_execution_intercept, deregister_llm_request_intercept, deregister_llm_sanitize_request_guardrail, deregister_llm_sanitize_response_guardrail, deregister_llm_stream_execution_intercept, @@ -43,23 +43,23 @@ use nemo_flow::api::registry::{ scope_register_tool_request_intercept, scope_register_tool_sanitize_request_guardrail, scope_register_tool_sanitize_response_guardrail, }; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; -use nemo_flow::api::scope::ScopeType; -use nemo_flow::api::scope::{event, pop_scope, push_scope}; -use nemo_flow::api::subscriber::{ +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::scope::ScopeType; +use nemo_relay::api::scope::{event, pop_scope, push_scope}; +use nemo_relay::api::subscriber::{ deregister_subscriber, register_subscriber, scope_deregister_subscriber, scope_register_subscriber, }; -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::api::tool::{ +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::api::tool::{ tool_call, tool_call_end, tool_call_execute, tool_conditional_execution, tool_request_intercepts, }; -use nemo_flow::error::{FlowError, Result}; -use nemo_flow::json::Json; +use nemo_relay::error::{FlowError, Result}; +use nemo_relay::json::Json; use serde_json::{Map, json}; use tokio_stream::Stream; @@ -68,7 +68,7 @@ static TEST_MUTEX: Mutex<()> = Mutex::new(()); fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } fn setup_isolated_thread() { @@ -130,7 +130,7 @@ fn test_manual_lifecycle_timestamp_overrides() { let scope_end = utc_timestamp("2026-01-01T00:00:06.723456Z"); let scope_handle = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("timestamp-scope") .scope_type(ScopeType::Agent) .timestamp(scope_start) @@ -138,7 +138,7 @@ fn test_manual_lifecycle_timestamp_overrides() { ) .unwrap(); event( - nemo_flow::api::scope::EmitMarkEventParams::builder() + nemo_relay::api::scope::EmitMarkEventParams::builder() .name("timestamp-mark") .parent(&scope_handle) .timestamp(mark_timestamp) @@ -146,7 +146,7 @@ fn test_manual_lifecycle_timestamp_overrides() { ) .unwrap(); let tool_handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("timestamp-tool") .args(json!({"x": 1})) .timestamp(tool_start) @@ -154,7 +154,7 @@ fn test_manual_lifecycle_timestamp_overrides() { ) .unwrap(); tool_call_end( - nemo_flow::api::tool::ToolCallEndParams::builder() + nemo_relay::api::tool::ToolCallEndParams::builder() .handle(&tool_handle) .result(json!({"ok": true})) .timestamp(tool_end) @@ -172,7 +172,7 @@ fn test_manual_lifecycle_timestamp_overrides() { ) .unwrap(); llm_call_end( - nemo_flow::api::llm::LlmCallEndParams::builder() + nemo_relay::api::llm::LlmCallEndParams::builder() .handle(&llm_handle) .response(json!({"ok": true})) .timestamp(llm_end) @@ -180,7 +180,7 @@ fn test_manual_lifecycle_timestamp_overrides() { ) .unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_handle.uuid) .timestamp(scope_end) .build(), @@ -221,7 +221,7 @@ fn test_manual_lifecycle_default_end_timestamps_follow_explicit_starts() { let llm_start = utc_timestamp("2099-02-01T00:00:02.333333Z"); let scope_handle = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("default_ts_scope") .scope_type(ScopeType::Agent) .timestamp(scope_start) @@ -229,7 +229,7 @@ fn test_manual_lifecycle_default_end_timestamps_follow_explicit_starts() { ) .unwrap(); let tool_handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("default_ts_tool") .args(json!({"x": 1})) .timestamp(tool_start) @@ -237,7 +237,7 @@ fn test_manual_lifecycle_default_end_timestamps_follow_explicit_starts() { ) .unwrap(); tool_call_end( - nemo_flow::api::tool::ToolCallEndParams::builder() + nemo_relay::api::tool::ToolCallEndParams::builder() .handle(&tool_handle) .result(json!({"ok": true})) .build(), @@ -254,14 +254,14 @@ fn test_manual_lifecycle_default_end_timestamps_follow_explicit_starts() { ) .unwrap(); llm_call_end( - nemo_flow::api::llm::LlmCallEndParams::builder() + nemo_relay::api::llm::LlmCallEndParams::builder() .handle(&llm_handle) .response(json!({"ok": true})) .build(), ) .unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_handle.uuid) .build(), ) @@ -454,7 +454,7 @@ fn test_scope_registry_and_subscriber_wrappers_cover_success_duplicates_and_miss setup_isolated_thread(); let scope = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("scope-registry") .scope_type(ScopeType::Function) .build(), @@ -605,7 +605,7 @@ fn test_scope_registry_and_subscriber_wrappers_cover_success_duplicates_and_miss assert!(!scope_deregister_subscriber(&scope.uuid, "scope-subscriber").unwrap()); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope.uuid) .build(), ) @@ -682,7 +682,7 @@ async fn test_tool_api_emits_sanitized_events_and_covers_error_paths() { .unwrap(); let handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool-api") .args(json!({"value": 1})) .attributes(ToolAttributes::REMOTE) @@ -693,7 +693,7 @@ async fn test_tool_api_emits_sanitized_events_and_covers_error_paths() { ) .unwrap(); tool_call_end( - nemo_flow::api::tool::ToolCallEndParams::builder() + nemo_relay::api::tool::ToolCallEndParams::builder() .handle(&handle) .result(json!({"ok": true})) .data(json!({"phase": "end"})) @@ -754,7 +754,7 @@ async fn test_tool_api_emits_sanitized_events_and_covers_error_paths() { )); assert!(matches!( tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool-api") .args(json!({"value": 3})) .func(noop_tool_exec()) @@ -778,7 +778,7 @@ async fn test_tool_api_emits_sanitized_events_and_covers_error_paths() { let baseline = events.lock().unwrap().len(); assert!(matches!( tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool-api") .args(json!({"value": 4})) .func(failing_tool_exec()) @@ -856,7 +856,7 @@ async fn test_llm_api_emits_sanitized_events_and_covers_error_paths() { ) .unwrap(); llm_call_end( - nemo_flow::api::llm::LlmCallEndParams::builder() + nemo_relay::api::llm::LlmCallEndParams::builder() .handle(&handle) .response(json!({"response": "ok"})) .data(json!({"phase": "end"})) @@ -1260,7 +1260,7 @@ async fn test_llm_stream_api_covers_success_rejection_and_execution_error_paths( drop(failed_events); event( - nemo_flow::api::scope::EmitMarkEventParams::builder() + nemo_relay::api::scope::EmitMarkEventParams::builder() .name("standalone-mark") .data(json!({"seen": true})) .build(), diff --git a/crates/core/tests/integration/codec_tests.rs b/crates/core/tests/integration/codec_tests.rs index fa42c0ae8..12ae1bdda 100644 --- a/crates/core/tests/integration/codec_tests.rs +++ b/crates/core/tests/integration/codec_tests.rs @@ -6,14 +6,14 @@ use serde_json::json; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::request::{ +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::request::{ ContentPart, FunctionCall, FunctionDefinition, GenerationParams, Message, MessageContent, ToolCall, ToolChoice, ToolChoiceFunction, ToolChoiceFunctionName, ToolDefinition, }; -use nemo_flow::codec::traits::LlmCodec; -use nemo_flow::error::Result; +use nemo_relay::codec::traits::LlmCodec; +use nemo_relay::error::Result; // --------------------------------------------------------------------------- // Mock Codec for registry and resolution tests diff --git a/crates/core/tests/integration/context_isolation_tests.rs b/crates/core/tests/integration/context_isolation_tests.rs index 6657a2ff3..18d9a484e 100644 --- a/crates/core/tests/integration/context_isolation_tests.rs +++ b/crates/core/tests/integration/context_isolation_tests.rs @@ -5,13 +5,13 @@ use std::sync::Arc; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ ScopeStack, TASK_SCOPE_STACK, create_scope_stack, current_scope_stack, propagate_scope_to_thread, scope_stack_active, set_thread_scope_stack, sync_thread_scope_stack, task_scope_push, task_scope_remove, task_scope_top, }; -use nemo_flow::api::scope::{ScopeHandle, ScopeType}; -use nemo_flow::error::FlowError; +use nemo_relay::api::scope::{ScopeHandle, ScopeType}; +use nemo_relay::error::FlowError; use uuid::Uuid; /// Two ScopeStackHandles push different scopes → verify independent. diff --git a/crates/core/tests/integration/middleware_tests.rs b/crates/core/tests/integration/middleware_tests.rs index f8b47342a..d741e1ee1 100644 --- a/crates/core/tests/integration/middleware_tests.rs +++ b/crates/core/tests/integration/middleware_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Comprehensive middleware chain tests for the NeMo Flow core runtime. +//! Comprehensive middleware chain tests for the NeMo Relay core runtime. //! //! These tests exercise the middleware pipeline mechanics: priority ordering, //! break_chain short-circuiting, execution intercept middleware chains (next()), @@ -14,13 +14,13 @@ use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{Arc, Mutex}; use futures::StreamExt; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::llm::{ +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmStreamCallExecuteParams, llm_call_execute, llm_request_intercepts, llm_stream_call_execute, }; -use nemo_flow::api::registry::{ +use nemo_relay::api::registry::{ deregister_llm_conditional_execution_guardrail, deregister_llm_execution_intercept, deregister_llm_request_intercept, deregister_llm_stream_execution_intercept, deregister_tool_conditional_execution_guardrail, deregister_tool_execution_intercept, @@ -32,20 +32,20 @@ use nemo_flow::api::registry::{ register_tool_sanitize_request_guardrail, register_tool_sanitize_response_guardrail, scope_register_tool_execution_intercept, scope_register_tool_sanitize_request_guardrail, }; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::runtime::{ LlmExecutionNextFn, LlmJsonStream, LlmStreamExecutionNextFn, ToolExecutionNextFn, }; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; -use nemo_flow::api::scope::{ScopeHandle, ScopeType}; -use nemo_flow::api::scope::{pop_scope, push_scope}; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::api::tool::{ +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::scope::{ScopeHandle, ScopeType}; +use nemo_relay::api::scope::{pop_scope, push_scope}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::tool::{ tool_call, tool_call_end, tool_call_execute, tool_conditional_execution, tool_request_intercepts, }; -use nemo_flow::error::FlowError; +use nemo_relay::error::FlowError; use serde_json::json; // All tests share the global context, so we serialize them. @@ -58,7 +58,7 @@ fn is_scope_event(event: &Event, scope_type: ScopeType, scope_category: ScopeCat fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } /// Helper: create a fresh scope stack on the current thread. @@ -72,7 +72,7 @@ fn setup_isolated_thread() { fn setup_isolated_scope(name: &str) -> ScopeHandle { setup_isolated_thread(); push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name(name) .scope_type(ScopeType::Agent) .build(), @@ -132,7 +132,7 @@ fn test_sanitize_guardrail_priority_ordering() { // Trigger the chain via tool_call (which runs sanitize request guardrails) let _handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("test_tool") .args(json!({})) .build(), @@ -426,7 +426,7 @@ async fn test_execution_intercept_calls_next() { }); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"value": 42})) .func(func) @@ -475,7 +475,7 @@ async fn test_execution_intercept_skips_next() { }); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"value": 42})) .func(func) @@ -545,7 +545,7 @@ async fn test_execution_intercept_chain_ordering() { }); let _ = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -597,7 +597,7 @@ async fn test_execution_intercept_modifies_args() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"original": true})) .func(func) @@ -635,7 +635,7 @@ async fn test_conditional_guardrail_rejects() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -668,7 +668,7 @@ async fn test_conditional_guardrail_allows() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"input": "data"})) .func(func) @@ -712,7 +712,7 @@ async fn test_tool_conditional_guardrail_emits_guardrail_scope() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let allowed = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("safe_tool") .args(json!({"safe": true})) .func(func.clone()) @@ -723,7 +723,7 @@ async fn test_tool_conditional_guardrail_emits_guardrail_scope() { deregister_tool_conditional_execution_guardrail("tool_scope_reject").unwrap(); let allowed = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("safe_tool") .args(json!({"safe": true})) .func(func) @@ -799,7 +799,7 @@ async fn test_conditional_guardrail_first_rejection_wins() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -843,7 +843,7 @@ async fn test_conditional_guardrail_tool_name_filtering() { // Dangerous tool is rejected let func1: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let err = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("dangerous_tool") .args(json!({})) .func(func1) @@ -855,7 +855,7 @@ async fn test_conditional_guardrail_tool_name_filtering() { // Safe tool is allowed let func2: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let ok = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("safe_tool") .args(json!({})) .func(func2) @@ -897,7 +897,7 @@ fn test_scope_local_guardrail_lifecycle() { // Invoke tool call -- guardrail should fire let _tool = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -911,7 +911,7 @@ fn test_scope_local_guardrail_lifecycle() { // Pop scope -- guardrail should be cleaned up pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -919,7 +919,7 @@ fn test_scope_local_guardrail_lifecycle() { // Invoke tool call again -- guardrail should NOT fire let _tool2 = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -956,7 +956,7 @@ async fn test_scope_local_execution_intercept_cleanup() { // Execute -- intercept should fire let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let _ = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -968,7 +968,7 @@ async fn test_scope_local_execution_intercept_cleanup() { // Pop scope pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -977,7 +977,7 @@ async fn test_scope_local_execution_intercept_cleanup() { // Execute again -- intercept should NOT fire let func2: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let _ = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func2) @@ -1050,7 +1050,7 @@ fn test_scope_local_and_global_guardrail_merge_priority() { .unwrap(); let _tool = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -1079,7 +1079,7 @@ fn test_scope_local_and_global_guardrail_merge_priority() { deregister_tool_sanitize_request_guardrail("global_g").unwrap(); deregister_subscriber("merge_observer").unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -1137,7 +1137,7 @@ async fn test_scope_local_and_global_execution_intercept_merge() { }); let _ = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -1162,7 +1162,7 @@ async fn test_scope_local_and_global_execution_intercept_merge() { // Cleanup deregister_tool_execution_intercept("global_exec").unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -1205,7 +1205,7 @@ async fn test_conditional_rejection_prevents_intercepts() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -1260,7 +1260,7 @@ async fn test_conditional_rejection_prevents_execution() { }); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -1334,7 +1334,7 @@ fn test_sanitize_guardrails_pipe_data() { .unwrap(); let _tool = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -1391,7 +1391,7 @@ fn test_response_sanitize_guardrails_pipe() { .unwrap(); let tool_handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -1399,7 +1399,7 @@ fn test_response_sanitize_guardrails_pipe() { .unwrap(); tool_call_end( - nemo_flow::api::tool::ToolCallEndParams::builder() + nemo_relay::api::tool::ToolCallEndParams::builder() .handle(&tool_handle) .result(json!({"raw": true})) .build(), @@ -1554,7 +1554,7 @@ fn test_concurrent_register_and_read() { let stack = create_scope_stack(); set_thread_scope_stack(stack); let _ = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -1664,7 +1664,7 @@ async fn test_full_pipeline_integration() { }); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"data": "test"})) .func(func) @@ -1799,7 +1799,7 @@ fn test_deregister_removes_from_chain() { // First call -- guardrail runs let _ = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -1813,7 +1813,7 @@ fn test_deregister_removes_from_chain() { // Second call -- guardrail should NOT run let _ = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -2338,7 +2338,7 @@ async fn test_empty_chain_passthrough() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"value": "unchanged"})) .func(func) diff --git a/crates/core/tests/integration/pipeline_tests.rs b/crates/core/tests/integration/pipeline_tests.rs index f8e1a48ea..57a192953 100644 --- a/crates/core/tests/integration/pipeline_tests.rs +++ b/crates/core/tests/integration/pipeline_tests.rs @@ -14,25 +14,25 @@ use futures::StreamExt; use serde_json::json; use tokio_stream::Stream; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::llm::{ +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmStreamCallExecuteParams, llm_call_execute, llm_stream_call_execute, }; -use nemo_flow::api::registry::{deregister_llm_request_intercept, register_llm_request_intercept}; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn}; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; -use nemo_flow::api::scope::ScopeType; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::request::MessageContent; -use nemo_flow::codec::response::AnnotatedLlmResponse; -use nemo_flow::codec::response::FinishReason; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::{FlowError, Result}; -use nemo_flow::json::Json; +use nemo_relay::api::registry::{deregister_llm_request_intercept, register_llm_request_intercept}; +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn}; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::scope::ScopeType; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::request::MessageContent; +use nemo_relay::codec::response::AnnotatedLlmResponse; +use nemo_relay::codec::response::FinishReason; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::{FlowError, Result}; +use nemo_relay::json::Json; // --------------------------------------------------------------------------- // Test isolation @@ -47,7 +47,7 @@ fn is_scope_event(event: &Event, scope_type: ScopeType, scope_category: ScopeCat fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } fn setup_isolated_thread() { diff --git a/crates/core/tests/integration/scope_local_tests.rs b/crates/core/tests/integration/scope_local_tests.rs index 34ee4db8f..c82ec3305 100644 --- a/crates/core/tests/integration/scope_local_tests.rs +++ b/crates/core/tests/integration/scope_local_tests.rs @@ -12,24 +12,24 @@ use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Arc, Mutex}; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::registry::{ +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::registry::{ deregister_tool_request_intercept, deregister_tool_sanitize_request_guardrail, register_tool_request_intercept, register_tool_sanitize_request_guardrail, scope_register_tool_conditional_execution_guardrail, scope_register_tool_request_intercept, scope_register_tool_sanitize_request_guardrail, }; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::ToolExecutionNextFn; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack}; -use nemo_flow::api::scope::{ScopeHandle, ScopeType}; -use nemo_flow::api::scope::{pop_scope, push_scope}; -use nemo_flow::api::subscriber::{ +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::ToolExecutionNextFn; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack}; +use nemo_relay::api::scope::{ScopeHandle, ScopeType}; +use nemo_relay::api::scope::{pop_scope, push_scope}; +use nemo_relay::api::subscriber::{ deregister_subscriber, register_subscriber, scope_register_subscriber, }; -use nemo_flow::api::tool::{tool_call, tool_call_end, tool_call_execute}; -use nemo_flow::error::FlowError; +use nemo_relay::api::tool::{tool_call, tool_call_end, tool_call_execute}; +use nemo_relay::error::FlowError; use serde_json::json; // All tests share the global context, so we serialize them. @@ -38,7 +38,7 @@ static TEST_MUTEX: Mutex<()> = Mutex::new(()); fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } /// Helper: create a fresh scope stack on the current thread and push a scope, @@ -47,7 +47,7 @@ fn setup_isolated_scope(name: &str) -> ScopeHandle { let stack = create_scope_stack(); set_thread_scope_stack(stack); push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name(name) .scope_type(ScopeType::Agent) .build(), @@ -97,7 +97,7 @@ fn test_scope_local_guardrail_registration_and_execution() { // Invoke tool_call — the sanitize guardrail runs inside. let tool_handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("test_tool") .args(json!({"input": "data"})) .build(), @@ -114,7 +114,7 @@ fn test_scope_local_guardrail_registration_and_execution() { } tool_call_end( - nemo_flow::api::tool::ToolCallEndParams::builder() + nemo_relay::api::tool::ToolCallEndParams::builder() .handle(&tool_handle) .result(json!("ok")) .build(), @@ -124,7 +124,7 @@ fn test_scope_local_guardrail_registration_and_execution() { // Cleanup deregister_subscriber("sanitize_observer").unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -146,7 +146,7 @@ async fn test_auto_cleanup_on_scope_pop() { set_thread_scope_stack(stack); let handle = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("ephemeral") .scope_type(ScopeType::Function) .build(), @@ -171,7 +171,7 @@ async fn test_auto_cleanup_on_scope_pop() { // Verify it runs before pop. let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"v": 1})) .func(func) @@ -183,7 +183,7 @@ async fn test_auto_cleanup_on_scope_pop() { // Pop the scope — middleware should be cleaned up. pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -192,7 +192,7 @@ async fn test_auto_cleanup_on_scope_pop() { // Now execute again — the field should NOT appear. let func2: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result2 = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({"v": 2})) .func(func2) @@ -271,7 +271,7 @@ async fn test_priority_merge_global_and_scope_local() { let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -293,7 +293,7 @@ async fn test_priority_merge_global_and_scope_local() { deregister_tool_request_intercept("global_p10").unwrap(); deregister_tool_request_intercept("global_p30").unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -343,7 +343,7 @@ fn test_name_coexistence_global_and_scope_local() { // Use tool_call which exercises sanitize guardrails. let _tool_handle = tool_call( - nemo_flow::api::tool::ToolCallParams::builder() + nemo_relay::api::tool::ToolCallParams::builder() .name("tool") .args(json!({})) .build(), @@ -356,7 +356,7 @@ fn test_name_coexistence_global_and_scope_local() { // Cleanup deregister_tool_sanitize_request_guardrail("shared_name").unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -382,7 +382,7 @@ async fn test_scope_isolation_between_stacks() { let scope_a = { set_thread_scope_stack(stack_a.clone()); let s = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("agent_a") .scope_type(ScopeType::Agent) .build(), @@ -408,7 +408,7 @@ async fn test_scope_isolation_between_stacks() { let scope_b = { set_thread_scope_stack(stack_b.clone()); let s = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("agent_b") .scope_type(ScopeType::Agent) .build(), @@ -434,7 +434,7 @@ async fn test_scope_isolation_between_stacks() { set_thread_scope_stack(stack_a.clone()); let func_a: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result_a = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func_a) @@ -448,7 +448,7 @@ async fn test_scope_isolation_between_stacks() { set_thread_scope_stack(stack_b.clone()); let func_b: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result_b = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func_b) @@ -461,14 +461,14 @@ async fn test_scope_isolation_between_stacks() { // Cleanup set_thread_scope_stack(stack_a); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_a.uuid) .build(), ) .unwrap(); set_thread_scope_stack(stack_b); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_b.uuid) .build(), ) @@ -510,7 +510,7 @@ async fn test_nested_scope_inheritance() { // Push scope A with its own request intercept let scope_a = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("scope_a") .scope_type(ScopeType::Agent) .build(), @@ -534,7 +534,7 @@ async fn test_nested_scope_inheritance() { // Push child scope B with its own request intercept let scope_b = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("scope_b") .scope_type(ScopeType::Function) .parent(&scope_a) @@ -560,7 +560,7 @@ async fn test_nested_scope_inheritance() { // Execute within scope B — should see global + scope_a + scope_b let func: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("tool") .args(json!({})) .func(func) @@ -579,13 +579,13 @@ async fn test_nested_scope_inheritance() { // Cleanup pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_b.uuid) .build(), ) .unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope_a.uuid) .build(), ) @@ -624,7 +624,7 @@ fn test_scope_local_subscriber() { // Push a child scope — this emits a Start event let child = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("child") .scope_type(ScopeType::Function) .parent(&handle) @@ -634,7 +634,7 @@ fn test_scope_local_subscriber() { // Pop the child — emits End event pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&child.uuid) .build(), ) @@ -651,7 +651,7 @@ fn test_scope_local_subscriber() { // The End event for this scope is emitted *before* removal, so the // scope-local subscriber sees its own scope's End event as well. pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) @@ -666,14 +666,14 @@ fn test_scope_local_subscriber() { // After pop, push another scope — the subscriber should NOT fire let another = push_scope( - nemo_flow::api::scope::PushScopeParams::builder() + nemo_relay::api::scope::PushScopeParams::builder() .name("after_pop") .scope_type(ScopeType::Function) .build(), ) .unwrap(); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&another.uuid) .build(), ) @@ -715,7 +715,7 @@ async fn test_scope_local_conditional_execution_guardrail() { // Call to banned_tool should be rejected let func_banned: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let err = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("banned_tool") .args(json!({"input": 1})) .func(func_banned) @@ -734,7 +734,7 @@ async fn test_scope_local_conditional_execution_guardrail() { // Call to a different tool should succeed let func_ok: ToolExecutionNextFn = Arc::new(|args| Box::pin(async move { Ok(args) })); let result = tool_call_execute( - nemo_flow::api::tool::ToolCallExecuteParams::builder() + nemo_relay::api::tool::ToolCallExecuteParams::builder() .name("allowed_tool") .args(json!({"input": 2})) .func(func_ok) @@ -746,7 +746,7 @@ async fn test_scope_local_conditional_execution_guardrail() { assert_eq!(result["input"], 2); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&handle.uuid) .build(), ) diff --git a/crates/core/tests/integration/stream_tests.rs b/crates/core/tests/integration/stream_tests.rs index 5cfdba74d..b7d311b4c 100644 --- a/crates/core/tests/integration/stream_tests.rs +++ b/crates/core/tests/integration/stream_tests.rs @@ -1,23 +1,23 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for stream in the NeMo Flow core crate. +//! Integration tests for stream in the NeMo Relay core crate. #![allow(clippy::await_holding_lock)] use std::pin::Pin; use std::sync::{Arc, Mutex}; -use nemo_flow::api::event::{Event, ScopeCategory}; -use nemo_flow::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; -use nemo_flow::api::llm::{LlmCallParams, llm_call}; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::error::FlowError; -use nemo_flow::error::Result; -use nemo_flow::json::Json; -use nemo_flow::stream::LlmStreamWrapper; +use nemo_relay::api::event::{Event, ScopeCategory}; +use nemo_relay::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; +use nemo_relay::api::llm::{LlmCallParams, llm_call}; +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::error::FlowError; +use nemo_relay::error::Result; +use nemo_relay::json::Json; +use nemo_relay::stream::LlmStreamWrapper; use serde_json::json; use tokio_stream::{Stream, StreamExt}; @@ -25,14 +25,14 @@ use tokio_stream::{Stream, StreamExt}; static TEST_MUTEX: Mutex<()> = Mutex::new(()); fn is_llm_end(event: &Event) -> bool { - event.scope_type() == Some(nemo_flow::api::scope::ScopeType::Llm) + event.scope_type() == Some(nemo_relay::api::scope::ScopeType::Llm) && event.scope_category() == Some(ScopeCategory::End) } fn reset_global() { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } fn make_llm_handle(name: &str) -> LlmHandle { diff --git a/crates/core/tests/unit/atif_tests.rs b/crates/core/tests/unit/atif_tests.rs index 193d36b92..2403fb188 100644 --- a/crates/core/tests/unit/atif_tests.rs +++ b/crates/core/tests/unit/atif_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for atif in the NeMo Flow core crate. +//! Unit tests for atif in the NeMo Relay core crate. use super::*; use crate::api::event::{ @@ -1296,7 +1296,7 @@ fn test_step_extra_invocation_timestamps() { // end must be >= start assert!(inv.end_timestamp.unwrap() >= inv.start_timestamp.unwrap()); assert_eq!(inv.invocation_id, Some(llm_uuid.to_string())); - assert_eq!(inv.framework, Some("nemo_flow".to_string())); + assert_eq!(inv.framework, Some("nemo_relay".to_string())); } #[test] diff --git a/crates/core/tests/unit/codec/anthropic_tests.rs b/crates/core/tests/unit/codec/anthropic_tests.rs index b70302437..9fe7d8724 100644 --- a/crates/core/tests/unit/codec/anthropic_tests.rs +++ b/crates/core/tests/unit/codec/anthropic_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for anthropic in the NeMo Flow core crate. +//! Unit tests for anthropic in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/codec/openai_chat_tests.rs b/crates/core/tests/unit/codec/openai_chat_tests.rs index 2f5600253..f54562af1 100644 --- a/crates/core/tests/unit/codec/openai_chat_tests.rs +++ b/crates/core/tests/unit/codec/openai_chat_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for openai chat in the NeMo Flow core crate. +//! Unit tests for openai chat in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/codec/openai_responses_tests.rs b/crates/core/tests/unit/codec/openai_responses_tests.rs index 63837924b..2576c8bab 100644 --- a/crates/core/tests/unit/codec/openai_responses_tests.rs +++ b/crates/core/tests/unit/codec/openai_responses_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for openai responses in the NeMo Flow core crate. +//! Unit tests for openai responses in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/codec/request_tests.rs b/crates/core/tests/unit/codec/request_tests.rs index 48b892a44..c35c60e24 100644 --- a/crates/core/tests/unit/codec/request_tests.rs +++ b/crates/core/tests/unit/codec/request_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for request in the NeMo Flow core crate. +//! Unit tests for request in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/codec/response_tests.rs b/crates/core/tests/unit/codec/response_tests.rs index 36dd51c0a..945f0fc14 100644 --- a/crates/core/tests/unit/codec/response_tests.rs +++ b/crates/core/tests/unit/codec/response_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for response in the NeMo Flow core crate. +//! Unit tests for response in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/codec/streaming_tests.rs b/crates/core/tests/unit/codec/streaming_tests.rs index cb534a9e8..07742c899 100644 --- a/crates/core/tests/unit/codec/streaming_tests.rs +++ b/crates/core/tests/unit/codec/streaming_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for streaming in the NeMo Flow core crate. +//! Unit tests for streaming in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/context_tests.rs b/crates/core/tests/unit/context_tests.rs index 084a7a2c3..281735ea1 100644 --- a/crates/core/tests/unit/context_tests.rs +++ b/crates/core/tests/unit/context_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for context in the NeMo Flow core crate. +//! Unit tests for context in the NeMo Relay core crate. use std::sync::{Arc, Mutex}; @@ -12,7 +12,7 @@ use crate::api::event::Event; use crate::api::llm::LlmRequest; use crate::api::registry::{ExecutionIntercept, Guardrail, Intercept, RequestIntercept}; use crate::api::runtime::EventSubscriberFn; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::ScopeStack; use crate::api::runtime::global_context; use crate::api::scope::{ScopeAttributes, ScopeHandle, ScopeType}; @@ -183,7 +183,7 @@ fn merge_helpers_preserve_global_and_scope_local_priority_order() { #[test] fn conditional_guardrail_snapshots_keep_names_and_callbacks_after_deregister() { - let mut state = NemoFlowContextState::new(); + let mut state = NemoRelayContextState::new(); state .tool_conditional_execution_guardrails .register(Guardrail { @@ -209,7 +209,7 @@ fn conditional_guardrail_snapshots_keep_names_and_callbacks_after_deregister() { }); let subscribers = [subscriber]; - let rejection = NemoFlowContextState::tool_conditional_execution_snapshot_chain( + let rejection = NemoRelayContextState::tool_conditional_execution_snapshot_chain( "snapshot_target", &json!({}), &entries, @@ -229,7 +229,7 @@ fn conditional_guardrail_snapshots_keep_names_and_callbacks_after_deregister() { #[test] fn context_state_supports_extensions_events_and_builders() { - let mut state = NemoFlowContextState::new(); + let mut state = NemoRelayContextState::new(); assert!(state.extensions.is_empty()); let key = format!("ext-{}", Uuid::now_v7()); @@ -299,7 +299,7 @@ fn context_state_supports_extensions_events_and_builders() { )); assert_eq!(event.uuid().get_version(), Some(Version::SortRand)); let subscribers = state.collect_event_subscribers(&[]); - NemoFlowContextState::emit_event(&event, &subscribers); + NemoRelayContextState::emit_event(&event, &subscribers); assert_eq!(events.lock().unwrap().as_slice(), ["mark"]); } diff --git a/crates/core/tests/unit/json_tests.rs b/crates/core/tests/unit/json_tests.rs index cedf1181f..d1fb57ba7 100644 --- a/crates/core/tests/unit/json_tests.rs +++ b/crates/core/tests/unit/json_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for json in the NeMo Flow core crate. +//! Unit tests for json in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/observability/atof_tests.rs b/crates/core/tests/unit/observability/atof_tests.rs index 7e0b10af9..0b66411c2 100644 --- a/crates/core/tests/unit/observability/atof_tests.rs +++ b/crates/core/tests/unit/observability/atof_tests.rs @@ -7,7 +7,7 @@ use super::*; use crate::api::event::{ BaseEvent, CategoryProfile, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, }; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::scope::{EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeType}; use crate::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; @@ -22,7 +22,7 @@ fn temp_dir(prefix: &str) -> PathBuf { .duration_since(UNIX_EPOCH) .unwrap() .as_nanos(); - let path = std::env::temp_dir().join(format!("nemo-flow-{prefix}-{id}")); + let path = std::env::temp_dir().join(format!("nemo-relay-{prefix}-{id}")); fs::create_dir_all(&path).unwrap(); path } @@ -30,7 +30,7 @@ fn temp_dir(prefix: &str) -> PathBuf { fn reset_global() { crate::shared_runtime::reset_runtime_owner_for_tests(); let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } fn make_mark_event(name: &str) -> Event { @@ -117,11 +117,11 @@ fn default_config_uses_cwd_append_and_timestamped_filename() { assert_eq!(config.output_directory, std::env::current_dir().unwrap()); assert_eq!(config.mode, AtofExporterMode::Append); - assert!(config.filename.starts_with("nemo-flow-events-")); + assert!(config.filename.starts_with("nemo-relay-events-")); assert!(config.filename.ends_with(".jsonl")); assert_eq!( config.filename.len(), - "nemo-flow-events-YYYY-MM-DD-HH.MM.SS.jsonl".len() + "nemo-relay-events-YYYY-MM-DD-HH.MM.SS.jsonl".len() ); } diff --git a/crates/core/tests/unit/observability/openinference_tests.rs b/crates/core/tests/unit/observability/openinference_tests.rs index 08e8f15be..0aa83b1cd 100644 --- a/crates/core/tests/unit/observability/openinference_tests.rs +++ b/crates/core/tests/unit/observability/openinference_tests.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for openinference in the NeMo Flow core crate. +//! Unit tests for openinference in the NeMo Relay core crate. use super::*; use crate::api::event::{ BaseEvent, CategoryProfile, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, tool_attributes_to_strings, }; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::scope::ScopeType; use crate::api::scope::{event, pop_scope, push_scope}; @@ -28,7 +28,7 @@ use uuid::Uuid; fn reset_global() { crate::shared_runtime::reset_runtime_owner_for_tests(); let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } fn make_provider() -> ( @@ -279,8 +279,8 @@ fn config_defaults_and_builder_overrides_are_applied() { let defaults = OpenInferenceConfig::default(); assert_eq!(defaults.transport, OtlpTransport::HttpBinary); - assert_eq!(defaults.service_name, "nemo-flow"); - assert_eq!(defaults.instrumentation_scope, "nemo-flow-openinference"); + assert_eq!(defaults.service_name, "nemo-relay"); + assert_eq!(defaults.instrumentation_scope, "nemo-relay-openinference"); assert_eq!(defaults.timeout, Duration::from_secs(3)); assert!(defaults.headers.is_empty()); assert!(defaults.resource_attributes.is_empty()); @@ -380,10 +380,10 @@ fn registered_subscriber_emits_spans_for_scope_push_pop_and_marks() { attributes.get("openinference.span.kind"), Some(&"AGENT".to_string()) ); - assert!(!attributes.contains_key("nemo_flow.start.data_json")); - assert!(!attributes.contains_key("nemo_flow.start.metadata_json")); + assert!(!attributes.contains_key("nemo_relay.start.data_json")); + assert!(!attributes.contains_key("nemo_relay.start.metadata_json")); assert_eq!( - attributes.get("nemo_flow.start.input_json"), + attributes.get("nemo_relay.start.input_json"), Some(&"{\"task\":\"scope-start\"}".to_string()) ); assert_eq!( @@ -401,11 +401,11 @@ fn registered_subscriber_emits_spans_for_scope_push_pop_and_marks() { let event_attributes = attr_map(&span.events.events[0].attributes); assert_eq!( - event_attributes.get("nemo_flow.mark.data_json"), + event_attributes.get("nemo_relay.mark.data_json"), Some(&"{\"step\":1}".to_string()) ); assert_eq!( - event_attributes.get("nemo_flow.mark.metadata_json"), + event_attributes.get("nemo_relay.mark.metadata_json"), Some(&"{\"source\":\"rust-test\"}".to_string()) ); } @@ -504,15 +504,15 @@ fn records_span_start_mark_and_end() { let attributes = attr_map(&span.attributes); assert_eq!( - attributes.get("nemo_flow.uuid"), + attributes.get("nemo_relay.uuid"), Some(&root_uuid.to_string()) ); assert_eq!( - attributes.get("nemo_flow.start.input_json"), + attributes.get("nemo_relay.start.input_json"), Some(&"{\"query\":\"hello\"}".to_string()) ); assert_eq!( - attributes.get("nemo_flow.end.output_json"), + attributes.get("nemo_relay.end.output_json"), Some(&"{\"result\":\"ok\"}".to_string()) ); } @@ -552,7 +552,7 @@ fn llm_input_value_omits_request_headers() { attributes.get("input.mime_type"), Some(&"text/plain".to_string()) ); - assert!(!attributes.contains_key("nemo_flow.start.input_json")); + assert!(!attributes.contains_key("nemo_relay.start.input_json")); assert!(!attributes["input.value"].contains("authorization")); assert!(!attributes["input.value"].contains("secret-token")); } @@ -650,13 +650,13 @@ fn output_value_prefers_display_content() { Some(&"text/plain".to_string()) ); assert_eq!( - attributes.get("nemo_flow.end.output_json"), + attributes.get("nemo_relay.end.output_json"), Some( &"{\"content\":\"Tool edit completed.\",\"details\":{\"diff\":\"-old\\n+new\"}}" .to_string() ) ); - assert!(!attributes.contains_key("nemo_flow.end.data_json")); + assert!(!attributes.contains_key("nemo_relay.end.data_json")); } #[test] @@ -864,15 +864,15 @@ fn atif_lineage_correlates_with_openinference_span_attributes() { let llm_attributes = attr_map(&llm_span.attributes); assert_eq!( - agent_attributes.get("nemo_flow.uuid"), + agent_attributes.get("nemo_relay.uuid"), Some(&agent_uuid.to_string()) ); assert_eq!( - llm_attributes.get("nemo_flow.uuid"), + llm_attributes.get("nemo_relay.uuid"), Some(&llm_uuid.to_string()) ); assert_eq!( - llm_attributes.get("nemo_flow.parent_uuid"), + llm_attributes.get("nemo_relay.parent_uuid"), Some(&agent_uuid.to_string()) ); @@ -886,7 +886,7 @@ fn atif_lineage_correlates_with_openinference_span_attributes() { let extra: AtifStepExtra = serde_json::from_value(agent_step.extra.clone().unwrap()).unwrap(); assert_eq!( - llm_attributes.get("nemo_flow.uuid"), + llm_attributes.get("nemo_relay.uuid"), Some(&extra.ancestry.function_id) ); assert_eq!(extra.ancestry.parent_id, Some(trajectory.session_id)); @@ -910,7 +910,7 @@ fn orphan_marks_become_zero_duration_spans() { let attributes = attr_map(&span.attributes); assert_eq!( - attributes.get("nemo_flow.mark.orphan"), + attributes.get("nemo_relay.mark.orphan"), Some(&"true".to_string()) ); assert_eq!( @@ -1006,7 +1006,7 @@ fn scope_end_output_payload_is_exported_to_openinference_attributes() { ); assert_eq!( serde_json::from_str::( - attributes.get("nemo_flow.end.output_json").unwrap(), + attributes.get("nemo_relay.end.output_json").unwrap(), ) .unwrap(), json!({"status": "done", "metrics": {"tokens": 42}}) @@ -1081,7 +1081,7 @@ fn helper_functions_cover_additional_openinference_branches() { Some(CategoryProfile::builder().model_name("demo-model").build()), )); let llm_attributes = attr_map(&common_attributes(&llm_end)); - assert!(!llm_attributes.contains_key("nemo_flow.model_name")); + assert!(!llm_attributes.contains_key("nemo_relay.model_name")); assert_eq!( llm_attributes.get(oi::llm::MODEL_NAME.as_str()), Some(&"demo-model".to_string()) @@ -1157,11 +1157,11 @@ fn helper_functions_cover_additional_openinference_branches() { )); let mark_attributes = attr_map(&mark_attributes(&mark)); assert_eq!( - mark_attributes.get("nemo_flow.mark.data_json"), + mark_attributes.get("nemo_relay.mark.data_json"), Some(&"{\"kind\":\"aux\"}".to_string()) ); assert_eq!( - mark_attributes.get("nemo_flow.mark.metadata_json"), + mark_attributes.get("nemo_relay.mark.metadata_json"), Some(&"{\"source\":\"unit\"}".to_string()) ); diff --git a/crates/core/tests/unit/observability/otel_tests.rs b/crates/core/tests/unit/observability/otel_tests.rs index 169307ae7..40a85a990 100644 --- a/crates/core/tests/unit/observability/otel_tests.rs +++ b/crates/core/tests/unit/observability/otel_tests.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for otel in the NeMo Flow core crate. +//! Unit tests for otel in the NeMo Relay core crate. use super::*; use crate::api::event::{ BaseEvent, CategoryProfile, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, tool_attributes_to_strings, }; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::scope::ScopeType; use crate::api::scope::{event, pop_scope, push_scope}; @@ -27,7 +27,7 @@ use uuid::Uuid; fn reset_global() { crate::shared_runtime::reset_runtime_owner_for_tests(); let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } fn make_provider() -> ( @@ -277,8 +277,8 @@ fn config_defaults_and_builder_overrides_are_applied() { let defaults = OpenTelemetryConfig::default(); assert_eq!(defaults.transport, OtlpTransport::HttpBinary); - assert_eq!(defaults.service_name, "nemo-flow"); - assert_eq!(defaults.instrumentation_scope, "nemo-flow-otel"); + assert_eq!(defaults.service_name, "nemo-relay"); + assert_eq!(defaults.instrumentation_scope, "nemo-relay-otel"); assert_eq!(defaults.timeout, Duration::from_secs(3)); assert!(defaults.headers.is_empty()); assert!(defaults.resource_attributes.is_empty()); @@ -371,21 +371,21 @@ fn registered_subscriber_emits_spans_for_scope_push_pop_and_marks() { let attributes = attr_map(&span.attributes); assert_eq!( - attributes.get("nemo_flow.start.data_json"), + attributes.get("nemo_relay.start.data_json"), Some(&"{\"task\":\"scope-start\"}".to_string()) ); assert_eq!( - attributes.get("nemo_flow.start.metadata_json"), + attributes.get("nemo_relay.start.metadata_json"), Some(&"{\"phase\":\"start\"}".to_string()) ); let event_attributes = attr_map(&span.events.events[0].attributes); assert_eq!( - event_attributes.get("nemo_flow.mark.data_json"), + event_attributes.get("nemo_relay.mark.data_json"), Some(&"{\"step\":1}".to_string()) ); assert_eq!( - event_attributes.get("nemo_flow.mark.metadata_json"), + event_attributes.get("nemo_relay.mark.metadata_json"), Some(&"{\"source\":\"rust-test\"}".to_string()) ); } @@ -481,15 +481,15 @@ fn records_span_start_mark_and_end() { let attributes = attr_map(&span.attributes); assert_eq!( - attributes.get("nemo_flow.uuid"), + attributes.get("nemo_relay.uuid"), Some(&root_uuid.to_string()) ); assert_eq!( - attributes.get("nemo_flow.start.input_json"), + attributes.get("nemo_relay.start.input_json"), Some(&"{\"query\":\"hello\"}".to_string()) ); assert_eq!( - attributes.get("nemo_flow.end.output_json"), + attributes.get("nemo_relay.end.output_json"), Some(&"{\"result\":\"ok\"}".to_string()) ); } @@ -609,15 +609,15 @@ fn atif_lineage_correlates_with_otel_span_attributes() { let llm_attributes = attr_map(&llm_span.attributes); assert_eq!( - agent_attributes.get("nemo_flow.uuid"), + agent_attributes.get("nemo_relay.uuid"), Some(&agent_uuid.to_string()) ); assert_eq!( - llm_attributes.get("nemo_flow.uuid"), + llm_attributes.get("nemo_relay.uuid"), Some(&llm_uuid.to_string()) ); assert_eq!( - llm_attributes.get("nemo_flow.parent_uuid"), + llm_attributes.get("nemo_relay.parent_uuid"), Some(&agent_uuid.to_string()) ); @@ -631,7 +631,7 @@ fn atif_lineage_correlates_with_otel_span_attributes() { let extra: AtifStepExtra = serde_json::from_value(agent_step.extra.clone().unwrap()).unwrap(); assert_eq!( - llm_attributes.get("nemo_flow.uuid"), + llm_attributes.get("nemo_relay.uuid"), Some(&extra.ancestry.function_id) ); assert_eq!(extra.ancestry.parent_id, Some(trajectory.session_id)); @@ -654,7 +654,7 @@ fn orphan_marks_become_zero_duration_spans() { let attributes = attr_map(&span.attributes); assert_eq!( - attributes.get("nemo_flow.mark.orphan"), + attributes.get("nemo_relay.mark.orphan"), Some(&"true".to_string()) ); } @@ -742,7 +742,7 @@ fn helper_functions_cover_additional_otel_branches() { ); let llm_attributes = attr_map(&common_attributes(&llm_event)); assert_eq!( - llm_attributes.get("nemo_flow.model_name"), + llm_attributes.get("nemo_relay.model_name"), Some(&"demo-model".to_string()) ); @@ -759,17 +759,17 @@ fn helper_functions_cover_additional_otel_branches() { )); let tool_attributes = attr_map(&common_attributes(&tool_event)); assert_eq!( - tool_attributes.get("nemo_flow.tool_call_id"), + tool_attributes.get("nemo_relay.tool_call_id"), Some(&"call-123".to_string()) ); let start_attributes = attr_map(&start_attributes(&tool_event)); assert_eq!( - start_attributes.get("nemo_flow.start.input_json"), + start_attributes.get("nemo_relay.start.input_json"), Some(&"{\"query\":\"hello\"}".to_string()) ); assert_eq!( - start_attributes.get("nemo_flow.start.metadata_json"), + start_attributes.get("nemo_relay.start.metadata_json"), Some(&"{\"meta\":true}".to_string()) ); @@ -785,7 +785,7 @@ fn helper_functions_cover_additional_otel_branches() { Some(CategoryProfile::builder().tool_call_id("call-456").build()), )))); assert_eq!( - end_attributes.get("nemo_flow.end.output_json"), + end_attributes.get("nemo_relay.end.output_json"), Some(&"{\"result\":true}".to_string()) ); @@ -801,11 +801,11 @@ fn helper_functions_cover_additional_otel_branches() { )); let mark_attributes = attr_map(&mark_attributes(&mark)); assert_eq!( - mark_attributes.get("nemo_flow.mark.data_json"), + mark_attributes.get("nemo_relay.mark.data_json"), Some(&"{\"kind\":\"aux\"}".to_string()) ); assert_eq!( - mark_attributes.get("nemo_flow.mark.metadata_json"), + mark_attributes.get("nemo_relay.mark.metadata_json"), Some(&"{\"source\":\"unit\"}".to_string()) ); diff --git a/crates/core/tests/unit/observability/plugin_component_tests.rs b/crates/core/tests/unit/observability/plugin_component_tests.rs index 7a904e0c9..c12f50d66 100644 --- a/crates/core/tests/unit/observability/plugin_component_tests.rs +++ b/crates/core/tests/unit/observability/plugin_component_tests.rs @@ -5,7 +5,7 @@ use super::*; use crate::api::event::{BaseEvent, EventCategory, ScopeEvent}; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::scope::{PopScopeParams, PushScopeParams}; use crate::config_editor::{EditorConfig, EditorFieldKind}; @@ -24,7 +24,7 @@ fn temp_dir(prefix: &str) -> PathBuf { .duration_since(UNIX_EPOCH) .unwrap() .as_nanos(); - let path = std::env::temp_dir().join(format!("nemo-flow-{prefix}-{id}")); + let path = std::env::temp_dir().join(format!("nemo-relay-{prefix}-{id}")); fs::create_dir_all(&path).unwrap(); path } @@ -33,7 +33,7 @@ fn reset_runtime() { let _ = clear_plugin_configuration(); crate::shared_runtime::reset_runtime_owner_for_tests(); let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } fn component(config: Json) -> PluginComponentSpec { @@ -173,15 +173,15 @@ fn default_config_and_component_conversion_cover_public_shape() { let atif = AtifSectionConfig::default(); assert!(!atif.enabled); - assert_eq!(atif.agent_name, "NeMo Flow"); + assert_eq!(atif.agent_name, "NeMo Relay"); assert_eq!(atif.agent_version, env!("CARGO_PKG_VERSION")); assert_eq!(atif.model_name, "unknown"); - assert_eq!(atif.filename_template, "nemo-flow-atif-{session_id}.json"); + assert_eq!(atif.filename_template, "nemo-relay-atif-{session_id}.json"); let otlp = OtlpSectionConfig::default(); assert!(!otlp.enabled); assert_eq!(otlp.transport, "http_binary"); - assert_eq!(otlp.service_name, "nemo-flow"); + assert_eq!(otlp.service_name, "nemo-relay"); assert_eq!(otlp.timeout_millis, 3_000); let generic: PluginComponentSpec = ComponentSpec::new(ObservabilityConfig { @@ -195,7 +195,7 @@ fn default_config_and_component_conversion_cover_public_shape() { assert_eq!(generic.kind, OBSERVABILITY_PLUGIN_KIND); assert!(generic.enabled); assert_eq!(generic.config["version"], json!(1)); - assert_eq!(generic.config["atif"]["agent_name"], json!("NeMo Flow")); + assert_eq!(generic.config["atif"]["agent_name"], json!("NeMo Relay")); } #[cfg(feature = "schema")] @@ -494,7 +494,7 @@ fn atof_enabled_writes_jsonl_and_teardown_flushes() { .keys() .cloned() .collect::>(); - assert_eq!(names, vec!["__nemo_flow_plugin__observability__atof"]); + assert_eq!(names, vec!["__nemo_relay_plugin__observability__atof"]); } let agent = push_agent("atof-agent"); @@ -540,8 +540,8 @@ fn atif_defaults_create_one_file_per_top_level_agent() { pop(&second); clear_plugin_configuration().unwrap(); - let first_path = dir.join(format!("nemo-flow-atif-{}.json", first.uuid)); - let second_path = dir.join(format!("nemo-flow-atif-{}.json", second.uuid)); + let first_path = dir.join(format!("nemo-relay-atif-{}.json", first.uuid)); + let second_path = dir.join(format!("nemo-relay-atif-{}.json", second.uuid)); assert!(first_path.exists()); assert!(second_path.exists()); @@ -550,7 +550,7 @@ fn atif_defaults_create_one_file_per_top_level_agent() { serde_json::from_str(&fs::read_to_string(second_path).unwrap()).unwrap(); assert_eq!(first_json["session_id"], first.uuid.to_string()); - assert_eq!(first_json["agent"]["name"], "NeMo Flow"); + assert_eq!(first_json["agent"]["name"], "NeMo Relay"); assert_eq!(first_json["agent"]["version"], env!("CARGO_PKG_VERSION")); assert_eq!(first_json["agent"]["model_name"], "unknown"); let first_serialized = first_json.to_string(); @@ -616,7 +616,7 @@ fn atif_completed_top_level_agent_is_evicted_after_write() { .unwrap() .observe_scope(&end_event, agent.uuid) .unwrap(); - let path = dir.join(format!("nemo-flow-atif-{}.json", agent.uuid)); + let path = dir.join(format!("nemo-relay-atif-{}.json", agent.uuid)); assert!(!path.exists()); write_atif_file(&pending_write).unwrap(); let scope_subscriber = manager @@ -749,7 +749,7 @@ fn otlp_sections_register_inferred_subscribers_with_full_config() { .keys() .cloned() .collect::>(); - assert!(names.contains(&"__nemo_flow_plugin__observability__opentelemetry".to_string())); - assert!(names.contains(&"__nemo_flow_plugin__observability__openinference".to_string())); + assert!(names.contains(&"__nemo_relay_plugin__observability__opentelemetry".to_string())); + assert!(names.contains(&"__nemo_relay_plugin__observability__openinference".to_string())); clear_plugin_configuration().unwrap(); } diff --git a/crates/core/tests/unit/plugin_tests.rs b/crates/core/tests/unit/plugin_tests.rs index 1335cf748..e5eb7255f 100644 --- a/crates/core/tests/unit/plugin_tests.rs +++ b/crates/core/tests/unit/plugin_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for plugin in the NeMo Flow core crate. +//! Unit tests for plugin in the NeMo Relay core crate. use super::*; use std::sync::Arc; @@ -12,7 +12,7 @@ use serde_json::json; use crate::api::llm::LlmRequest; use crate::api::llm::{llm_conditional_execution, llm_request_intercepts}; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::tool::tool_conditional_execution; use crate::error::FlowError; @@ -57,7 +57,7 @@ fn expect_registration_failed(result: Result<()>, message_fragment: &str) { fn set_conflicting_runtime_owner_for_tests() { unsafe { std::env::set_var( - "NEMO_FLOW_RUNTIME_OWNER", + "NEMO_RELAY_RUNTIME_OWNER", format!( "pid={};binding=python;version={}", std::process::id(), @@ -297,7 +297,7 @@ fn reset_global() { crate::shared_runtime::reset_runtime_owner_for_tests(); let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); clear_plugin_configuration().unwrap(); recorded_names().lock().unwrap().clear(); PARTIAL_FAIL_ROLLBACKS.store(0, Ordering::SeqCst); @@ -596,11 +596,11 @@ fn test_plugin_component_helpers_and_serialization_error_variant() { assert_eq!(totals.get("beta.plugin"), Some(&1)); assert_eq!( component_namespace("alpha.plugin", 1, totals["alpha.plugin"]), - "__nemo_flow_plugin__alpha.plugin__1__" + "__nemo_relay_plugin__alpha.plugin__1__" ); assert_eq!( component_namespace("beta.plugin", 1, totals["beta.plugin"]), - "__nemo_flow_plugin__beta.plugin__" + "__nemo_relay_plugin__beta.plugin__" ); let parse_error = serde_json::from_str::("{").unwrap_err(); @@ -776,8 +776,8 @@ fn test_initialize_plugins_restores_previous_configuration_after_failed_replacem assert_eq!( names, vec![ - "__nemo_flow_plugin__recording.plugin__subscriber", - "__nemo_flow_plugin__recording.plugin__subscriber", + "__nemo_relay_plugin__recording.plugin__subscriber", + "__nemo_relay_plugin__recording.plugin__subscriber", ] ); reset_global(); @@ -840,8 +840,8 @@ fn test_initialize_plugins_skips_disabled_components_and_namespaces_multiple_ins assert_eq!( names, vec![ - "__nemo_flow_plugin__recording.plugin__1__subscriber", - "__nemo_flow_plugin__recording.plugin__2__subscriber", + "__nemo_relay_plugin__recording.plugin__1__subscriber", + "__nemo_relay_plugin__recording.plugin__2__subscriber", ] ); reset_global(); diff --git a/crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs b/crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs index 43039d45e..22e721b49 100644 --- a/crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs +++ b/crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs @@ -4,7 +4,7 @@ //! Unit tests for the planned NeMo Guardrails plugin component contract. use super::*; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::config_editor::{EditorConfig, EditorFieldKind}; #[cfg(feature = "schema")] @@ -20,7 +20,7 @@ fn reset_runtime() { let _ = deregister_nemo_guardrails_component(); crate::shared_runtime::reset_runtime_owner_for_tests(); let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } fn ensure_registered() { diff --git a/crates/core/tests/unit/registry_tests.rs b/crates/core/tests/unit/registry_tests.rs index e2eb64248..3230cd151 100644 --- a/crates/core/tests/unit/registry_tests.rs +++ b/crates/core/tests/unit/registry_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for registry in the NeMo Flow core crate. +//! Unit tests for registry in the NeMo Relay core crate. use super::*; diff --git a/crates/core/tests/unit/shared_tests.rs b/crates/core/tests/unit/shared_tests.rs index d423e06e1..7b9e8edd6 100644 --- a/crates/core/tests/unit/shared_tests.rs +++ b/crates/core/tests/unit/shared_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for shared in the NeMo Flow core crate. +//! Unit tests for shared in the NeMo Relay core crate. use super::*; use std::sync::Arc; @@ -10,7 +10,7 @@ use serde_json::{Map, json}; use crate::api::llm::LlmRequest; use crate::api::registry::{deregister_llm_request_intercept, register_llm_request_intercept}; -use crate::api::runtime::NemoFlowContextState; +use crate::api::runtime::NemoRelayContextState; use crate::api::runtime::global_context; use crate::api::runtime::{create_scope_stack, set_thread_scope_stack}; use crate::api::scope::ScopeType; @@ -75,7 +75,7 @@ fn reset_global() { { let ctx = global_context(); let mut state = ctx.write().unwrap(); - *state = NemoFlowContextState::new(); + *state = NemoRelayContextState::new(); } set_thread_scope_stack(create_scope_stack()); let _ = deregister_llm_request_intercept("shared-none"); diff --git a/crates/core/tests/unit/stream_tests.rs b/crates/core/tests/unit/stream_tests.rs index 5df9de686..52615a1c7 100644 --- a/crates/core/tests/unit/stream_tests.rs +++ b/crates/core/tests/unit/stream_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for stream in the NeMo Flow core crate. +//! Unit tests for stream in the NeMo Relay core crate. use super::*; use serde_json::json; diff --git a/crates/core/tests/unit/types_tests.rs b/crates/core/tests/unit/types_tests.rs index b3d8e1472..464639adb 100644 --- a/crates/core/tests/unit/types_tests.rs +++ b/crates/core/tests/unit/types_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for types in the NeMo Flow core crate. +//! Unit tests for types in the NeMo Relay core crate. use std::sync::Arc; diff --git a/crates/ffi/Cargo.toml b/crates/ffi/Cargo.toml index dfdb67dd9..7c5ba0100 100644 --- a/crates/ffi/Cargo.toml +++ b/crates/ffi/Cargo.toml @@ -2,12 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-ffi" +name = "nemo-relay-ffi" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "C-compatible FFI bindings for integrating NeMo Flow into native applications." +description = "C-compatible FFI bindings for integrating NeMo Relay into native applications." readme = "README.md" [lints] @@ -17,8 +17,8 @@ workspace = true crate-type = ["cdylib", "staticlib", "rlib"] [dependencies] -nemo-flow = { workspace = true, features = ["otel", "openinference"] } -nemo-flow-adaptive = { workspace = true, features = ["redis-backend"] } +nemo-relay = { workspace = true, features = ["otel", "openinference"] } +nemo-relay-adaptive = { workspace = true, features = ["redis-backend"] } chrono = "0.4" libc = "0.2" serde_json = "1" diff --git a/crates/ffi/README.md b/crates/ffi/README.md index e2c533617..3a9085f97 100644 --- a/crates/ffi/README.md +++ b/crates/ffi/README.md @@ -3,21 +3,21 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow-ffi` provides the C-compatible ABI for NeMo Flow. Use it when a +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay-ffi` provides the C-compatible ABI for NeMo Relay. Use it when a native integration or downstream language binding needs direct access to the shared Rust runtime contract. @@ -26,21 +26,21 @@ binding consumes it through CGo. ## Why Use It? -- 🔌 **Expose NeMo Flow to native consumers**: Call the shared Rust runtime from +- 🔌 **Expose NeMo Relay to native consumers**: Call the shared Rust runtime from C-compatible hosts and downstream language bindings. - 🧱 **Build on one ABI**: Keep native integrations aligned with the same scope, middleware, lifecycle event, and observability contract. -- 📦 **Consume a generated C header**: Use the committed `nemo_flow.h` surface +- 📦 **Consume a generated C header**: Use the committed `nemo_relay.h` surface produced by the crate build. - 🚧 **Work source-first**: Use this experimental surface when Rust, Python, and Node.js packages are not the right integration layer. ## What You Get -- ✅ **Exported `nemo_flow_*` symbols**: APIs for scopes, tool calls, LLM calls, +- ✅ **Exported `nemo_relay_*` symbols**: APIs for scopes, tool calls, LLM calls, middleware, subscribers, plugins, observability exporters, and scope stack isolation. -- ✅ **Generated header**: A committed `nemo_flow.h` file for C-compatible +- ✅ **Generated header**: A committed `nemo_relay.h` file for C-compatible consumers. - ✅ **Native library outputs**: Shared and static libraries for platform linking. @@ -54,13 +54,13 @@ binding consumes it through CGo. Build the FFI library from a repository checkout: ```bash -cargo build --release -p nemo-flow-ffi +cargo build --release -p nemo-relay-ffi ``` The generated header is available at: ```text -crates/ffi/nemo_flow.h +crates/ffi/nemo_relay.h ``` Cargo writes the shared and static libraries under `target/release/`. @@ -71,7 +71,7 @@ Include the generated header and link against the release library for your platform: ```c -#include "nemo_flow.h" +#include "nemo_relay.h" ``` Use the FFI surface only when you need a native ABI. Rust, Python, and Node.js @@ -79,4 +79,4 @@ applications should prefer the supported packages for those languages. ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/ffi/build.rs b/crates/ffi/build.rs index 056b4fd96..013b53194 100644 --- a/crates/ffi/build.rs +++ b/crates/ffi/build.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Build script that regenerates the committed `nemo_flow.h` header. +//! Build script that regenerates the committed `nemo_relay.h` header. fn main() { let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -13,6 +13,6 @@ fn main() { .with_config(config) .generate() { - bindings.write_to_file(format!("{crate_dir}/nemo_flow.h")); + bindings.write_to_file(format!("{crate_dir}/nemo_relay.h")); } } diff --git a/crates/ffi/cbindgen.toml b/crates/ffi/cbindgen.toml index 5cfd8732d..f01cc38bf 100644 --- a/crates/ffi/cbindgen.toml +++ b/crates/ffi/cbindgen.toml @@ -2,8 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 language = "C" -header = "/* NeMo Flow C API - Auto-generated by cbindgen. Do not edit. */" -include_guard = "NEMO_FLOW_H" +header = "/* NeMo Relay C API - Auto-generated by cbindgen. Do not edit. */" +include_guard = "NEMO_RELAY_H" no_includes = true sys_includes = ["stdint.h", "stdbool.h", "stddef.h"] style = "both" diff --git a/crates/ffi/nemo_flow.h b/crates/ffi/nemo_relay.h similarity index 63% rename from crates/ffi/nemo_flow.h rename to crates/ffi/nemo_relay.h index 58185bfb0..1d62ec421 100644 --- a/crates/ffi/nemo_flow.h +++ b/crates/ffi/nemo_relay.h @@ -1,7 +1,7 @@ -/* NeMo Flow C API - Auto-generated by cbindgen. Do not edit. */ +/* NeMo Relay C API - Auto-generated by cbindgen. Do not edit. */ -#ifndef NEMO_FLOW_H -#define NEMO_FLOW_H +#ifndef NEMO_RELAY_H +#define NEMO_RELAY_H #include #include @@ -10,104 +10,104 @@ /** * Status codes returned by all FFI functions. * - * Every `extern "C"` function in this library returns an `NemoFlowStatus`. - * On non-`Ok` returns, call [`nemo_flow_last_error`] on the same thread to + * Every `extern "C"` function in this library returns an `NemoRelayStatus`. + * On non-`Ok` returns, call [`nemo_relay_last_error`] on the same thread to * retrieve a human-readable error message. */ -enum NemoFlowStatus { +enum NemoRelayStatus { /** * Operation completed successfully. */ - NEMO_FLOW_STATUS_OK = 0, + NEMO_RELAY_STATUS_OK = 0, /** * A resource with the given name already exists. */ - NEMO_FLOW_STATUS_ALREADY_EXISTS = 1, + NEMO_RELAY_STATUS_ALREADY_EXISTS = 1, /** * The requested resource was not found. */ - NEMO_FLOW_STATUS_NOT_FOUND = 2, + NEMO_RELAY_STATUS_NOT_FOUND = 2, /** * The scope stack is empty (no active scope). */ - NEMO_FLOW_STATUS_SCOPE_STACK_EMPTY = 3, + NEMO_RELAY_STATUS_SCOPE_STACK_EMPTY = 3, /** * A guardrail rejected the operation. */ - NEMO_FLOW_STATUS_GUARDRAIL_REJECTED = 4, + NEMO_RELAY_STATUS_GUARDRAIL_REJECTED = 4, /** * An internal runtime error occurred. */ - NEMO_FLOW_STATUS_INTERNAL = 5, + NEMO_RELAY_STATUS_INTERNAL = 5, /** * A required pointer argument was null. */ - NEMO_FLOW_STATUS_NULL_POINTER = 6, + NEMO_RELAY_STATUS_NULL_POINTER = 6, /** * A JSON string argument could not be parsed. */ - NEMO_FLOW_STATUS_INVALID_JSON = 7, + NEMO_RELAY_STATUS_INVALID_JSON = 7, /** * A C string argument contained invalid UTF-8. */ - NEMO_FLOW_STATUS_INVALID_UTF8 = 8, + NEMO_RELAY_STATUS_INVALID_UTF8 = 8, /** * A function argument had an invalid value (e.g. malformed UUID). */ - NEMO_FLOW_STATUS_INVALID_ARG = 9, + NEMO_RELAY_STATUS_INVALID_ARG = 9, }; -typedef int32_t NemoFlowStatus; +typedef int32_t NemoRelayStatus; /** * The type of scope in the agent execution hierarchy. */ -enum NemoFlowScopeType { +enum NemoRelayScopeType { /** * Top-level agent scope. */ - NEMO_FLOW_SCOPE_TYPE_AGENT = 0, + NEMO_RELAY_SCOPE_TYPE_AGENT = 0, /** * Generic function scope. */ - NEMO_FLOW_SCOPE_TYPE_FUNCTION = 1, + NEMO_RELAY_SCOPE_TYPE_FUNCTION = 1, /** * Tool invocation scope. */ - NEMO_FLOW_SCOPE_TYPE_TOOL = 2, + NEMO_RELAY_SCOPE_TYPE_TOOL = 2, /** * LLM call scope. */ - NEMO_FLOW_SCOPE_TYPE_LLM = 3, + NEMO_RELAY_SCOPE_TYPE_LLM = 3, /** * Retriever scope (e.g., RAG lookup). */ - NEMO_FLOW_SCOPE_TYPE_RETRIEVER = 4, + NEMO_RELAY_SCOPE_TYPE_RETRIEVER = 4, /** * Embedder scope. */ - NEMO_FLOW_SCOPE_TYPE_EMBEDDER = 5, + NEMO_RELAY_SCOPE_TYPE_EMBEDDER = 5, /** * Reranker scope. */ - NEMO_FLOW_SCOPE_TYPE_RERANKER = 6, + NEMO_RELAY_SCOPE_TYPE_RERANKER = 6, /** * Guardrail evaluation scope. */ - NEMO_FLOW_SCOPE_TYPE_GUARDRAIL = 7, + NEMO_RELAY_SCOPE_TYPE_GUARDRAIL = 7, /** * Evaluator scope. */ - NEMO_FLOW_SCOPE_TYPE_EVALUATOR = 8, + NEMO_RELAY_SCOPE_TYPE_EVALUATOR = 8, /** * User-defined custom scope. */ - NEMO_FLOW_SCOPE_TYPE_CUSTOM = 9, + NEMO_RELAY_SCOPE_TYPE_CUSTOM = 9, /** * Unknown or unspecified scope type. */ - NEMO_FLOW_SCOPE_TYPE_UNKNOWN = 10, + NEMO_RELAY_SCOPE_TYPE_UNKNOWN = 10, }; -typedef int32_t NemoFlowScopeType; +typedef int32_t NemoRelayScopeType; /** * Opaque ATIF exporter handle. @@ -122,8 +122,8 @@ typedef struct FfiAtofExporter FfiAtofExporter; /** * Opaque handle carrying both request and response codec trait objects. * - * Created by `nemo_flow_openai_chat_codec_new` (and similar constructors). - * Freed by `nemo_flow_codec_free`. The handle carries two `Arc`s pointing + * Created by `nemo_relay_openai_chat_codec_new` (and similar constructors). + * Freed by `nemo_relay_codec_free`. The handle carries two `Arc`s pointing * to the same underlying codec instance: one for the `LlmCodec` trait and * one for the `LlmResponseCodec` trait. */ @@ -158,12 +158,12 @@ typedef struct FfiOpenTelemetrySubscriber FfiOpenTelemetrySubscriber; * Opaque plugin registration context. * * This wrapper contains a borrowed raw pointer to an - * `nemo_flow::plugin::PluginRegistrationContext`, not an owned heap allocation. + * `nemo_relay::plugin::PluginRegistrationContext`, not an owned heap allocation. * It is only valid for the duration of the plugin registration callback that receives * it. C callers must not store the pointer, use it after the callback returns, or attempt to * free or drop it. * - * There is intentionally no `nemo_flow_plugin_context_free` function because this FFI + * There is intentionally no `nemo_relay_plugin_context_free` function because this FFI * wrapper does not own the underlying registration context. */ typedef struct FfiPluginContext FfiPluginContext; @@ -180,7 +180,7 @@ typedef struct FfiScopeStack FfiScopeStack; /** * Opaque stream handle for consuming LLM streaming responses chunk by chunk. - * Use `nemo_flow_stream_next` to poll and `nemo_flow_stream_free` to release. + * Use `nemo_relay_stream_next` to poll and `nemo_relay_stream_free` to release. */ typedef struct FfiStream FfiStream; @@ -194,138 +194,138 @@ typedef struct FfiThreadScopeStackBinding FfiThreadScopeStackBinding; */ typedef struct FfiToolHandle FfiToolHandle; -typedef struct Option_NemoFlowCollectorCb Option_NemoFlowCollectorCb; +typedef struct Option_NemoRelayCollectorCb Option_NemoRelayCollectorCb; -typedef struct Option_NemoFlowFinalizerCb Option_NemoFlowFinalizerCb; +typedef struct Option_NemoRelayFinalizerCb Option_NemoRelayFinalizerCb; -typedef struct Option_NemoFlowPluginValidateCb Option_NemoFlowPluginValidateCb; +typedef struct Option_NemoRelayPluginValidateCb Option_NemoRelayPluginValidateCb; /** * Callback for LLM execution (default callable). Receives a native JSON C string, * returns the response as a JSON C string. */ -typedef char *(*NemoFlowLlmExecCb)(void *user_data, const char *native_json); +typedef char *(*NemoRelayLlmExecCb)(void *user_data, const char *native_json); /** * Optional destructor for user data passed to callbacks. * Called when the runtime no longer needs the associated callback. */ -typedef void (*NemoFlowFreeFn)(void *user_data); +typedef void (*NemoRelayFreeFn)(void *user_data); /** - * Nullable version of [`NemoFlowCodecDecodeCb`] for use as an optional + * Nullable version of [`NemoRelayCodecDecodeCb`] for use as an optional * parameter in FFI execute functions. Pass null to indicate no codec. */ -typedef char *(*NemoFlowCodecDecodeFn)(void *user_data, const struct FfiLLMRequest *request); +typedef char *(*NemoRelayCodecDecodeFn)(void *user_data, const struct FfiLLMRequest *request); /** - * Nullable version of [`NemoFlowCodecEncodeCb`] for use as an optional + * Nullable version of [`NemoRelayCodecEncodeCb`] for use as an optional * parameter in FFI execute functions. Pass null to indicate no codec. */ -typedef char *(*NemoFlowCodecEncodeFn)(void *user_data, - const char *annotated_json, - const struct FfiLLMRequest *original_request); +typedef char *(*NemoRelayCodecEncodeFn)(void *user_data, + const char *annotated_json, + const struct FfiLLMRequest *original_request); /** * Callback for LLM request sanitization. Receives an `FfiLLMRequest` and returns * a new (possibly modified) `FfiLLMRequest`. Return null to use defaults. */ -typedef struct FfiLLMRequest *(*NemoFlowLlmRequestCb)(void *user_data, - const struct FfiLLMRequest *request); +typedef struct FfiLLMRequest *(*NemoRelayLlmRequestCb)(void *user_data, + const struct FfiLLMRequest *request); /** * Generic JSON-to-JSON callback, used for LLM response sanitization and intercepts. * The returned string must be allocated with `malloc` or equivalent. */ -typedef char *(*NemoFlowJsonCb)(void *user_data, const char *json); +typedef char *(*NemoRelayJsonCb)(void *user_data, const char *json); /** * Callback for LLM conditional execution guardrails. * Returns NULL to allow execution, or an error message string to reject. */ -typedef char *(*NemoFlowLlmConditionalCb)(void *user_data, const struct FfiLLMRequest *request); +typedef char *(*NemoRelayLlmConditionalCb)(void *user_data, const struct FfiLLMRequest *request); /** * C callback type for LLM request intercepts with unified annotated-aware * signature. Receives the intercept name, the opaque `FfiLLMRequest`, and * optionally the annotated request as a JSON C string (null if no Codec * resolved). Writes transformed outputs to `out_request` and - * `out_annotated_json`. Returns `NemoFlowStatus`. + * `out_annotated_json`. Returns `NemoRelayStatus`. */ -typedef NemoFlowStatus (*NemoFlowLlmRequestInterceptCb)(void *user_data, - const char *name, - const struct FfiLLMRequest *request, - const char *annotated_json, - struct FfiLLMRequest **out_request, - char **out_annotated_json); +typedef NemoRelayStatus (*NemoRelayLlmRequestInterceptCb)(void *user_data, + const char *name, + const struct FfiLLMRequest *request, + const char *annotated_json, + struct FfiLLMRequest **out_request, + char **out_annotated_json); /** * Runtime-provided "next" callback for LLM execution middleware chain. * Takes a native JSON C string, returns a response JSON C string. */ -typedef char *(*NemoFlowLlmExecNextFn)(const char *native_json, void *next_ctx); +typedef char *(*NemoRelayLlmExecNextFn)(const char *native_json, void *next_ctx); /** * Callback for LLM execution intercepts with middleware chain support. * Receives native JSON C string plus a `next` callback and its context. */ -typedef char *(*NemoFlowLlmExecInterceptCb)(void *user_data, - const char *native_json, - NemoFlowLlmExecNextFn next_fn, - void *next_ctx); +typedef char *(*NemoRelayLlmExecInterceptCb)(void *user_data, + const char *native_json, + NemoRelayLlmExecNextFn next_fn, + void *next_ctx); /** * Callback for event subscribers. Invoked on each lifecycle event emitted by * the runtime. The `FfiEvent` pointer is only valid for the duration of the call. */ -typedef void (*NemoFlowEventSubscriberCb)(void *user_data, const struct FfiEvent *event); +typedef void (*NemoRelayEventSubscriberCb)(void *user_data, const struct FfiEvent *event); /** * Callback for plugin registration. * Receives plugin config JSON and a plugin context pointer that is * only valid for the duration of the call. */ -typedef NemoFlowStatus (*NemoFlowPluginRegisterCb)(void *user_data, - const char *plugin_config_json, - struct FfiPluginContext *ctx); +typedef NemoRelayStatus (*NemoRelayPluginRegisterCb)(void *user_data, + const char *plugin_config_json, + struct FfiPluginContext *ctx); /** * Callback for tool request/response sanitization guardrails and intercepts. * Receives tool name and arguments as JSON, returns sanitized arguments as JSON. * The returned string must be allocated with `malloc` or equivalent. */ -typedef char *(*NemoFlowToolSanitizeCb)(void *user_data, const char *name, const char *args_json); +typedef char *(*NemoRelayToolSanitizeCb)(void *user_data, const char *name, const char *args_json); /** * Callback for tool conditional execution guardrails. * Receives tool name and arguments as JSON. * Returns NULL to allow execution, or an error message string to reject. */ -typedef char *(*NemoFlowToolConditionalCb)(void *user_data, const char *name, const char *args_json); +typedef char *(*NemoRelayToolConditionalCb)(void *user_data, const char *name, const char *args_json); /** * Runtime-provided "next" callback for tool execution middleware chain. * Call this from an intercept to invoke the next layer (or original function). * `next_ctx` is an opaque pointer managed by the runtime. */ -typedef char *(*NemoFlowToolExecNextFn)(const char *args_json, void *next_ctx); +typedef char *(*NemoRelayToolExecNextFn)(const char *args_json, void *next_ctx); /** * Callback for tool execution intercepts. Receives arguments as JSON plus * a `next` callback and its context. Call `next_fn(args, next_ctx)` to invoke * the next layer in the middleware chain, or return directly to short-circuit. */ -typedef char *(*NemoFlowToolExecInterceptCb)(void *user_data, - const char *args_json, - NemoFlowToolExecNextFn next_fn, - void *next_ctx); +typedef char *(*NemoRelayToolExecInterceptCb)(void *user_data, + const char *args_json, + NemoRelayToolExecNextFn next_fn, + void *next_ctx); /** * Callback for tool execution (default callable). Receives arguments as JSON, * returns result as JSON. The returned string must be allocated with `malloc` * or equivalent. */ -typedef char *(*NemoFlowToolExecCb)(void *user_data, const char *args_json); +typedef char *(*NemoRelayToolExecCb)(void *user_data, const char *args_json); /** * Run the registered tool request intercept chain on the given arguments. @@ -337,37 +337,37 @@ typedef char *(*NemoFlowToolExecCb)(void *user_data, const char *args_json); * - `name`: Tool name (null-terminated C string). * - `args_json`: Tool arguments as a JSON C string. * - `out`: On success, receives the transformed JSON string (caller must free - * with `nemo_flow_string_free`). + * with `nemo_relay_string_free`). * * # Returns - * Returns [`NemoFlowStatus::Ok`] on success and writes the transformed JSON + * Returns [`NemoRelayStatus::Ok`] on success and writes the transformed JSON * string to `out`. * * # Safety * All pointers must be valid. `out` must be non-null. */ -NemoFlowStatus nemo_flow_tool_request_intercepts(const char *name, - const char *args_json, - char **out); +NemoRelayStatus nemo_relay_tool_request_intercepts(const char *name, + const char *args_json, + char **out); /** * Run the registered tool conditional execution guardrail chain. * - * Returns `NemoFlowStatus::Ok` if all guardrails pass, or - * `NemoFlowStatus::GuardrailRejected` if blocked. + * Returns `NemoRelayStatus::Ok` if all guardrails pass, or + * `NemoRelayStatus::GuardrailRejected` if blocked. * * # Parameters * - `name`: Tool name (null-terminated C string). * - `args_json`: Tool arguments as a JSON C string. * * # Returns - * Returns [`NemoFlowStatus::Ok`] when execution is allowed and - * [`NemoFlowStatus::GuardrailRejected`] when a guardrail blocks the call. + * Returns [`NemoRelayStatus::Ok`] when execution is allowed and + * [`NemoRelayStatus::GuardrailRejected`] when a guardrail blocks the call. * * # Safety * All pointers must be valid. */ -NemoFlowStatus nemo_flow_tool_conditional_execution(const char *name, const char *args_json); +NemoRelayStatus nemo_relay_tool_conditional_execution(const char *name, const char *args_json); /** * Run the registered LLM request intercept chain on the given request. @@ -381,44 +381,44 @@ NemoFlowStatus nemo_flow_tool_conditional_execution(const char *name, const char * - `native_json`: The request payload as a JSON C string representing an * `LlmRequest` (`{"headers": {...}, "content": {...}}`). * - `out`: On success, receives the transformed JSON string (caller must free - * with `nemo_flow_string_free`). The output is a serialized `LlmRequest`. + * with `nemo_relay_string_free`). The output is a serialized `LlmRequest`. * * # Returns - * Returns [`NemoFlowStatus::Ok`] on success and writes the transformed + * Returns [`NemoRelayStatus::Ok`] on success and writes the transformed * serialized request to `out`. * * # Safety * All pointers must be valid. `out` must be non-null. */ -NemoFlowStatus nemo_flow_llm_request_intercepts(const char *name, - const char *native_json, - char **out); +NemoRelayStatus nemo_relay_llm_request_intercepts(const char *name, + const char *native_json, + char **out); /** * Run the registered LLM conditional execution guardrail chain. * - * Returns `NemoFlowStatus::Ok` if all guardrails pass, or - * `NemoFlowStatus::GuardrailRejected` if blocked. + * Returns `NemoRelayStatus::Ok` if all guardrails pass, or + * `NemoRelayStatus::GuardrailRejected` if blocked. * * # Parameters * - `native_json`: The request payload as a JSON C string representing an * `LlmRequest` (`{"headers": {...}, "content": {...}}`). * * # Returns - * Returns [`NemoFlowStatus::Ok`] when execution is allowed and - * [`NemoFlowStatus::GuardrailRejected`] when a guardrail blocks the call. + * Returns [`NemoRelayStatus::Ok`] when execution is allowed and + * [`NemoRelayStatus::GuardrailRejected`] when a guardrail blocks the call. * * # Safety * All pointers must be valid. */ -NemoFlowStatus nemo_flow_llm_conditional_execution(const char *native_json); +NemoRelayStatus nemo_relay_llm_conditional_execution(const char *native_json); /** * Begin a manual LLM call lifecycle span. * * This emits an LLM Start event after applying sanitize-request guardrails to * the observability payload. Request and execution intercepts only run through - * `nemo_flow_llm_call_execute`. + * `nemo_relay_llm_call_execute`. * * # Parameters * - `name`: Null-terminated LLM provider name. @@ -437,7 +437,7 @@ NemoFlowStatus nemo_flow_llm_conditional_execution(const char *native_json); * - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the * handle start time and start event, or null to use the current UTC time. * - `out`: On success, receives a heap-allocated `FfiLLMHandle` that must be - * freed with `nemo_flow_llm_handle_free`. + * freed with `nemo_relay_llm_handle_free`. * * # Errors * Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -448,25 +448,25 @@ NemoFlowStatus nemo_flow_llm_conditional_execution(const char *native_json); * pointer arguments may be null; when non-null, they must be valid for reads * for the duration of the call. */ -NemoFlowStatus nemo_flow_llm_call(const char *name, - const char *native_json, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - const char *model_name, - const int64_t *timestamp_unix_micros, - struct FfiLLMHandle **out); +NemoRelayStatus nemo_relay_llm_call(const char *name, + const char *native_json, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + const char *model_name, + const int64_t *timestamp_unix_micros, + struct FfiLLMHandle **out); /** * End a manual LLM call lifecycle span. * * This emits an LLM End event after applying sanitize-response guardrails to * the observability payload. Response intercepts only run through - * `nemo_flow_llm_call_execute`. + * `nemo_relay_llm_call_execute`. * * # Parameters - * - `handle`: The LLM handle from `nemo_flow_llm_call`. + * - `handle`: The LLM handle from `nemo_relay_llm_call`. * - `response_json`: LLM response as a null-terminated JSON C string. This * response becomes the end-event data after sanitize-response guardrails * unless it sanitizes to JSON null. @@ -486,44 +486,44 @@ NemoFlowStatus nemo_flow_llm_call(const char *name, * pointer arguments may be null; when non-null, they must be valid for reads * for the duration of the call. */ -NemoFlowStatus nemo_flow_llm_call_end(const struct FfiLLMHandle *handle, - const char *response_json, - const char *data_json, - const char *metadata_json, - const int64_t *timestamp_unix_micros); +NemoRelayStatus nemo_relay_llm_call_end(const struct FfiLLMHandle *handle, + const char *response_json, + const char *data_json, + const char *metadata_json, + const int64_t *timestamp_unix_micros); /** * Create a new OpenAI Chat Completions codec handle. * * The returned handle implements both request codec (decode/encode) and - * response codec (decode_response). Free with `nemo_flow_codec_free`. + * response codec (decode_response). Free with `nemo_relay_codec_free`. * * # Safety - * Caller must free the returned handle via `nemo_flow_codec_free`. + * Caller must free the returned handle via `nemo_relay_codec_free`. */ -struct FfiCodecHandle *nemo_flow_openai_chat_codec_new(void); +struct FfiCodecHandle *nemo_relay_openai_chat_codec_new(void); /** * Create a new OpenAI Responses API codec handle. * * The returned handle implements both request codec (decode/encode) and - * response codec (decode_response). Free with `nemo_flow_codec_free`. + * response codec (decode_response). Free with `nemo_relay_codec_free`. * * # Safety - * Caller must free the returned handle via `nemo_flow_codec_free`. + * Caller must free the returned handle via `nemo_relay_codec_free`. */ -struct FfiCodecHandle *nemo_flow_openai_responses_codec_new(void); +struct FfiCodecHandle *nemo_relay_openai_responses_codec_new(void); /** * Create a new Anthropic Messages API codec handle. * * The returned handle implements both request codec (decode/encode) and - * response codec (decode_response). Free with `nemo_flow_codec_free`. + * response codec (decode_response). Free with `nemo_relay_codec_free`. * * # Safety - * Caller must free the returned handle via `nemo_flow_codec_free`. + * Caller must free the returned handle via `nemo_relay_codec_free`. */ -struct FfiCodecHandle *nemo_flow_anthropic_messages_codec_new(void); +struct FfiCodecHandle *nemo_relay_anthropic_messages_codec_new(void); /** * Execute an LLM call end-to-end: run conditional-execution guardrails (on raw @@ -546,32 +546,32 @@ struct FfiCodecHandle *nemo_flow_anthropic_messages_codec_new(void); * - `metadata_json`: Optional JSON metadata, or null. * - `model_name`: Optional LLM model identifier, or null. * - `out`: On success, receives the response as a JSON C string. Caller must - * free with `nemo_flow_string_free`. + * free with `nemo_relay_string_free`. * * # Safety * `name`, `native_json`, and `out` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_llm_call_execute(const char *name, - const char *native_json, - NemoFlowLlmExecCb func, - void *func_user_data, - NemoFlowFreeFn func_free, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - const char *model_name, - NemoFlowCodecDecodeFn codec_decode, - NemoFlowCodecEncodeFn codec_encode, - void *codec_user_data, - NemoFlowFreeFn codec_free_fn, - const struct FfiCodecHandle *response_codec, - char **out); +NemoRelayStatus nemo_relay_llm_call_execute(const char *name, + const char *native_json, + NemoRelayLlmExecCb func, + void *func_user_data, + NemoRelayFreeFn func_free, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + const char *model_name, + NemoRelayCodecDecodeFn codec_decode, + NemoRelayCodecEncodeFn codec_encode, + void *codec_user_data, + NemoRelayFreeFn codec_free_fn, + const struct FfiCodecHandle *response_codec, + char **out); /** * Execute a streaming LLM call end-to-end. Conditional-execution guardrails * run first on the raw request. Returns a stream handle that can be polled - * with `nemo_flow_stream_next`. Blocks until the stream is set up. + * with `nemo_relay_stream_next`. Blocks until the stream is set up. * * # Parameters * - `name`: Null-terminated LLM provider name. @@ -596,24 +596,24 @@ NemoFlowStatus nemo_flow_llm_call_execute(const char *name, * `name`, `native_json`, and `out` must be valid, non-null pointers. `collector` * and `finalizer` may be null. */ -NemoFlowStatus nemo_flow_llm_stream_call_execute(const char *name, - const char *native_json, - NemoFlowLlmExecCb func, - void *func_user_data, - NemoFlowFreeFn func_free, - struct Option_NemoFlowCollectorCb collector, - struct Option_NemoFlowFinalizerCb finalizer, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - const char *model_name, - NemoFlowCodecDecodeFn codec_decode, - NemoFlowCodecEncodeFn codec_encode, - void *codec_user_data, - NemoFlowFreeFn codec_free_fn, - const struct FfiCodecHandle *response_codec, - struct FfiStream **out); +NemoRelayStatus nemo_relay_llm_stream_call_execute(const char *name, + const char *native_json, + NemoRelayLlmExecCb func, + void *func_user_data, + NemoRelayFreeFn func_free, + struct Option_NemoRelayCollectorCb collector, + struct Option_NemoRelayFinalizerCb finalizer, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + const char *model_name, + NemoRelayCodecDecodeFn codec_decode, + NemoRelayCodecEncodeFn codec_encode, + void *codec_user_data, + NemoRelayFreeFn codec_free_fn, + const struct FfiCodecHandle *response_codec, + struct FfiStream **out); /** * Poll the next chunk from a streaming LLM response. Blocks until a chunk is @@ -621,23 +621,23 @@ NemoFlowStatus nemo_flow_llm_stream_call_execute(const char *name, * * # Returns * - `1`: A chunk was written to `*out_chunk`. Caller must free with - * `nemo_flow_string_free`. + * `nemo_relay_string_free`. * - `0`: The stream is complete (no more chunks). - * - `-1`: An error occurred. Call `nemo_flow_last_error` for details. + * - `-1`: An error occurred. Call `nemo_relay_last_error` for details. * * # Safety * `stream` and `out_chunk` must be valid, non-null pointers. */ -int32_t nemo_flow_stream_next(struct FfiStream *stream, char **out_chunk); +int32_t nemo_relay_stream_next(struct FfiStream *stream, char **out_chunk); /** * Free a stream handle and release its resources. * * # Safety * `stream` must be a valid `FfiStream` pointer returned by - * `nemo_flow_llm_stream_call_execute`, or null. + * `nemo_relay_llm_stream_call_execute`, or null. */ -void nemo_flow_stream_free(struct FfiStream *stream); +void nemo_relay_stream_free(struct FfiStream *stream); /** * Register an LLM request sanitization guardrail. The callback can modify or @@ -653,11 +653,11 @@ void nemo_flow_stream_free(struct FfiStream *stream); * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_llm_sanitize_request_guardrail(const char *name, - int32_t priority, - NemoFlowLlmRequestCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_llm_sanitize_request_guardrail(const char *name, + int32_t priority, + NemoRelayLlmRequestCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister an LLM request sanitization guardrail by name. @@ -665,7 +665,7 @@ NemoFlowStatus nemo_flow_register_llm_sanitize_request_guardrail(const char *nam * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_sanitize_request_guardrail(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_sanitize_request_guardrail(const char *name); /** * Register an LLM response sanitization guardrail. The callback can inspect @@ -681,11 +681,11 @@ NemoFlowStatus nemo_flow_deregister_llm_sanitize_request_guardrail(const char *n * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_llm_sanitize_response_guardrail(const char *name, - int32_t priority, - NemoFlowJsonCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_llm_sanitize_response_guardrail(const char *name, + int32_t priority, + NemoRelayJsonCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister an LLM response sanitization guardrail by name. @@ -693,7 +693,7 @@ NemoFlowStatus nemo_flow_register_llm_sanitize_response_guardrail(const char *na * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_sanitize_response_guardrail(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_sanitize_response_guardrail(const char *name); /** * Register an LLM conditional execution guardrail. The callback decides @@ -707,17 +707,17 @@ NemoFlowStatus nemo_flow_deregister_llm_sanitize_response_guardrail(const char * * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal an internal callback failure instead of - * allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C + * allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C * and return null. * * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_llm_conditional_execution_guardrail(const char *name, - int32_t priority, - NemoFlowLlmConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_llm_conditional_execution_guardrail(const char *name, + int32_t priority, + NemoRelayLlmConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister an LLM conditional execution guardrail by name. @@ -725,7 +725,7 @@ NemoFlowStatus nemo_flow_register_llm_conditional_execution_guardrail(const char * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_conditional_execution_guardrail(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_conditional_execution_guardrail(const char *name); /** * Register an LLM request intercept. The callback can transform the @@ -740,17 +740,17 @@ NemoFlowStatus nemo_flow_deregister_llm_conditional_execution_guardrail(const ch * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal failure, call - * [`crate::error::nemo_flow_set_last_error_message`] from C and return null. + * [`crate::error::nemo_relay_set_last_error_message`] from C and return null. * * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_llm_request_intercept(const char *name, - int32_t priority, - bool break_chain, - NemoFlowLlmRequestInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_llm_request_intercept(const char *name, + int32_t priority, + bool break_chain, + NemoRelayLlmRequestInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister an LLM request intercept by name. @@ -758,7 +758,7 @@ NemoFlowStatus nemo_flow_register_llm_request_intercept(const char *name, * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_request_intercept(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_request_intercept(const char *name); /** * Register an LLM execution intercept following the middleware chain pattern. @@ -776,11 +776,11 @@ NemoFlowStatus nemo_flow_deregister_llm_request_intercept(const char *name); * # Safety * `name` must be a valid C string. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_register_llm_execution_intercept(const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_register_llm_execution_intercept(const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister an LLM execution intercept by name. @@ -788,7 +788,7 @@ NemoFlowStatus nemo_flow_register_llm_execution_intercept(const char *name, * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_execution_intercept(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_execution_intercept(const char *name); /** * Register an LLM streaming execution intercept following the middleware chain @@ -806,11 +806,11 @@ NemoFlowStatus nemo_flow_deregister_llm_execution_intercept(const char *name); * # Safety * `name` must be a valid C string. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_register_llm_stream_execution_intercept(const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_register_llm_stream_execution_intercept(const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister an LLM streaming execution intercept by name. @@ -818,7 +818,7 @@ NemoFlowStatus nemo_flow_register_llm_stream_execution_intercept(const char *nam * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_llm_stream_execution_intercept(const char *name); +NemoRelayStatus nemo_relay_deregister_llm_stream_execution_intercept(const char *name); /** * Register an event subscriber. The callback is invoked for every lifecycle @@ -833,10 +833,10 @@ NemoFlowStatus nemo_flow_deregister_llm_stream_execution_intercept(const char *n * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_subscriber(const char *name, - NemoFlowEventSubscriberCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_subscriber(const char *name, + NemoRelayEventSubscriberCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister an event subscriber by name. @@ -844,14 +844,14 @@ NemoFlowStatus nemo_flow_register_subscriber(const char *name, * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_subscriber(const char *name); +NemoRelayStatus nemo_relay_deregister_subscriber(const char *name); /** * Return the built-in observability plugin kind. * - * The caller owns the returned string and must free it with `nemo_flow_string_free`. + * The caller owns the returned string and must free it with `nemo_relay_string_free`. */ -char *nemo_flow_observability_plugin_kind(void); +char *nemo_relay_observability_plugin_kind(void); /** * Return the default observability plugin config as JSON. @@ -859,7 +859,7 @@ char *nemo_flow_observability_plugin_kind(void); * # Safety * `out_json` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_observability_default_config_json(char **out_json); +NemoRelayStatus nemo_relay_observability_default_config_json(char **out_json); /** * Wrap an observability config JSON object as a top-level plugin component. @@ -871,9 +871,9 @@ NemoFlowStatus nemo_flow_observability_default_config_json(char **out_json); * `config_json`, when non-null, must be a valid C string. `out_json` must be a * valid, non-null pointer. */ -NemoFlowStatus nemo_flow_observability_component_spec_json(const char *config_json, - bool enabled, - char **out_json); +NemoRelayStatus nemo_relay_observability_component_spec_json(const char *config_json, + bool enabled, + char **out_json); /** * Creates a new ATIF exporter. @@ -888,11 +888,11 @@ NemoFlowStatus nemo_flow_observability_component_spec_json(const char *config_js * # Safety * All non-null string pointers must be valid C strings. `out` must be valid. */ -NemoFlowStatus nemo_flow_atif_exporter_create(const char *session_id, - const char *agent_name, - const char *agent_version, - const char *model_name, - struct FfiAtifExporter **out); +NemoRelayStatus nemo_relay_atif_exporter_create(const char *session_id, + const char *agent_name, + const char *agent_version, + const char *model_name, + struct FfiAtifExporter **out); /** * Registers the exporter as an event subscriber. @@ -904,8 +904,8 @@ NemoFlowStatus nemo_flow_atif_exporter_create(const char *session_id, * # Safety * `exporter` and `name` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_atif_exporter_register(const struct FfiAtifExporter *exporter, - const char *name); +NemoRelayStatus nemo_relay_atif_exporter_register(const struct FfiAtifExporter *exporter, + const char *name); /** * Deregisters the exporter subscriber. @@ -916,7 +916,7 @@ NemoFlowStatus nemo_flow_atif_exporter_register(const struct FfiAtifExporter *ex * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_atif_exporter_deregister(const char *name); +NemoRelayStatus nemo_relay_atif_exporter_deregister(const char *name); /** * Exports collected events as an ATIF trajectory JSON string. @@ -924,12 +924,12 @@ NemoFlowStatus nemo_flow_atif_exporter_deregister(const char *name); * # Parameters * - `exporter`: The exporter handle. * - `out`: On success, receives a JSON string (caller must free with - * `nemo_flow_string_free`). + * `nemo_relay_string_free`). * * # Safety * `exporter` and `out` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_atif_exporter_export(const struct FfiAtifExporter *exporter, char **out); +NemoRelayStatus nemo_relay_atif_exporter_export(const struct FfiAtifExporter *exporter, char **out); /** * Clears all collected events from the exporter. @@ -940,7 +940,7 @@ NemoFlowStatus nemo_flow_atif_exporter_export(const struct FfiAtifExporter *expo * # Safety * `exporter` must be a valid, non-null `FfiAtifExporter` pointer. */ -NemoFlowStatus nemo_flow_atif_exporter_clear(const struct FfiAtifExporter *exporter); +NemoRelayStatus nemo_relay_atif_exporter_clear(const struct FfiAtifExporter *exporter); /** * Creates a new filesystem-backed ATOF JSONL exporter. @@ -954,10 +954,10 @@ NemoFlowStatus nemo_flow_atif_exporter_clear(const struct FfiAtifExporter *expor * # Safety * All non-null string pointers must be valid C strings. `out` must be valid. */ -NemoFlowStatus nemo_flow_atof_exporter_create(const char *output_directory, - const char *mode, - const char *filename, - struct FfiAtofExporter **out); +NemoRelayStatus nemo_relay_atof_exporter_create(const char *output_directory, + const char *mode, + const char *filename, + struct FfiAtofExporter **out); /** * Registers the ATOF exporter as an event subscriber. @@ -965,8 +965,8 @@ NemoFlowStatus nemo_flow_atof_exporter_create(const char *output_directory, * # Safety * `exporter` and `name` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_atof_exporter_register(const struct FfiAtofExporter *exporter, - const char *name); +NemoRelayStatus nemo_relay_atof_exporter_register(const struct FfiAtofExporter *exporter, + const char *name); /** * Deregisters the ATOF exporter subscriber. @@ -974,7 +974,7 @@ NemoFlowStatus nemo_flow_atof_exporter_register(const struct FfiAtofExporter *ex * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_atof_exporter_deregister(const char *name); +NemoRelayStatus nemo_relay_atof_exporter_deregister(const char *name); /** * Flushes the ATOF exporter output file. @@ -982,7 +982,7 @@ NemoFlowStatus nemo_flow_atof_exporter_deregister(const char *name); * # Safety * `exporter` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_atof_exporter_force_flush(const struct FfiAtofExporter *exporter); +NemoRelayStatus nemo_relay_atof_exporter_force_flush(const struct FfiAtofExporter *exporter); /** * Shuts down the ATOF exporter by flushing output. @@ -990,7 +990,7 @@ NemoFlowStatus nemo_flow_atof_exporter_force_flush(const struct FfiAtofExporter * # Safety * `exporter` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_atof_exporter_shutdown(const struct FfiAtofExporter *exporter); +NemoRelayStatus nemo_relay_atof_exporter_shutdown(const struct FfiAtofExporter *exporter); /** * Returns the ATOF exporter output path as a string. @@ -998,7 +998,7 @@ NemoFlowStatus nemo_flow_atof_exporter_shutdown(const struct FfiAtofExporter *ex * # Safety * `exporter` and `out` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_atof_exporter_path(const struct FfiAtofExporter *exporter, char **out); +NemoRelayStatus nemo_relay_atof_exporter_path(const struct FfiAtofExporter *exporter, char **out); /** * Creates a new OpenTelemetry subscriber. @@ -1010,16 +1010,16 @@ NemoFlowStatus nemo_flow_atof_exporter_path(const struct FfiAtofExporter *export * # Safety * Any non-null C strings must be valid and `out` must be non-null. */ -NemoFlowStatus nemo_flow_otel_subscriber_create(const char *transport, - const char *endpoint, - const char *headers_json, - const char *resource_attributes_json, - const char *service_name, - const char *service_namespace, - const char *service_version, - const char *instrumentation_scope, - uint64_t timeout_millis, - struct FfiOpenTelemetrySubscriber **out); +NemoRelayStatus nemo_relay_otel_subscriber_create(const char *transport, + const char *endpoint, + const char *headers_json, + const char *resource_attributes_json, + const char *service_name, + const char *service_namespace, + const char *service_version, + const char *instrumentation_scope, + uint64_t timeout_millis, + struct FfiOpenTelemetrySubscriber **out); /** * Registers the OpenTelemetry subscriber as an event subscriber. @@ -1027,8 +1027,8 @@ NemoFlowStatus nemo_flow_otel_subscriber_create(const char *transport, * # Safety * `subscriber` and `name` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_otel_subscriber_register(const struct FfiOpenTelemetrySubscriber *subscriber, - const char *name); +NemoRelayStatus nemo_relay_otel_subscriber_register(const struct FfiOpenTelemetrySubscriber *subscriber, + const char *name); /** * Deregisters the OpenTelemetry subscriber by name. @@ -1036,7 +1036,7 @@ NemoFlowStatus nemo_flow_otel_subscriber_register(const struct FfiOpenTelemetryS * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_otel_subscriber_deregister(const char *name); +NemoRelayStatus nemo_relay_otel_subscriber_deregister(const char *name); /** * Forces a flush of finished spans through the exporter. @@ -1044,7 +1044,7 @@ NemoFlowStatus nemo_flow_otel_subscriber_deregister(const char *name); * # Safety * `subscriber` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_otel_subscriber_force_flush(const struct FfiOpenTelemetrySubscriber *subscriber); +NemoRelayStatus nemo_relay_otel_subscriber_force_flush(const struct FfiOpenTelemetrySubscriber *subscriber); /** * Shuts down the underlying tracer provider. @@ -1052,7 +1052,7 @@ NemoFlowStatus nemo_flow_otel_subscriber_force_flush(const struct FfiOpenTelemet * # Safety * `subscriber` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_otel_subscriber_shutdown(const struct FfiOpenTelemetrySubscriber *subscriber); +NemoRelayStatus nemo_relay_otel_subscriber_shutdown(const struct FfiOpenTelemetrySubscriber *subscriber); /** * Creates a new OpenInference subscriber. @@ -1064,16 +1064,16 @@ NemoFlowStatus nemo_flow_otel_subscriber_shutdown(const struct FfiOpenTelemetryS * # Safety * Any non-null C strings must be valid and `out` must be non-null. */ -NemoFlowStatus nemo_flow_openinference_subscriber_create(const char *transport, - const char *endpoint, - const char *headers_json, - const char *resource_attributes_json, - const char *service_name, - const char *service_namespace, - const char *service_version, - const char *instrumentation_scope, - uint64_t timeout_millis, - struct FfiOpenInferenceSubscriber **out); +NemoRelayStatus nemo_relay_openinference_subscriber_create(const char *transport, + const char *endpoint, + const char *headers_json, + const char *resource_attributes_json, + const char *service_name, + const char *service_namespace, + const char *service_version, + const char *instrumentation_scope, + uint64_t timeout_millis, + struct FfiOpenInferenceSubscriber **out); /** * Registers the OpenInference subscriber as an event subscriber. @@ -1081,8 +1081,8 @@ NemoFlowStatus nemo_flow_openinference_subscriber_create(const char *transport, * # Safety * `subscriber` and `name` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_openinference_subscriber_register(const struct FfiOpenInferenceSubscriber *subscriber, - const char *name); +NemoRelayStatus nemo_relay_openinference_subscriber_register(const struct FfiOpenInferenceSubscriber *subscriber, + const char *name); /** * Deregisters the OpenInference subscriber by name. @@ -1090,7 +1090,7 @@ NemoFlowStatus nemo_flow_openinference_subscriber_register(const struct FfiOpenI * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_openinference_subscriber_deregister(const char *name); +NemoRelayStatus nemo_relay_openinference_subscriber_deregister(const char *name); /** * Forces a flush of finished spans through the exporter. @@ -1098,7 +1098,7 @@ NemoFlowStatus nemo_flow_openinference_subscriber_deregister(const char *name); * # Safety * `subscriber` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_openinference_subscriber_force_flush(const struct FfiOpenInferenceSubscriber *subscriber); +NemoRelayStatus nemo_relay_openinference_subscriber_force_flush(const struct FfiOpenInferenceSubscriber *subscriber); /** * Shuts down the underlying tracer provider. @@ -1106,7 +1106,7 @@ NemoFlowStatus nemo_flow_openinference_subscriber_force_flush(const struct FfiOp * # Safety * `subscriber` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_openinference_subscriber_shutdown(const struct FfiOpenInferenceSubscriber *subscriber); +NemoRelayStatus nemo_relay_openinference_subscriber_shutdown(const struct FfiOpenInferenceSubscriber *subscriber); /** * Validate a generic plugin config document and return the diagnostics report as JSON. @@ -1114,7 +1114,7 @@ NemoFlowStatus nemo_flow_openinference_subscriber_shutdown(const struct FfiOpenI * # Safety * `config_json` must be a valid C string and `out_json` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_validate_plugin_config(const char *config_json, char **out_json); +NemoRelayStatus nemo_relay_validate_plugin_config(const char *config_json, char **out_json); /** * Initialize the active global plugin components and return the resulting diagnostics report. @@ -1122,12 +1122,12 @@ NemoFlowStatus nemo_flow_validate_plugin_config(const char *config_json, char ** * # Safety * `config_json` must be a valid C string and `out_json` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_initialize_plugins(const char *config_json, char **out_json); +NemoRelayStatus nemo_relay_initialize_plugins(const char *config_json, char **out_json); /** * Clear the active global plugin configuration. */ -NemoFlowStatus nemo_flow_clear_plugin_configuration(void); +NemoRelayStatus nemo_relay_clear_plugin_configuration(void); /** * Return the last successfully configured plugin report as JSON. @@ -1135,7 +1135,7 @@ NemoFlowStatus nemo_flow_clear_plugin_configuration(void); * # Safety * `out_json` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_active_plugin_report_json(char **out_json); +NemoRelayStatus nemo_relay_active_plugin_report_json(char **out_json); /** * Return the registered plugin kinds as JSON. @@ -1143,7 +1143,7 @@ NemoFlowStatus nemo_flow_active_plugin_report_json(char **out_json); * # Safety * `out_json` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_list_plugin_kinds_json(char **out_json); +NemoRelayStatus nemo_relay_list_plugin_kinds_json(char **out_json); /** * Register a plugin backed by foreign callbacks. @@ -1151,11 +1151,11 @@ NemoFlowStatus nemo_flow_list_plugin_kinds_json(char **out_json); * # Safety * `plugin_kind` must be a valid C string and `register_cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_plugin(const char *plugin_kind, - struct Option_NemoFlowPluginValidateCb validate_cb, - NemoFlowPluginRegisterCb register_cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_plugin(const char *plugin_kind, + struct Option_NemoRelayPluginValidateCb validate_cb, + NemoRelayPluginRegisterCb register_cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a plugin by kind. @@ -1163,7 +1163,7 @@ NemoFlowStatus nemo_flow_register_plugin(const char *plugin_kind, * # Safety * `plugin_kind` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_plugin(const char *plugin_kind); +NemoRelayStatus nemo_relay_deregister_plugin(const char *plugin_kind); /** * Register an event subscriber into the plugin registration context. @@ -1172,11 +1172,11 @@ NemoFlowStatus nemo_flow_deregister_plugin(const char *plugin_kind); * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_subscriber(struct FfiPluginContext *ctx, - const char *name, - NemoFlowEventSubscriberCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_subscriber(struct FfiPluginContext *ctx, + const char *name, + NemoRelayEventSubscriberCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register a tool sanitize-request guardrail into the plugin registration context. @@ -1185,12 +1185,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_subscriber(struct FfiPluginCont * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_tool_sanitize_request_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowToolSanitizeCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_tool_sanitize_request_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayToolSanitizeCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register a tool sanitize-response guardrail into the plugin registration context. @@ -1199,12 +1199,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_tool_sanitize_request_guardrail * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_tool_sanitize_response_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowToolSanitizeCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_tool_sanitize_response_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayToolSanitizeCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register a tool conditional-execution guardrail into the plugin registration context. @@ -1213,12 +1213,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_tool_sanitize_response_guardrai * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_tool_conditional_execution_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowToolConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_tool_conditional_execution_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayToolConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM sanitize-request guardrail into the plugin registration context. @@ -1227,12 +1227,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_tool_conditional_execution_guar * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_sanitize_request_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowLlmRequestCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_sanitize_request_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayLlmRequestCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM sanitize-response guardrail into the plugin registration context. @@ -1241,12 +1241,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_sanitize_response_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowJsonCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_sanitize_response_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayJsonCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM conditional-execution guardrail into the plugin registration context. @@ -1255,12 +1255,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_sanitize_response_guardrail * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_conditional_execution_guardrail(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowLlmConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_conditional_execution_guardrail(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayLlmConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM request intercept into the plugin registration context. @@ -1269,13 +1269,13 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_conditional_execution_guard * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_request_intercept(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - bool break_chain, - NemoFlowLlmRequestInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_request_intercept(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + bool break_chain, + NemoRelayLlmRequestInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register a tool request intercept into the plugin registration context. @@ -1284,13 +1284,13 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_request_intercept(struct Ff * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_tool_request_intercept(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - bool break_chain, - NemoFlowToolSanitizeCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_tool_request_intercept(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + bool break_chain, + NemoRelayToolSanitizeCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM execution intercept into the plugin registration context. @@ -1299,12 +1299,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_tool_request_intercept(struct F * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_execution_intercept(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_execution_intercept(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register an LLM stream execution intercept into the plugin registration context. @@ -1313,12 +1313,12 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_execution_intercept(struct * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_llm_stream_execution_intercept(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_llm_stream_execution_intercept(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Register a tool execution intercept into the plugin registration context. @@ -1327,24 +1327,24 @@ NemoFlowStatus nemo_flow_plugin_context_register_llm_stream_execution_intercept( * `ctx` and `name` must be valid pointers and the callback must remain valid for the duration * of the plugin registration lifetime. */ -NemoFlowStatus nemo_flow_plugin_context_register_tool_execution_intercept(struct FfiPluginContext *ctx, - const char *name, - int32_t priority, - NemoFlowToolExecInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_plugin_context_register_tool_execution_intercept(struct FfiPluginContext *ctx, + const char *name, + int32_t priority, + NemoRelayToolExecInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Retrieve the current scope handle from the thread-local scope stack. * * # Parameters * - `out`: On success, receives a heap-allocated `FfiScopeHandle` that must be - * freed with `nemo_flow_scope_handle_free`. + * freed with `nemo_relay_scope_handle_free`. * * # Safety * `out` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_get_handle(struct FfiScopeHandle **out); +NemoRelayStatus nemo_relay_get_handle(struct FfiScopeHandle **out); /** * Push a new scope onto the scope stack. @@ -1367,7 +1367,7 @@ NemoFlowStatus nemo_flow_get_handle(struct FfiScopeHandle **out); * - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the * handle start time and start event, or null to use the current UTC time. * - `out`: On success, receives a heap-allocated `FfiScopeHandle` that must - * be freed with `nemo_flow_scope_handle_free`. + * be freed with `nemo_relay_scope_handle_free`. * * # Errors * Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -1379,15 +1379,15 @@ NemoFlowStatus nemo_flow_get_handle(struct FfiScopeHandle **out); * be null; when non-null, optional pointers must be valid for reads for the * duration of the call. */ -NemoFlowStatus nemo_flow_push_scope(const char *name, - NemoFlowScopeType scope_type, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - const char *input_json, - const int64_t *timestamp_unix_micros, - struct FfiScopeHandle **out); +NemoRelayStatus nemo_relay_push_scope(const char *name, + NemoRelayScopeType scope_type, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + const char *input_json, + const int64_t *timestamp_unix_micros, + struct FfiScopeHandle **out); /** * Pop a scope from the scope stack by its handle. @@ -1412,9 +1412,9 @@ NemoFlowStatus nemo_flow_push_scope(const char *name, * `timestamp_unix_micros` may be null; when non-null, optional pointers must * be valid for reads for the duration of the call. */ -NemoFlowStatus nemo_flow_pop_scope(const struct FfiScopeHandle *handle, - const char *output_json, - const int64_t *timestamp_unix_micros); +NemoRelayStatus nemo_relay_pop_scope(const struct FfiScopeHandle *handle, + const char *output_json, + const int64_t *timestamp_unix_micros); /** * Emit a named lifecycle event. @@ -1441,11 +1441,11 @@ NemoFlowStatus nemo_flow_pop_scope(const struct FfiScopeHandle *handle, * non-null, optional pointers must be valid for reads for the duration of the * call. */ -NemoFlowStatus nemo_flow_event(const char *name, - const struct FfiScopeHandle *parent, - const char *data_json, - const char *metadata_json, - const int64_t *timestamp_unix_micros); +NemoRelayStatus nemo_relay_event(const char *name, + const struct FfiScopeHandle *parent, + const char *data_json, + const char *metadata_json, + const int64_t *timestamp_unix_micros); /** * Register a scope-local tool conditional execution guardrail. @@ -1459,18 +1459,18 @@ NemoFlowStatus nemo_flow_event(const char *name, * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal an internal callback failure instead of - * allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C + * allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C * and return null. * * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_tool_conditional_execution_guardrail(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowToolConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_tool_conditional_execution_guardrail(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayToolConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local tool conditional execution guardrail by name. @@ -1478,8 +1478,8 @@ NemoFlowStatus nemo_flow_scope_register_tool_conditional_execution_guardrail(con * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_tool_conditional_execution_guardrail(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_tool_conditional_execution_guardrail(const char *scope_uuid, + const char *name); /** * Register a scope-local tool execution intercept following the middleware @@ -1496,12 +1496,12 @@ NemoFlowStatus nemo_flow_scope_deregister_tool_conditional_execution_guardrail(c * # Safety * `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_scope_register_tool_execution_intercept(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowToolExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_scope_register_tool_execution_intercept(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayToolExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister a scope-local tool execution intercept by name. @@ -1509,8 +1509,8 @@ NemoFlowStatus nemo_flow_scope_register_tool_execution_intercept(const char *sco * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_tool_execution_intercept(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_tool_execution_intercept(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM request sanitization guardrail. @@ -1526,12 +1526,12 @@ NemoFlowStatus nemo_flow_scope_deregister_tool_execution_intercept(const char *s * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_llm_sanitize_request_guardrail(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowLlmRequestCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_llm_sanitize_request_guardrail(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayLlmRequestCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local LLM request sanitization guardrail by name. @@ -1539,8 +1539,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_sanitize_request_guardrail(const cha * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_sanitize_request_guardrail(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_sanitize_request_guardrail(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM response sanitization guardrail. @@ -1556,12 +1556,12 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_sanitize_request_guardrail(const c * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_llm_sanitize_response_guardrail(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowJsonCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_llm_sanitize_response_guardrail(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayJsonCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local LLM response sanitization guardrail by name. @@ -1569,8 +1569,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_sanitize_response_guardrail(const ch * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_sanitize_response_guardrail(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_sanitize_response_guardrail(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM conditional execution guardrail. @@ -1584,18 +1584,18 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_sanitize_response_guardrail(const * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal an internal callback failure instead of - * allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C + * allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C * and return null. * * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_llm_conditional_execution_guardrail(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowLlmConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_llm_conditional_execution_guardrail(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayLlmConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local LLM conditional execution guardrail by name. @@ -1603,8 +1603,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_conditional_execution_guardrail(cons * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_conditional_execution_guardrail(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_conditional_execution_guardrail(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM request intercept. @@ -1619,18 +1619,18 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_conditional_execution_guardrail(co * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal failure, call - * [`crate::error::nemo_flow_set_last_error_message`] from C and return null. + * [`crate::error::nemo_relay_set_last_error_message`] from C and return null. * * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_llm_request_intercept(const char *scope_uuid, - const char *name, - int32_t priority, - bool break_chain, - NemoFlowLlmRequestInterceptCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_llm_request_intercept(const char *scope_uuid, + const char *name, + int32_t priority, + bool break_chain, + NemoRelayLlmRequestInterceptCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local LLM request intercept by name. @@ -1638,8 +1638,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_request_intercept(const char *scope_ * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_request_intercept(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_request_intercept(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM execution intercept following the middleware @@ -1656,12 +1656,12 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_request_intercept(const char *scop * # Safety * `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_scope_register_llm_execution_intercept(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_scope_register_llm_execution_intercept(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister a scope-local LLM execution intercept by name. @@ -1669,8 +1669,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_execution_intercept(const char *scop * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_execution_intercept(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_execution_intercept(const char *scope_uuid, + const char *name); /** * Register a scope-local LLM streaming execution intercept following the @@ -1687,12 +1687,12 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_execution_intercept(const char *sc * # Safety * `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_scope_register_llm_stream_execution_intercept(const char *scope_uuid, - const char *name, - int32_t priority, - NemoFlowLlmExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_scope_register_llm_stream_execution_intercept(const char *scope_uuid, + const char *name, + int32_t priority, + NemoRelayLlmExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister a scope-local LLM streaming execution intercept by name. @@ -1700,8 +1700,8 @@ NemoFlowStatus nemo_flow_scope_register_llm_stream_execution_intercept(const cha * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_llm_stream_execution_intercept(const char *scope_uuid, - const char *name); +NemoRelayStatus nemo_relay_scope_deregister_llm_stream_execution_intercept(const char *scope_uuid, + const char *name); /** * Register a scope-local event subscriber. @@ -1716,11 +1716,11 @@ NemoFlowStatus nemo_flow_scope_deregister_llm_stream_execution_intercept(const c * # Safety * `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_scope_register_subscriber(const char *scope_uuid, - const char *name, - NemoFlowEventSubscriberCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_scope_register_subscriber(const char *scope_uuid, + const char *name, + NemoRelayEventSubscriberCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a scope-local event subscriber by name. @@ -1728,34 +1728,34 @@ NemoFlowStatus nemo_flow_scope_register_subscriber(const char *scope_uuid, * # Safety * `scope_uuid` and `name` must be valid C strings. */ -NemoFlowStatus nemo_flow_scope_deregister_subscriber(const char *scope_uuid, const char *name); +NemoRelayStatus nemo_relay_scope_deregister_subscriber(const char *scope_uuid, const char *name); /** * Create a new isolated scope stack with its own root scope. * * Each scope stack is independent: scopes pushed on one do not appear on another. - * Use `nemo_flow_scope_stack_set_thread` to bind a stack to the current thread - * before making other NeMo Flow API calls. + * Use `nemo_relay_scope_stack_set_thread` to bind a stack to the current thread + * before making other NeMo Relay API calls. * * # Parameters * - `out`: On success, receives a heap-allocated `FfiScopeStack` that must be - * freed with `nemo_flow_scope_stack_free`. + * freed with `nemo_relay_scope_stack_free`. * * # Returns - * - Returns [`NemoFlowStatus::Ok`] on success and writes the new scope stack + * - Returns [`NemoRelayStatus::Ok`] on success and writes the new scope stack * to `out`. - * - Returns [`NemoFlowStatus::NullPointer`] when `out` is null. + * - Returns [`NemoRelayStatus::NullPointer`] when `out` is null. * * # Safety * `out` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_scope_stack_create(struct FfiScopeStack **out); +NemoRelayStatus nemo_relay_scope_stack_create(struct FfiScopeStack **out); /** * Bind an isolated scope stack to the current OS thread. * - * After this call, all NeMo Flow scope operations on the current thread - * (e.g. `nemo_flow_push_scope`, `nemo_flow_get_handle`) will use the + * After this call, all NeMo Relay scope operations on the current thread + * (e.g. `nemo_relay_push_scope`, `nemo_relay_get_handle`) will use the * given scope stack. This is typically used from Go goroutines that have * called `runtime.LockOSThread()`. * @@ -1766,20 +1766,20 @@ NemoFlowStatus nemo_flow_scope_stack_create(struct FfiScopeStack **out); * - `stack`: Scope stack to bind to the current OS thread. * * # Returns - * - Returns [`NemoFlowStatus::Ok`] when the thread-local scope stack was + * - Returns [`NemoRelayStatus::Ok`] when the thread-local scope stack was * updated successfully. - * - Returns [`NemoFlowStatus::NullPointer`] when `stack` is null. + * - Returns [`NemoRelayStatus::NullPointer`] when `stack` is null. * * # Safety * `stack` must be a valid, non-null `FfiScopeStack` pointer. */ -NemoFlowStatus nemo_flow_scope_stack_set_thread(const struct FfiScopeStack *stack); +NemoRelayStatus nemo_relay_scope_stack_set_thread(const struct FfiScopeStack *stack); /** * Capture the current thread-local scope stack binding. * * The returned binding must be restored with - * `nemo_flow_scope_stack_restore_thread`. + * `nemo_relay_scope_stack_restore_thread`. * * # Parameters * - `out`: On success, receives a heap-allocated binding handle. @@ -1787,22 +1787,22 @@ NemoFlowStatus nemo_flow_scope_stack_set_thread(const struct FfiScopeStack *stac * # Safety * `out` must be a valid, non-null pointer. */ -NemoFlowStatus nemo_flow_scope_stack_capture_thread(struct FfiThreadScopeStackBinding **out); +NemoRelayStatus nemo_relay_scope_stack_capture_thread(struct FfiThreadScopeStackBinding **out); /** * Restore and free a captured thread-local scope stack binding. * * # Safety * `binding` must be a valid pointer returned by - * `nemo_flow_scope_stack_capture_thread`. + * `nemo_relay_scope_stack_capture_thread`. */ -NemoFlowStatus nemo_flow_scope_stack_restore_thread(struct FfiThreadScopeStackBinding *binding); +NemoRelayStatus nemo_relay_scope_stack_restore_thread(struct FfiThreadScopeStackBinding *binding); /** * Returns whether the current execution context has an explicitly-initialized * scope stack. * - * Returns `true` if `nemo_flow_scope_stack_set_thread` has been called on the + * Returns `true` if `nemo_relay_scope_stack_set_thread` has been called on the * current OS thread (or the caller is inside a tokio task-local scope). * Returns `false` when only the auto-created default is present. * @@ -1810,14 +1810,14 @@ NemoFlowStatus nemo_flow_scope_stack_restore_thread(struct FfiThreadScopeStackBi * This helper does not allocate or install a scope stack. It only reports * whether one is already explicit in the current execution context. */ -bool nemo_flow_scope_stack_active(void); +bool nemo_relay_scope_stack_active(void); /** * Begin a manual tool call lifecycle span. * * This emits a tool Start event after applying sanitize-request guardrails to * the observability payload. Request and execution intercepts only run through - * `nemo_flow_tool_call_execute`. + * `nemo_relay_tool_call_execute`. * * # Parameters * - `name`: Null-terminated tool name. @@ -1835,7 +1835,7 @@ bool nemo_flow_scope_stack_active(void); * - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the * handle start time and start event, or null to use the current UTC time. * - `out`: On success, receives a heap-allocated `FfiToolHandle` that must be - * freed with `nemo_flow_tool_handle_free`. + * freed with `nemo_relay_tool_handle_free`. * * # Errors * Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -1846,25 +1846,25 @@ bool nemo_flow_scope_stack_active(void); * Optional pointer arguments may be null; when non-null, they must be valid * for reads for the duration of the call. */ -NemoFlowStatus nemo_flow_tool_call(const char *name, - const char *args_json, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - const char *tool_call_id, - const int64_t *timestamp_unix_micros, - struct FfiToolHandle **out); +NemoRelayStatus nemo_relay_tool_call(const char *name, + const char *args_json, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + const char *tool_call_id, + const int64_t *timestamp_unix_micros, + struct FfiToolHandle **out); /** * End a manual tool call lifecycle span. * * This emits a tool End event after applying sanitize-response guardrails to * the observability payload. Response intercepts only run through - * `nemo_flow_tool_call_execute`. + * `nemo_relay_tool_call_execute`. * * # Parameters - * - `handle`: The tool handle from `nemo_flow_tool_call`. + * - `handle`: The tool handle from `nemo_relay_tool_call`. * - `result_json`: Tool result as a null-terminated JSON C string. This * result becomes the end-event data after sanitize-response guardrails unless * it sanitizes to JSON null. @@ -1884,11 +1884,11 @@ NemoFlowStatus nemo_flow_tool_call(const char *name, * pointer arguments may be null; when non-null, they must be valid for reads * for the duration of the call. */ -NemoFlowStatus nemo_flow_tool_call_end(const struct FfiToolHandle *handle, - const char *result_json, - const char *data_json, - const char *metadata_json, - const int64_t *timestamp_unix_micros); +NemoRelayStatus nemo_relay_tool_call_end(const struct FfiToolHandle *handle, + const char *result_json, + const char *data_json, + const char *metadata_json, + const int64_t *timestamp_unix_micros); /** * Execute a tool call end-to-end: run conditional-execution guardrails (on raw @@ -1909,21 +1909,21 @@ NemoFlowStatus nemo_flow_tool_call_end(const struct FfiToolHandle *handle, * - `data_json`: Optional JSON data, or null. * - `metadata_json`: Optional JSON metadata, or null. * - `out`: On success, receives the result as a JSON C string. Caller must free - * with `nemo_flow_string_free`. + * with `nemo_relay_string_free`. * * # Safety * `name`, `args_json`, and `out` must be valid, non-null pointers. */ -NemoFlowStatus nemo_flow_tool_call_execute(const char *name, - const char *args_json, - NemoFlowToolExecCb func, - void *func_user_data, - NemoFlowFreeFn func_free, - const struct FfiScopeHandle *parent, - uint32_t attributes, - const char *data_json, - const char *metadata_json, - char **out); +NemoRelayStatus nemo_relay_tool_call_execute(const char *name, + const char *args_json, + NemoRelayToolExecCb func, + void *func_user_data, + NemoRelayFreeFn func_free, + const struct FfiScopeHandle *parent, + uint32_t attributes, + const char *data_json, + const char *metadata_json, + char **out); /** * Register a tool conditional execution guardrail. The callback decides whether @@ -1937,17 +1937,17 @@ NemoFlowStatus nemo_flow_tool_call_execute(const char *name, * - `free_fn`: Optional destructor for `user_data`. * * The callback is fallible. To signal an internal callback failure instead of - * allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C + * allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C * and return null. * * # Safety * `name` must be a valid C string. `cb` must be a valid function pointer. */ -NemoFlowStatus nemo_flow_register_tool_conditional_execution_guardrail(const char *name, - int32_t priority, - NemoFlowToolConditionalCb cb, - void *user_data, - NemoFlowFreeFn free_fn); +NemoRelayStatus nemo_relay_register_tool_conditional_execution_guardrail(const char *name, + int32_t priority, + NemoRelayToolConditionalCb cb, + void *user_data, + NemoRelayFreeFn free_fn); /** * Deregister a tool conditional execution guardrail by name. @@ -1955,7 +1955,7 @@ NemoFlowStatus nemo_flow_register_tool_conditional_execution_guardrail(const cha * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_tool_conditional_execution_guardrail(const char *name); +NemoRelayStatus nemo_relay_deregister_tool_conditional_execution_guardrail(const char *name); /** * Register a tool execution intercept following the middleware chain pattern. @@ -1973,11 +1973,11 @@ NemoFlowStatus nemo_flow_deregister_tool_conditional_execution_guardrail(const c * # Safety * `name` must be a valid C string. Callback pointers must be valid. */ -NemoFlowStatus nemo_flow_register_tool_execution_intercept(const char *name, - int32_t priority, - NemoFlowToolExecInterceptCb exec_cb, - void *exec_user_data, - NemoFlowFreeFn exec_free); +NemoRelayStatus nemo_relay_register_tool_execution_intercept(const char *name, + int32_t priority, + NemoRelayToolExecInterceptCb exec_cb, + void *exec_user_data, + NemoRelayFreeFn exec_free); /** * Deregister a tool execution intercept by name. @@ -1985,17 +1985,17 @@ NemoFlowStatus nemo_flow_register_tool_execution_intercept(const char *name, * # Safety * `name` must be a valid C string. */ -NemoFlowStatus nemo_flow_deregister_tool_execution_intercept(const char *name); +NemoRelayStatus nemo_relay_deregister_tool_execution_intercept(const char *name); /** - * Free a C string previously returned by any `nemo_flow_*` accessor function. + * Free a C string previously returned by any `nemo_relay_*` accessor function. * Passing null is a safe no-op. * * # Safety * `ptr` must be a pointer returned by this library, or null. Double-free is * undefined behavior. */ -void nemo_flow_string_free(char *ptr); +void nemo_relay_string_free(char *ptr); /** * Retrieve the last error message set on this thread, or null if no error @@ -2005,7 +2005,7 @@ void nemo_flow_string_free(char *ptr); * until the next FFI call on the same thread. Do **not** free the returned * pointer. */ -const char *nemo_flow_last_error(void); +const char *nemo_relay_last_error(void); /** * Set the thread-local last-error message from foreign code. @@ -2017,109 +2017,109 @@ const char *nemo_flow_last_error(void); * `msg` must be either null or a valid, null-terminated C string for the * duration of this call. */ -void nemo_flow_set_last_error_message(const char *msg); +void nemo_relay_set_last_error_message(const char *msg); /** * Free a scope handle previously returned by the runtime. * * # Safety - * `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. + * `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. */ -void nemo_flow_scope_handle_free(struct FfiScopeHandle *ptr); +void nemo_relay_scope_handle_free(struct FfiScopeHandle *ptr); /** * Free a tool handle previously returned by the runtime. * * # Safety - * `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. + * `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. */ -void nemo_flow_tool_handle_free(struct FfiToolHandle *ptr); +void nemo_relay_tool_handle_free(struct FfiToolHandle *ptr); /** * Free an LLM handle previously returned by the runtime. * * # Safety - * `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. + * `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. */ -void nemo_flow_llm_handle_free(struct FfiLLMHandle *ptr); +void nemo_relay_llm_handle_free(struct FfiLLMHandle *ptr); /** * Free an LLM request object. * * # Safety - * `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. + * `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. */ -void nemo_flow_llm_request_free(struct FfiLLMRequest *ptr); +void nemo_relay_llm_request_free(struct FfiLLMRequest *ptr); /** * Free an event object. * * # Safety - * `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. + * `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. */ -void nemo_flow_event_free(struct FfiEvent *ptr); +void nemo_relay_event_free(struct FfiEvent *ptr); /** - * Free a scope stack handle previously returned by `nemo_flow_scope_stack_create`. + * Free a scope stack handle previously returned by `nemo_relay_scope_stack_create`. * * # Safety - * `ptr` must be a valid pointer returned by `nemo_flow_scope_stack_create`, or null. + * `ptr` must be a valid pointer returned by `nemo_relay_scope_stack_create`, or null. */ -void nemo_flow_scope_stack_free(struct FfiScopeStack *ptr); +void nemo_relay_scope_stack_free(struct FfiScopeStack *ptr); /** - * Free an ATIF exporter handle previously returned by `nemo_flow_atif_exporter_create`. + * Free an ATIF exporter handle previously returned by `nemo_relay_atif_exporter_create`. * * # Safety - * `ptr` must be a valid pointer returned by `nemo_flow_atif_exporter_create`, or null. + * `ptr` must be a valid pointer returned by `nemo_relay_atif_exporter_create`, or null. */ -void nemo_flow_atif_exporter_free(struct FfiAtifExporter *ptr); +void nemo_relay_atif_exporter_free(struct FfiAtifExporter *ptr); /** - * Free an ATOF JSONL exporter handle previously returned by `nemo_flow_atof_exporter_create`. + * Free an ATOF JSONL exporter handle previously returned by `nemo_relay_atof_exporter_create`. * * # Safety - * `ptr` must be a valid pointer returned by `nemo_flow_atof_exporter_create`, or null. + * `ptr` must be a valid pointer returned by `nemo_relay_atof_exporter_create`, or null. */ -void nemo_flow_atof_exporter_free(struct FfiAtofExporter *ptr); +void nemo_relay_atof_exporter_free(struct FfiAtofExporter *ptr); /** * Free an OpenTelemetry subscriber handle previously returned by - * `nemo_flow_otel_subscriber_create`. + * `nemo_relay_otel_subscriber_create`. * * # Safety - * `ptr` must be a valid pointer returned by `nemo_flow_otel_subscriber_create`, or null. + * `ptr` must be a valid pointer returned by `nemo_relay_otel_subscriber_create`, or null. */ -void nemo_flow_otel_subscriber_free(struct FfiOpenTelemetrySubscriber *ptr); +void nemo_relay_otel_subscriber_free(struct FfiOpenTelemetrySubscriber *ptr); /** * Free an OpenInference subscriber handle previously returned by - * `nemo_flow_openinference_subscriber_create`. + * `nemo_relay_openinference_subscriber_create`. * * # Safety * `ptr` must be a valid pointer returned by - * `nemo_flow_openinference_subscriber_create`, or null. + * `nemo_relay_openinference_subscriber_create`, or null. */ -void nemo_flow_openinference_subscriber_free(struct FfiOpenInferenceSubscriber *ptr); +void nemo_relay_openinference_subscriber_free(struct FfiOpenInferenceSubscriber *ptr); /** * Free a codec handle previously returned by one of the codec constructor - * functions (`nemo_flow_openai_chat_codec_new`, etc.). + * functions (`nemo_relay_openai_chat_codec_new`, etc.). * * # Safety * `handle` must be a valid pointer returned by one of the codec constructor * functions, or null. Double-free is undefined behavior. */ -void nemo_flow_codec_free(struct FfiCodecHandle *handle); +void nemo_relay_codec_free(struct FfiCodecHandle *handle); /** * Return the UUID of a scope handle as a C string. Caller must free the result - * with `nemo_flow_string_free`. Returns null if `ptr` is null. + * with `nemo_relay_string_free`. Returns null if `ptr` is null. * * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -char *nemo_flow_scope_handle_uuid(const struct FfiScopeHandle *ptr); +char *nemo_relay_scope_handle_uuid(const struct FfiScopeHandle *ptr); /** * Return the name of a scope handle as a C string. Caller must free the result. @@ -2128,7 +2128,7 @@ char *nemo_flow_scope_handle_uuid(const struct FfiScopeHandle *ptr); * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -char *nemo_flow_scope_handle_name(const struct FfiScopeHandle *ptr); +char *nemo_relay_scope_handle_name(const struct FfiScopeHandle *ptr); /** * Return the scope type of a scope handle. Returns `Unknown` if `ptr` is null. @@ -2136,7 +2136,7 @@ char *nemo_flow_scope_handle_name(const struct FfiScopeHandle *ptr); * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -NemoFlowScopeType nemo_flow_scope_handle_scope_type(const struct FfiScopeHandle *ptr); +NemoRelayScopeType nemo_relay_scope_handle_scope_type(const struct FfiScopeHandle *ptr); /** * Return the bitfield attributes of a scope handle. Returns 0 if `ptr` is null. @@ -2144,34 +2144,34 @@ NemoFlowScopeType nemo_flow_scope_handle_scope_type(const struct FfiScopeHandle * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -uint32_t nemo_flow_scope_handle_attributes(const struct FfiScopeHandle *ptr); +uint32_t nemo_relay_scope_handle_attributes(const struct FfiScopeHandle *ptr); /** * Return the parent scope UUID as a C string, or null if there is no parent. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -char *nemo_flow_scope_handle_parent_uuid(const struct FfiScopeHandle *ptr); +char *nemo_relay_scope_handle_parent_uuid(const struct FfiScopeHandle *ptr); /** * Return the scope data as a JSON C string, or null if no data is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -char *nemo_flow_scope_handle_data(const struct FfiScopeHandle *ptr); +char *nemo_relay_scope_handle_data(const struct FfiScopeHandle *ptr); /** * Return the scope metadata as a JSON C string, or null if no metadata is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiScopeHandle` pointer or null. */ -char *nemo_flow_scope_handle_metadata(const struct FfiScopeHandle *ptr); +char *nemo_relay_scope_handle_metadata(const struct FfiScopeHandle *ptr); /** * Return the UUID of a tool handle as a C string. Caller must free the result. @@ -2179,7 +2179,7 @@ char *nemo_flow_scope_handle_metadata(const struct FfiScopeHandle *ptr); * # Safety * `ptr` must be a valid `FfiToolHandle` pointer or null. */ -char *nemo_flow_tool_handle_uuid(const struct FfiToolHandle *ptr); +char *nemo_relay_tool_handle_uuid(const struct FfiToolHandle *ptr); /** * Return the name of a tool handle as a C string. Caller must free the result. @@ -2187,7 +2187,7 @@ char *nemo_flow_tool_handle_uuid(const struct FfiToolHandle *ptr); * # Safety * `ptr` must be a valid `FfiToolHandle` pointer or null. */ -char *nemo_flow_tool_handle_name(const struct FfiToolHandle *ptr); +char *nemo_relay_tool_handle_name(const struct FfiToolHandle *ptr); /** * Return the bitfield attributes of a tool handle. Returns 0 if `ptr` is null. @@ -2195,16 +2195,16 @@ char *nemo_flow_tool_handle_name(const struct FfiToolHandle *ptr); * # Safety * `ptr` must be a valid `FfiToolHandle` pointer or null. */ -uint32_t nemo_flow_tool_handle_attributes(const struct FfiToolHandle *ptr); +uint32_t nemo_relay_tool_handle_attributes(const struct FfiToolHandle *ptr); /** * Return the parent scope UUID of a tool handle, or null if none. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiToolHandle` pointer or null. */ -char *nemo_flow_tool_handle_parent_uuid(const struct FfiToolHandle *ptr); +char *nemo_relay_tool_handle_parent_uuid(const struct FfiToolHandle *ptr); /** * Return the UUID of an LLM handle as a C string. Caller must free the result. @@ -2212,7 +2212,7 @@ char *nemo_flow_tool_handle_parent_uuid(const struct FfiToolHandle *ptr); * # Safety * `ptr` must be a valid `FfiLLMHandle` pointer or null. */ -char *nemo_flow_llm_handle_uuid(const struct FfiLLMHandle *ptr); +char *nemo_relay_llm_handle_uuid(const struct FfiLLMHandle *ptr); /** * Return the name of an LLM handle as a C string. Caller must free the result. @@ -2220,7 +2220,7 @@ char *nemo_flow_llm_handle_uuid(const struct FfiLLMHandle *ptr); * # Safety * `ptr` must be a valid `FfiLLMHandle` pointer or null. */ -char *nemo_flow_llm_handle_name(const struct FfiLLMHandle *ptr); +char *nemo_relay_llm_handle_name(const struct FfiLLMHandle *ptr); /** * Return the bitfield attributes of an LLM handle. Returns 0 if `ptr` is null. @@ -2228,20 +2228,20 @@ char *nemo_flow_llm_handle_name(const struct FfiLLMHandle *ptr); * # Safety * `ptr` must be a valid `FfiLLMHandle` pointer or null. */ -uint32_t nemo_flow_llm_handle_attributes(const struct FfiLLMHandle *ptr); +uint32_t nemo_relay_llm_handle_attributes(const struct FfiLLMHandle *ptr); /** * Return the parent scope UUID of an LLM handle, or null if none. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiLLMHandle` pointer or null. */ -char *nemo_flow_llm_handle_parent_uuid(const struct FfiLLMHandle *ptr); +char *nemo_relay_llm_handle_parent_uuid(const struct FfiLLMHandle *ptr); /** * Create a new LLM request object. Returns a heap-allocated `FfiLLMRequest` - * that must be freed with `nemo_flow_llm_request_free`. Returns null on + * that must be freed with `nemo_relay_llm_request_free`. Returns null on * invalid input. * * # Parameters @@ -2251,7 +2251,8 @@ char *nemo_flow_llm_handle_parent_uuid(const struct FfiLLMHandle *ptr); * # Safety * All string arguments must be valid null-terminated C strings or null. */ -struct FfiLLMRequest *nemo_flow_llm_request_new(const char *headers_json, const char *content_json); +struct FfiLLMRequest *nemo_relay_llm_request_new(const char *headers_json, + const char *content_json); /** * Return the headers of an LLM request as a JSON C string. Caller must free the result. @@ -2259,7 +2260,7 @@ struct FfiLLMRequest *nemo_flow_llm_request_new(const char *headers_json, const * # Safety * `ptr` must be a valid `FfiLLMRequest` pointer or null. */ -char *nemo_flow_llm_request_headers(const struct FfiLLMRequest *ptr); +char *nemo_relay_llm_request_headers(const struct FfiLLMRequest *ptr); /** * Return the content of an LLM request as a JSON C string. Caller must free the result. @@ -2267,7 +2268,7 @@ char *nemo_flow_llm_request_headers(const struct FfiLLMRequest *ptr); * # Safety * `ptr` must be a valid `FfiLLMRequest` pointer or null. */ -char *nemo_flow_llm_request_content(const struct FfiLLMRequest *ptr); +char *nemo_relay_llm_request_content(const struct FfiLLMRequest *ptr); /** * Return the UUID of an event as a C string. Caller must free the result. @@ -2275,34 +2276,34 @@ char *nemo_flow_llm_request_content(const struct FfiLLMRequest *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_uuid(const struct FfiEvent *ptr); +char *nemo_relay_event_uuid(const struct FfiEvent *ptr); /** * Return the name of an event as a C string, or null if unnamed. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_name(const struct FfiEvent *ptr); +char *nemo_relay_event_name(const struct FfiEvent *ptr); /** * Return the event discriminator as a C string. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_kind(const struct FfiEvent *ptr); +char *nemo_relay_event_kind(const struct FfiEvent *ptr); /** * Return the canonical subscriber event JSON as a C string. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_json(const struct FfiEvent *ptr); +char *nemo_relay_event_json(const struct FfiEvent *ptr); /** * Return the ATOF version as a C string. @@ -2310,7 +2311,7 @@ char *nemo_flow_event_json(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_atof_version(const struct FfiEvent *ptr); +char *nemo_relay_event_atof_version(const struct FfiEvent *ptr); /** * Return the ATOF scope category as a C string, or null for mark events. @@ -2318,7 +2319,7 @@ char *nemo_flow_event_atof_version(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_scope_category(const struct FfiEvent *ptr); +char *nemo_relay_event_scope_category(const struct FfiEvent *ptr); /** * Return the ATOF category as a C string, or null if absent. @@ -2326,7 +2327,7 @@ char *nemo_flow_event_scope_category(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_category(const struct FfiEvent *ptr); +char *nemo_relay_event_category(const struct FfiEvent *ptr); /** * Return ATOF attributes as a JSON string array. @@ -2334,7 +2335,7 @@ char *nemo_flow_event_category(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_attributes_json(const struct FfiEvent *ptr); +char *nemo_relay_event_attributes_json(const struct FfiEvent *ptr); /** * Return the ATOF category profile as a JSON C string, or null if absent. @@ -2342,7 +2343,7 @@ char *nemo_flow_event_attributes_json(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_category_profile(const struct FfiEvent *ptr); +char *nemo_relay_event_category_profile(const struct FfiEvent *ptr); /** * Return the Agent Trajectory Observability Format (ATOF) data schema as a @@ -2351,7 +2352,7 @@ char *nemo_flow_event_category_profile(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_data_schema(const struct FfiEvent *ptr); +char *nemo_relay_event_data_schema(const struct FfiEvent *ptr); /** * Return the raw attribute bitfield for an event, or 0 if it has none. @@ -2359,25 +2360,25 @@ char *nemo_flow_event_data_schema(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -uint32_t nemo_flow_event_attributes(const struct FfiEvent *ptr); +uint32_t nemo_relay_event_attributes(const struct FfiEvent *ptr); /** * Return the event data as a JSON C string, or null if no data is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_data(const struct FfiEvent *ptr); +char *nemo_relay_event_data(const struct FfiEvent *ptr); /** * Return the event metadata as a JSON C string, or null if no metadata is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_metadata(const struct FfiEvent *ptr); +char *nemo_relay_event_metadata(const struct FfiEvent *ptr); /** * Return the event timestamp as an RFC 3339 C string. Caller must free the result. @@ -2385,80 +2386,80 @@ char *nemo_flow_event_metadata(const struct FfiEvent *ptr); * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_timestamp(const struct FfiEvent *ptr); +char *nemo_relay_event_timestamp(const struct FfiEvent *ptr); /** * Return the event input as a JSON C string, or null if no input is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_input(const struct FfiEvent *ptr); +char *nemo_relay_event_input(const struct FfiEvent *ptr); /** * Return the event output as a JSON C string, or null if no output is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_output(const struct FfiEvent *ptr); +char *nemo_relay_event_output(const struct FfiEvent *ptr); /** * Return the event model name as a C string, or null if no model name is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_model_name(const struct FfiEvent *ptr); +char *nemo_relay_event_model_name(const struct FfiEvent *ptr); /** * Return the event tool call ID as a C string, or null if no tool call ID is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_tool_call_id(const struct FfiEvent *ptr); +char *nemo_relay_event_tool_call_id(const struct FfiEvent *ptr); /** * Return the event parent UUID as a C string, or null if no parent UUID is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_parent_uuid(const struct FfiEvent *ptr); +char *nemo_relay_event_parent_uuid(const struct FfiEvent *ptr); /** * Return the event scope type as a C string, or null if no scope type is set. - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_scope_type(const struct FfiEvent *ptr); +char *nemo_relay_event_scope_type(const struct FfiEvent *ptr); /** * Return the annotated request from an LLM start event as a JSON C string, * or null if not available (non-LLM events, or no codec was active). - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_annotated_request(const struct FfiEvent *ptr); +char *nemo_relay_event_annotated_request(const struct FfiEvent *ptr); /** * Return the annotated response from an LLM end event as a JSON C string, * or null if not available (non-LLM events, or no response codec was active). - * Caller must free the result with `nemo_flow_string_free`. + * Caller must free the result with `nemo_relay_string_free`. * * # Safety * `ptr` must be a valid `FfiEvent` pointer or null. */ -char *nemo_flow_event_annotated_response(const struct FfiEvent *ptr); +char *nemo_relay_event_annotated_response(const struct FfiEvent *ptr); -#endif /* NEMO_FLOW_H */ +#endif /* NEMO_RELAY_H */ diff --git a/crates/ffi/src/api/llm.rs b/crates/ffi/src/api/llm.rs index 009abb27b..ad311248e 100644 --- a/crates/ffi/src/api/llm.rs +++ b/crates/ffi/src/api/llm.rs @@ -3,12 +3,13 @@ use super::{ Arc, FfiCodecHandle, FfiLLMHandle, FfiScopeHandle, FlowResult, LlmAttributes, - LlmExecutionNextFn, LlmRequest, LlmStreamExecutionNextFn, NemoFlowCodecDecodeFn, - NemoFlowCodecEncodeFn, NemoFlowCollectorCb, NemoFlowFinalizerCb, NemoFlowFreeFn, - NemoFlowLlmExecCb, NemoFlowStatus, TASK_SCOPE_STACK, c_char, c_str_to_json, c_str_to_opt_json, - c_str_to_string, clear_last_error, core_llm_api, current_scope_stack, json_to_c_string, - set_last_error, status_from_error, tokio_runtime, unix_micros_to_opt_timestamp, wrap_codec_fn, - wrap_collector_fn, wrap_finalizer_fn, wrap_llm_exec_fn, wrap_llm_stream_exec_fn, + LlmExecutionNextFn, LlmRequest, LlmStreamExecutionNextFn, NemoRelayCodecDecodeFn, + NemoRelayCodecEncodeFn, NemoRelayCollectorCb, NemoRelayFinalizerCb, NemoRelayFreeFn, + NemoRelayLlmExecCb, NemoRelayStatus, TASK_SCOPE_STACK, c_char, c_str_to_json, + c_str_to_opt_json, c_str_to_string, clear_last_error, core_llm_api, current_scope_stack, + json_to_c_string, set_last_error, status_from_error, tokio_runtime, + unix_micros_to_opt_timestamp, wrap_codec_fn, wrap_collector_fn, wrap_finalizer_fn, + wrap_llm_exec_fn, wrap_llm_stream_exec_fn, }; use tokio_stream::StreamExt; @@ -20,7 +21,7 @@ use tokio_stream::StreamExt; /// /// This emits an LLM Start event after applying sanitize-request guardrails to /// the observability payload. Request and execution intercepts only run through -/// `nemo_flow_llm_call_execute`. +/// `nemo_relay_llm_call_execute`. /// /// # Parameters /// - `name`: Null-terminated LLM provider name. @@ -39,7 +40,7 @@ use tokio_stream::StreamExt; /// - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the /// handle start time and start event, or null to use the current UTC time. /// - `out`: On success, receives a heap-allocated `FfiLLMHandle` that must be -/// freed with `nemo_flow_llm_handle_free`. +/// freed with `nemo_relay_llm_handle_free`. /// /// # Errors /// Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -50,7 +51,7 @@ use tokio_stream::StreamExt; /// pointer arguments may be null; when non-null, they must be valid for reads /// for the duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_call( +pub unsafe extern "C" fn nemo_relay_llm_call( name: *const c_char, native_json: *const c_char, parent: *const FfiScopeHandle, @@ -60,11 +61,11 @@ pub unsafe extern "C" fn nemo_flow_llm_call( model_name: *const c_char, timestamp_unix_micros: *const i64, out: *mut *mut FfiLLMHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("null pointer argument"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -72,13 +73,13 @@ pub unsafe extern "C" fn nemo_flow_llm_call( }; let native = match c_str_to_json(native_json) { Some(n) => n, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let request: LlmRequest = match serde_json::from_value(native) { Ok(r) => r, Err(_) => { set_last_error("failed to parse native_json as LlmRequest"); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } }; let parent_ref = if parent.is_null() { @@ -89,11 +90,11 @@ pub unsafe extern "C" fn nemo_flow_llm_call( let attrs = LlmAttributes::from_bits_truncate(attributes); let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let model_name_opt = if model_name.is_null() { None @@ -105,7 +106,7 @@ pub unsafe extern "C" fn nemo_flow_llm_call( }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_llm_api::llm_call( @@ -122,7 +123,7 @@ pub unsafe extern "C" fn nemo_flow_llm_call( ) { Ok(h) => { unsafe { *out = Box::into_raw(Box::new(FfiLLMHandle(h))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -132,10 +133,10 @@ pub unsafe extern "C" fn nemo_flow_llm_call( /// /// This emits an LLM End event after applying sanitize-response guardrails to /// the observability payload. Response intercepts only run through -/// `nemo_flow_llm_call_execute`. +/// `nemo_relay_llm_call_execute`. /// /// # Parameters -/// - `handle`: The LLM handle from `nemo_flow_llm_call`. +/// - `handle`: The LLM handle from `nemo_relay_llm_call`. /// - `response_json`: LLM response as a null-terminated JSON C string. This /// response becomes the end-event data after sanitize-response guardrails /// unless it sanitizes to JSON null. @@ -155,33 +156,33 @@ pub unsafe extern "C" fn nemo_flow_llm_call( /// pointer arguments may be null; when non-null, they must be valid for reads /// for the duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_call_end( +pub unsafe extern "C" fn nemo_relay_llm_call_end( handle: *const FfiLLMHandle, response_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, timestamp_unix_micros: *const i64, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if handle.is_null() { set_last_error("handle is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let response = match c_str_to_json(response_json) { Some(r) => r, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_llm_api::llm_call_end( @@ -193,7 +194,7 @@ pub unsafe extern "C" fn nemo_flow_llm_call_end( .timestamp_opt(timestamp) .build(), ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -205,58 +206,58 @@ pub unsafe extern "C" fn nemo_flow_llm_call_end( /// Create a new OpenAI Chat Completions codec handle. /// /// The returned handle implements both request codec (decode/encode) and -/// response codec (decode_response). Free with `nemo_flow_codec_free`. +/// response codec (decode_response). Free with `nemo_relay_codec_free`. /// /// # Safety -/// Caller must free the returned handle via `nemo_flow_codec_free`. +/// Caller must free the returned handle via `nemo_relay_codec_free`. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_openai_chat_codec_new() -> *mut FfiCodecHandle { +pub extern "C" fn nemo_relay_openai_chat_codec_new() -> *mut FfiCodecHandle { Box::into_raw(Box::new(FfiCodecHandle { - codec: Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), - response_codec: Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), + codec: Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), + response_codec: Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), })) } /// Create a new OpenAI Responses API codec handle. /// /// The returned handle implements both request codec (decode/encode) and -/// response codec (decode_response). Free with `nemo_flow_codec_free`. +/// response codec (decode_response). Free with `nemo_relay_codec_free`. /// /// # Safety -/// Caller must free the returned handle via `nemo_flow_codec_free`. +/// Caller must free the returned handle via `nemo_relay_codec_free`. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_openai_responses_codec_new() -> *mut FfiCodecHandle { +pub extern "C" fn nemo_relay_openai_responses_codec_new() -> *mut FfiCodecHandle { Box::into_raw(Box::new(FfiCodecHandle { - codec: Arc::new(nemo_flow::codec::openai_responses::OpenAIResponsesCodec), - response_codec: Arc::new(nemo_flow::codec::openai_responses::OpenAIResponsesCodec), + codec: Arc::new(nemo_relay::codec::openai_responses::OpenAIResponsesCodec), + response_codec: Arc::new(nemo_relay::codec::openai_responses::OpenAIResponsesCodec), })) } /// Create a new Anthropic Messages API codec handle. /// /// The returned handle implements both request codec (decode/encode) and -/// response codec (decode_response). Free with `nemo_flow_codec_free`. +/// response codec (decode_response). Free with `nemo_relay_codec_free`. /// /// # Safety -/// Caller must free the returned handle via `nemo_flow_codec_free`. +/// Caller must free the returned handle via `nemo_relay_codec_free`. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_anthropic_messages_codec_new() -> *mut FfiCodecHandle { +pub extern "C" fn nemo_relay_anthropic_messages_codec_new() -> *mut FfiCodecHandle { Box::into_raw(Box::new(FfiCodecHandle { - codec: Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), - response_codec: Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), + codec: Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), + response_codec: Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), })) } struct ParsedExecuteInputs { name: String, request: LlmRequest, - parent_handle: Option, + parent_handle: Option, attrs: LlmAttributes, data: Option, metadata: Option, model_name: Option, - codec: Option>, - response_codec: Option>, + codec: Option>, + response_codec: Option>, } struct RawExecuteInputs { @@ -267,22 +268,22 @@ struct RawExecuteInputs { data_json: *const c_char, metadata_json: *const c_char, model_name: *const c_char, - codec_decode: NemoFlowCodecDecodeFn, - codec_encode: NemoFlowCodecEncodeFn, + codec_decode: NemoRelayCodecDecodeFn, + codec_encode: NemoRelayCodecEncodeFn, codec_user_data: *mut libc::c_void, - codec_free_fn: NemoFlowFreeFn, + codec_free_fn: NemoRelayFreeFn, response_codec: *const FfiCodecHandle, } -fn parse_llm_request(native_json: *const c_char) -> Result { - let native = c_str_to_json(native_json).ok_or(NemoFlowStatus::InvalidJson)?; +fn parse_llm_request(native_json: *const c_char) -> Result { + let native = c_str_to_json(native_json).ok_or(NemoRelayStatus::InvalidJson)?; serde_json::from_value(native).map_err(|_| { set_last_error("failed to parse native_json as LlmRequest"); - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson }) } -fn parse_optional_model_name(model_name: *const c_char) -> Result, NemoFlowStatus> { +fn parse_optional_model_name(model_name: *const c_char) -> Result, NemoRelayStatus> { if model_name.is_null() { Ok(None) } else { @@ -290,7 +291,7 @@ fn parse_optional_model_name(model_name: *const c_char) -> Result } } -fn parse_execute_inputs(raw: RawExecuteInputs) -> Result { +fn parse_execute_inputs(raw: RawExecuteInputs) -> Result { let name = c_str_to_string(raw.name)?; let request = parse_llm_request(raw.native_json)?; let parent_handle = if raw.parent.is_null() { @@ -299,8 +300,8 @@ fn parse_execute_inputs(raw: RawExecuteInputs) -> Result Some(wrap_codec_fn( @@ -314,7 +315,7 @@ fn parse_execute_inputs(raw: RawExecuteInputs) -> Result Result NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("null pointer argument"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let parsed = match parse_execute_inputs(RawExecuteInputs { name, @@ -427,7 +428,7 @@ pub unsafe extern "C" fn nemo_flow_llm_call_execute( match result { Ok(json) => { unsafe { *out = json_to_c_string(&json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -438,7 +439,7 @@ pub unsafe extern "C" fn nemo_flow_llm_call_execute( // --------------------------------------------------------------------------- /// Opaque stream handle for consuming LLM streaming responses chunk by chunk. -/// Use `nemo_flow_stream_next` to poll and `nemo_flow_stream_free` to release. +/// Use `nemo_relay_stream_next` to poll and `nemo_relay_stream_free` to release. pub struct FfiStream { pub(crate) receiver: tokio::sync::Mutex>>, @@ -446,7 +447,7 @@ pub struct FfiStream { /// Execute a streaming LLM call end-to-end. Conditional-execution guardrails /// run first on the raw request. Returns a stream handle that can be polled -/// with `nemo_flow_stream_next`. Blocks until the stream is set up. +/// with `nemo_relay_stream_next`. Blocks until the stream is set up. /// /// # Parameters /// - `name`: Null-terminated LLM provider name. @@ -471,30 +472,30 @@ pub struct FfiStream { /// `name`, `native_json`, and `out` must be valid, non-null pointers. `collector` /// and `finalizer` may be null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_stream_call_execute( +pub unsafe extern "C" fn nemo_relay_llm_stream_call_execute( name: *const c_char, native_json: *const c_char, - func: NemoFlowLlmExecCb, + func: NemoRelayLlmExecCb, func_user_data: *mut libc::c_void, - func_free: NemoFlowFreeFn, - collector: Option, - finalizer: Option, + func_free: NemoRelayFreeFn, + collector: Option, + finalizer: Option, parent: *const FfiScopeHandle, attributes: u32, data_json: *const c_char, metadata_json: *const c_char, model_name: *const c_char, - codec_decode: NemoFlowCodecDecodeFn, - codec_encode: NemoFlowCodecEncodeFn, + codec_decode: NemoRelayCodecDecodeFn, + codec_encode: NemoRelayCodecEncodeFn, codec_user_data: *mut libc::c_void, - codec_free_fn: NemoFlowFreeFn, + codec_free_fn: NemoRelayFreeFn, response_codec: *const FfiCodecHandle, out: *mut *mut FfiStream, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("null pointer argument"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let parsed = match parse_execute_inputs(RawExecuteInputs { name, @@ -564,7 +565,7 @@ pub unsafe extern "C" fn nemo_flow_llm_stream_call_execute( receiver: tokio::sync::Mutex::new(rx), }); unsafe { *out = Box::into_raw(ffi_stream) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -575,14 +576,14 @@ pub unsafe extern "C" fn nemo_flow_llm_stream_call_execute( /// /// # Returns /// - `1`: A chunk was written to `*out_chunk`. Caller must free with -/// `nemo_flow_string_free`. +/// `nemo_relay_string_free`. /// - `0`: The stream is complete (no more chunks). -/// - `-1`: An error occurred. Call `nemo_flow_last_error` for details. +/// - `-1`: An error occurred. Call `nemo_relay_last_error` for details. /// /// # Safety /// `stream` and `out_chunk` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_stream_next( +pub unsafe extern "C" fn nemo_relay_stream_next( stream: *mut FfiStream, out_chunk: *mut *mut c_char, ) -> i32 { @@ -612,9 +613,9 @@ pub unsafe extern "C" fn nemo_flow_stream_next( /// /// # Safety /// `stream` must be a valid `FfiStream` pointer returned by -/// `nemo_flow_llm_stream_call_execute`, or null. +/// `nemo_relay_llm_stream_call_execute`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_stream_free(stream: *mut FfiStream) { +pub unsafe extern "C" fn nemo_relay_stream_free(stream: *mut FfiStream) { if !stream.is_null() { drop(unsafe { Box::from_raw(stream) }); } diff --git a/crates/ffi/src/api/llm_registry.rs b/crates/ffi/src/api/llm_registry.rs index 5e64cf9cc..35fec0517 100644 --- a/crates/ffi/src/api/llm_registry.rs +++ b/crates/ffi/src/api/llm_registry.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - NemoFlowEventSubscriberCb, NemoFlowFreeFn, NemoFlowJsonCb, NemoFlowLlmConditionalCb, - NemoFlowLlmExecInterceptCb, NemoFlowLlmRequestCb, NemoFlowLlmRequestInterceptCb, - NemoFlowStatus, c_char, c_str_to_string, clear_last_error, core_registry_api, + NemoRelayEventSubscriberCb, NemoRelayFreeFn, NemoRelayJsonCb, NemoRelayLlmConditionalCb, + NemoRelayLlmExecInterceptCb, NemoRelayLlmRequestCb, NemoRelayLlmRequestInterceptCb, + NemoRelayStatus, c_char, c_str_to_string, clear_last_error, core_registry_api, core_subscriber_api, status_from_error, wrap_event_subscriber, wrap_llm_conditional_fn, wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, wrap_llm_response_fn, wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_intercept_fn, @@ -27,13 +27,13 @@ use super::{ /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_register_llm_sanitize_request_guardrail( name: *const c_char, priority: i32, - cb: NemoFlowLlmRequestCb, + cb: NemoRelayLlmRequestCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -41,7 +41,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_request_guardrail( }; let wrapped = wrap_llm_sanitize_request_fn(cb, user_data, free_fn); match core_registry_api::register_llm_sanitize_request_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -51,16 +51,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_request_guardrail( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_deregister_llm_sanitize_request_guardrail( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_sanitize_request_guardrail(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -78,13 +78,13 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_sanitize_request_guardrail( /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_register_llm_sanitize_response_guardrail( name: *const c_char, priority: i32, - cb: NemoFlowJsonCb, + cb: NemoRelayJsonCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -92,7 +92,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_response_guardrail( }; let wrapped = wrap_llm_response_fn(cb, user_data, free_fn); match core_registry_api::register_llm_sanitize_response_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -102,16 +102,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_sanitize_response_guardrail( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_deregister_llm_sanitize_response_guardrail( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_sanitize_response_guardrail(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -127,19 +127,19 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_sanitize_response_guardrail( /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal an internal callback failure instead of -/// allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C +/// allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C /// and return null. /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_register_llm_conditional_execution_guardrail( name: *const c_char, priority: i32, - cb: NemoFlowLlmConditionalCb, + cb: NemoRelayLlmConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -148,7 +148,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_conditional_execution_guardrail( let wrapped = wrap_llm_conditional_fn(cb, user_data, free_fn); match core_registry_api::register_llm_conditional_execution_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -158,16 +158,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_conditional_execution_guardrail( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_deregister_llm_conditional_execution_guardrail( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_conditional_execution_guardrail(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -188,19 +188,19 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_conditional_execution_guardrai /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal failure, call -/// [`crate::error::nemo_flow_set_last_error_message`] from C and return null. +/// [`crate::error::nemo_relay_set_last_error_message`] from C and return null. /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_request_intercept( +pub unsafe extern "C" fn nemo_relay_register_llm_request_intercept( name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowLlmRequestInterceptCb, + cb: NemoRelayLlmRequestInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -208,7 +208,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_request_intercept( }; let wrapped = wrap_llm_request_intercept_fn(cb, user_data, free_fn); match core_registry_api::register_llm_request_intercept(&name, priority, break_chain, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -218,16 +218,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_request_intercept( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_request_intercept( +pub unsafe extern "C" fn nemo_relay_deregister_llm_request_intercept( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_request_intercept(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -247,13 +247,13 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_request_intercept( /// # Safety /// `name` must be a valid C string. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_execution_intercept( +pub unsafe extern "C" fn nemo_relay_register_llm_execution_intercept( name: *const c_char, priority: i32, - exec_cb: NemoFlowLlmExecInterceptCb, + exec_cb: NemoRelayLlmExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -261,7 +261,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_execution_intercept( }; let exec = wrap_llm_exec_intercept_fn(exec_cb, exec_user_data, exec_free); match core_registry_api::register_llm_execution_intercept(&name, priority, exec) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -271,16 +271,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_execution_intercept( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_execution_intercept( +pub unsafe extern "C" fn nemo_relay_deregister_llm_execution_intercept( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_execution_intercept(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -300,13 +300,13 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_execution_intercept( /// # Safety /// `name` must be a valid C string. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_llm_stream_execution_intercept( +pub unsafe extern "C" fn nemo_relay_register_llm_stream_execution_intercept( name: *const c_char, priority: i32, - exec_cb: NemoFlowLlmExecInterceptCb, + exec_cb: NemoRelayLlmExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -314,7 +314,7 @@ pub unsafe extern "C" fn nemo_flow_register_llm_stream_execution_intercept( }; let exec = wrap_llm_stream_exec_intercept_fn(exec_cb, exec_user_data, exec_free); match core_registry_api::register_llm_stream_execution_intercept(&name, priority, exec) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -324,16 +324,16 @@ pub unsafe extern "C" fn nemo_flow_register_llm_stream_execution_intercept( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_llm_stream_execution_intercept( +pub unsafe extern "C" fn nemo_relay_deregister_llm_stream_execution_intercept( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_llm_stream_execution_intercept(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -354,12 +354,12 @@ pub unsafe extern "C" fn nemo_flow_deregister_llm_stream_execution_intercept( /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_subscriber( +pub unsafe extern "C" fn nemo_relay_register_subscriber( name: *const c_char, - cb: NemoFlowEventSubscriberCb, + cb: NemoRelayEventSubscriberCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -367,7 +367,7 @@ pub unsafe extern "C" fn nemo_flow_register_subscriber( }; let wrapped = wrap_event_subscriber(cb, user_data, free_fn); match core_subscriber_api::register_subscriber(&name, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -377,14 +377,14 @@ pub unsafe extern "C" fn nemo_flow_register_subscriber( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_subscriber(name: *const c_char) -> NemoFlowStatus { +pub unsafe extern "C" fn nemo_relay_deregister_subscriber(name: *const c_char) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_subscriber_api::deregister_subscriber(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } diff --git a/crates/ffi/src/api/mod.rs b/crates/ffi/src/api/mod.rs index 52ba10e5e..a1d6fffdc 100644 --- a/crates/ffi/src/api/mod.rs +++ b/crates/ffi/src/api/mod.rs @@ -4,7 +4,7 @@ //! Top-level FFI API functions exported as `extern "C"`. //! //! Each function clears the thread-local error before executing and returns an -//! [`NemoFlowStatus`]. On failure, call [`nemo_flow_last_error`] to retrieve +//! [`NemoRelayStatus`]. On failure, call [`nemo_relay_last_error`] to retrieve //! the error message. use std::ffi::CStr; @@ -14,53 +14,53 @@ use std::sync::{Arc, OnceLock}; use std::time::Duration; use crate::callable::{ - NemoFlowCodecDecodeFn, NemoFlowCodecEncodeFn, NemoFlowCollectorCb, NemoFlowEventSubscriberCb, - NemoFlowFinalizerCb, NemoFlowFreeFn, NemoFlowJsonCb, NemoFlowLlmConditionalCb, - NemoFlowLlmExecCb, NemoFlowLlmExecInterceptCb, NemoFlowLlmRequestCb, - NemoFlowLlmRequestInterceptCb, NemoFlowPluginRegisterCb, NemoFlowPluginValidateCb, - NemoFlowToolConditionalCb, NemoFlowToolExecCb, NemoFlowToolExecInterceptCb, - NemoFlowToolSanitizeCb, wrap_codec_fn, wrap_collector_fn, wrap_event_subscriber, - wrap_finalizer_fn, wrap_llm_conditional_fn, wrap_llm_exec_fn, wrap_llm_exec_intercept_fn, - wrap_llm_request_intercept_fn, wrap_llm_response_fn, wrap_llm_sanitize_request_fn, - wrap_llm_stream_exec_fn, wrap_llm_stream_exec_intercept_fn, wrap_tool_conditional_fn, - wrap_tool_exec_fn, wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, - wrap_tool_sanitize_fn, + NemoRelayCodecDecodeFn, NemoRelayCodecEncodeFn, NemoRelayCollectorCb, + NemoRelayEventSubscriberCb, NemoRelayFinalizerCb, NemoRelayFreeFn, NemoRelayJsonCb, + NemoRelayLlmConditionalCb, NemoRelayLlmExecCb, NemoRelayLlmExecInterceptCb, + NemoRelayLlmRequestCb, NemoRelayLlmRequestInterceptCb, NemoRelayPluginRegisterCb, + NemoRelayPluginValidateCb, NemoRelayToolConditionalCb, NemoRelayToolExecCb, + NemoRelayToolExecInterceptCb, NemoRelayToolSanitizeCb, wrap_codec_fn, wrap_collector_fn, + wrap_event_subscriber, wrap_finalizer_fn, wrap_llm_conditional_fn, wrap_llm_exec_fn, + wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, wrap_llm_response_fn, + wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_fn, wrap_llm_stream_exec_intercept_fn, + wrap_tool_conditional_fn, wrap_tool_exec_fn, wrap_tool_exec_intercept_fn, + wrap_tool_request_intercept_fn, wrap_tool_sanitize_fn, }; use crate::convert::{ - c_str_to_json, c_str_to_opt_json, c_str_to_string, json_to_c_string, nemo_flow_string_free, + c_str_to_json, c_str_to_opt_json, c_str_to_string, json_to_c_string, nemo_relay_string_free, str_to_c_string, unix_micros_to_opt_timestamp, }; use crate::error::{ - NemoFlowStatus, clear_last_error, last_error_message, set_last_error, status_from_error, + NemoRelayStatus, clear_last_error, last_error_message, set_last_error, status_from_error, status_from_plugin_error, }; use crate::types::{ FfiAtifExporter, FfiAtofExporter, FfiCodecHandle, FfiLLMHandle, FfiOpenInferenceSubscriber, FfiOpenTelemetrySubscriber, FfiPluginContext, FfiScopeHandle, FfiScopeStack, - FfiThreadScopeStackBinding, FfiToolHandle, NemoFlowScopeType, + FfiThreadScopeStackBinding, FfiToolHandle, NemoRelayScopeType, }; -pub use crate::types::{nemo_flow_openinference_subscriber_free, nemo_flow_otel_subscriber_free}; +pub use crate::types::{nemo_relay_openinference_subscriber_free, nemo_relay_otel_subscriber_free}; use libc::c_char; -use nemo_flow::api::llm as core_llm_api; -use nemo_flow::api::llm::{LlmAttributes, LlmRequest}; -use nemo_flow::api::registry as core_registry_api; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::runtime::{ +use nemo_relay::api::llm as core_llm_api; +use nemo_relay::api::llm::{LlmAttributes, LlmRequest}; +use nemo_relay::api::registry as core_registry_api; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::runtime::{ TASK_SCOPE_STACK, capture_thread_scope_stack, create_scope_stack, current_scope_stack, restore_thread_scope_stack, scope_stack_active, set_thread_scope_stack, }; -use nemo_flow::api::scope as core_scope_api; -use nemo_flow::api::scope::ScopeAttributes; -use nemo_flow::api::subscriber as core_subscriber_api; -use nemo_flow::api::tool as core_tool_api; -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::error::Result as FlowResult; -use nemo_flow::plugin::{ +use nemo_relay::api::scope as core_scope_api; +use nemo_relay::api::scope::ScopeAttributes; +use nemo_relay::api::subscriber as core_subscriber_api; +use nemo_relay::api::tool as core_tool_api; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::error::Result as FlowResult; +use nemo_relay::plugin::{ ConfigDiagnostic, DiagnosticLevel, Plugin, PluginConfig, PluginError, PluginRegistrationContext, active_plugin_report, clear_plugin_configuration, deregister_plugin, initialize_plugins, list_plugin_kinds, register_plugin, validate_plugin_config, }; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use tokio::runtime::Runtime; mod llm; @@ -106,20 +106,20 @@ fn tokio_runtime() -> &'static Runtime { /// - `name`: Tool name (null-terminated C string). /// - `args_json`: Tool arguments as a JSON C string. /// - `out`: On success, receives the transformed JSON string (caller must free -/// with `nemo_flow_string_free`). +/// with `nemo_relay_string_free`). /// /// # Returns -/// Returns [`NemoFlowStatus::Ok`] on success and writes the transformed JSON +/// Returns [`NemoRelayStatus::Ok`] on success and writes the transformed JSON /// string to `out`. /// /// # Safety /// All pointers must be valid. `out` must be non-null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_request_intercepts( +pub unsafe extern "C" fn nemo_relay_tool_request_intercepts( name: *const c_char, args_json: *const c_char, out: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -127,12 +127,12 @@ pub unsafe extern "C" fn nemo_flow_tool_request_intercepts( }; let args = match c_str_to_json(args_json) { Some(a) => a, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; match core_tool_api::tool_request_intercepts(&name, args) { Ok(result) => { unsafe { *out = json_to_c_string(&result) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -140,24 +140,24 @@ pub unsafe extern "C" fn nemo_flow_tool_request_intercepts( /// Run the registered tool conditional execution guardrail chain. /// -/// Returns `NemoFlowStatus::Ok` if all guardrails pass, or -/// `NemoFlowStatus::GuardrailRejected` if blocked. +/// Returns `NemoRelayStatus::Ok` if all guardrails pass, or +/// `NemoRelayStatus::GuardrailRejected` if blocked. /// /// # Parameters /// - `name`: Tool name (null-terminated C string). /// - `args_json`: Tool arguments as a JSON C string. /// /// # Returns -/// Returns [`NemoFlowStatus::Ok`] when execution is allowed and -/// [`NemoFlowStatus::GuardrailRejected`] when a guardrail blocks the call. +/// Returns [`NemoRelayStatus::Ok`] when execution is allowed and +/// [`NemoRelayStatus::GuardrailRejected`] when a guardrail blocks the call. /// /// # Safety /// All pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_conditional_execution( +pub unsafe extern "C" fn nemo_relay_tool_conditional_execution( name: *const c_char, args_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -165,10 +165,10 @@ pub unsafe extern "C" fn nemo_flow_tool_conditional_execution( }; let args = match c_str_to_json(args_json) { Some(a) => a, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; match core_tool_api::tool_conditional_execution(&name, &args) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -184,20 +184,20 @@ pub unsafe extern "C" fn nemo_flow_tool_conditional_execution( /// - `native_json`: The request payload as a JSON C string representing an /// `LlmRequest` (`{"headers": {...}, "content": {...}}`). /// - `out`: On success, receives the transformed JSON string (caller must free -/// with `nemo_flow_string_free`). The output is a serialized `LlmRequest`. +/// with `nemo_relay_string_free`). The output is a serialized `LlmRequest`. /// /// # Returns -/// Returns [`NemoFlowStatus::Ok`] on success and writes the transformed +/// Returns [`NemoRelayStatus::Ok`] on success and writes the transformed /// serialized request to `out`. /// /// # Safety /// All pointers must be valid. `out` must be non-null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_request_intercepts( +pub unsafe extern "C" fn nemo_relay_llm_request_intercepts( name: *const c_char, native_json: *const c_char, out: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name_str = if name.is_null() { "" @@ -206,20 +206,20 @@ pub unsafe extern "C" fn nemo_flow_llm_request_intercepts( }; let native = match c_str_to_json(native_json) { Some(j) => j, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let request: LlmRequest = match serde_json::from_value(native) { Ok(r) => r, Err(_) => { set_last_error("failed to parse native_json as LlmRequest"); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } }; match core_llm_api::llm_request_intercepts(name_str, request) { Ok(transformed) => { let result_json = serde_json::to_value(&transformed).unwrap_or(serde_json::Value::Null); unsafe { *out = json_to_c_string(&result_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -227,37 +227,37 @@ pub unsafe extern "C" fn nemo_flow_llm_request_intercepts( /// Run the registered LLM conditional execution guardrail chain. /// -/// Returns `NemoFlowStatus::Ok` if all guardrails pass, or -/// `NemoFlowStatus::GuardrailRejected` if blocked. +/// Returns `NemoRelayStatus::Ok` if all guardrails pass, or +/// `NemoRelayStatus::GuardrailRejected` if blocked. /// /// # Parameters /// - `native_json`: The request payload as a JSON C string representing an /// `LlmRequest` (`{"headers": {...}, "content": {...}}`). /// /// # Returns -/// Returns [`NemoFlowStatus::Ok`] when execution is allowed and -/// [`NemoFlowStatus::GuardrailRejected`] when a guardrail blocks the call. +/// Returns [`NemoRelayStatus::Ok`] when execution is allowed and +/// [`NemoRelayStatus::GuardrailRejected`] when a guardrail blocks the call. /// /// # Safety /// All pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_conditional_execution( +pub unsafe extern "C" fn nemo_relay_llm_conditional_execution( native_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let native = match c_str_to_json(native_json) { Some(j) => j, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let request: LlmRequest = match serde_json::from_value(native) { Ok(r) => r, Err(_) => { set_last_error("failed to parse native_json as LlmRequest"); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } }; match core_llm_api::llm_conditional_execution(&request) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } diff --git a/crates/ffi/src/api/observability.rs b/crates/ffi/src/api/observability.rs index 971026b84..d6e8d84b4 100644 --- a/crates/ffi/src/api/observability.rs +++ b/crates/ffi/src/api/observability.rs @@ -3,27 +3,27 @@ use super::{ Duration, FfiAtifExporter, FfiAtofExporter, FfiOpenInferenceSubscriber, - FfiOpenTelemetrySubscriber, NemoFlowStatus, c_char, c_str_to_json, c_str_to_string, + FfiOpenTelemetrySubscriber, NemoRelayStatus, c_char, c_str_to_json, c_str_to_string, clear_last_error, core_subscriber_api, json_to_c_string, set_last_error, status_from_error, str_to_c_string, tokio_runtime, }; -type AtofExporter = nemo_flow::observability::atof::AtofExporter; -type AtofExporterConfig = nemo_flow::observability::atof::AtofExporterConfig; -type AtofExporterError = nemo_flow::observability::atof::AtofExporterError; -type AtofExporterMode = nemo_flow::observability::atof::AtofExporterMode; -type OpenTelemetryConfig = nemo_flow::observability::otel::OpenTelemetryConfig; -type OpenTelemetrySubscriber = nemo_flow::observability::otel::OpenTelemetrySubscriber; -type OpenInferenceConfig = nemo_flow::observability::openinference::OpenInferenceConfig; -type OpenInferenceSubscriber = nemo_flow::observability::openinference::OpenInferenceSubscriber; -type ObservabilityComponentSpec = nemo_flow::observability::plugin_component::ComponentSpec; -type ObservabilityConfig = nemo_flow::observability::plugin_component::ObservabilityConfig; - -fn status_from_atof_error(error: &AtofExporterError) -> NemoFlowStatus { +type AtofExporter = nemo_relay::observability::atof::AtofExporter; +type AtofExporterConfig = nemo_relay::observability::atof::AtofExporterConfig; +type AtofExporterError = nemo_relay::observability::atof::AtofExporterError; +type AtofExporterMode = nemo_relay::observability::atof::AtofExporterMode; +type OpenTelemetryConfig = nemo_relay::observability::otel::OpenTelemetryConfig; +type OpenTelemetrySubscriber = nemo_relay::observability::otel::OpenTelemetrySubscriber; +type OpenInferenceConfig = nemo_relay::observability::openinference::OpenInferenceConfig; +type OpenInferenceSubscriber = nemo_relay::observability::openinference::OpenInferenceSubscriber; +type ObservabilityComponentSpec = nemo_relay::observability::plugin_component::ComponentSpec; +type ObservabilityConfig = nemo_relay::observability::plugin_component::ObservabilityConfig; + +fn status_from_atof_error(error: &AtofExporterError) -> NemoRelayStatus { set_last_error(&error.to_string()); match error { AtofExporterError::Runtime(error) => status_from_error(error), - _ => NemoFlowStatus::Internal, + _ => NemoRelayStatus::Internal, } } @@ -33,10 +33,10 @@ fn status_from_atof_error(error: &AtofExporterError) -> NemoFlowStatus { /// Return the built-in observability plugin kind. /// -/// The caller owns the returned string and must free it with `nemo_flow_string_free`. +/// The caller owns the returned string and must free it with `nemo_relay_string_free`. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_observability_plugin_kind() -> *mut c_char { - str_to_c_string(nemo_flow::observability::plugin_component::OBSERVABILITY_PLUGIN_KIND) +pub extern "C" fn nemo_relay_observability_plugin_kind() -> *mut c_char { + str_to_c_string(nemo_relay::observability::plugin_component::OBSERVABILITY_PLUGIN_KIND) } /// Return the default observability plugin config as JSON. @@ -44,23 +44,23 @@ pub extern "C" fn nemo_flow_observability_plugin_kind() -> *mut c_char { /// # Safety /// `out_json` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_observability_default_config_json( +pub unsafe extern "C" fn nemo_relay_observability_default_config_json( out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let config_json = match serde_json::to_value(ObservabilityConfig::default()) { Ok(value) => value, Err(error) => { set_last_error(&error.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&config_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Wrap an observability config JSON object as a top-level plugin component. @@ -72,41 +72,41 @@ pub unsafe extern "C" fn nemo_flow_observability_default_config_json( /// `config_json`, when non-null, must be a valid C string. `out_json` must be a /// valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_observability_component_spec_json( +pub unsafe extern "C" fn nemo_relay_observability_component_spec_json( config_json: *const c_char, enabled: bool, out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let config = if config_json.is_null() { ObservabilityConfig::default() } else { let Some(config_value) = c_str_to_json(config_json) else { - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; }; match serde_json::from_value::(config_value) { Ok(config) => config, Err(error) => { set_last_error(&error.to_string()); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } } }; - let component: nemo_flow::plugin::PluginComponentSpec = + let component: nemo_relay::plugin::PluginComponentSpec = ObservabilityComponentSpec { enabled, config }.into(); let component_json = match serde_json::to_value(component) { Ok(value) => value, Err(error) => { set_last_error(&error.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&component_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } // --------------------------------------------------------------------------- @@ -125,17 +125,17 @@ pub unsafe extern "C" fn nemo_flow_observability_component_spec_json( /// # Safety /// All non-null string pointers must be valid C strings. `out` must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_create( +pub unsafe extern "C" fn nemo_relay_atif_exporter_create( session_id: *const c_char, agent_name: *const c_char, agent_version: *const c_char, model_name: *const c_char, out: *mut *mut FfiAtifExporter, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let session_id = match c_str_to_string(session_id) { Ok(s) => s, @@ -158,7 +158,7 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_create( } }; - let agent_info = nemo_flow::observability::atif::AtifAgentInfo { + let agent_info = nemo_relay::observability::atif::AtifAgentInfo { name: agent_name, version: agent_version, model_name: model_name_opt, @@ -166,9 +166,9 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_create( extra: None, }; - let exporter = nemo_flow::observability::atif::AtifExporter::new(session_id, agent_info); + let exporter = nemo_relay::observability::atif::AtifExporter::new(session_id, agent_info); unsafe { *out = Box::into_raw(Box::new(FfiAtifExporter(exporter))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Registers the exporter as an event subscriber. @@ -180,14 +180,14 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_create( /// # Safety /// `exporter` and `name` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_register( +pub unsafe extern "C" fn nemo_relay_atif_exporter_register( exporter: *const FfiAtifExporter, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -195,7 +195,7 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_register( }; let subscriber = unsafe { &*exporter }.0.subscriber(); match core_subscriber_api::register_subscriber(&name, subscriber) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -208,14 +208,16 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_register( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_deregister(name: *const c_char) -> NemoFlowStatus { +pub unsafe extern "C" fn nemo_relay_atif_exporter_deregister( + name: *const c_char, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_subscriber_api::deregister_subscriber(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -225,33 +227,33 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_deregister(name: *const c_char) /// # Parameters /// - `exporter`: The exporter handle. /// - `out`: On success, receives a JSON string (caller must free with -/// `nemo_flow_string_free`). +/// `nemo_relay_string_free`). /// /// # Safety /// `exporter` and `out` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_export( +pub unsafe extern "C" fn nemo_relay_atif_exporter_export( exporter: *const FfiAtifExporter, out: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let trajectory = unsafe { &*exporter }.0.export(); match serde_json::to_string(&trajectory) { Ok(json_str) => { unsafe { *out = str_to_c_string(&json_str) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => { set_last_error(&format!("failed to serialize trajectory: {e}")); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -264,16 +266,16 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_export( /// # Safety /// `exporter` must be a valid, non-null `FfiAtifExporter` pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_clear( +pub unsafe extern "C" fn nemo_relay_atif_exporter_clear( exporter: *const FfiAtifExporter, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } unsafe { &*exporter }.0.clear(); - NemoFlowStatus::Ok + NemoRelayStatus::Ok } // --------------------------------------------------------------------------- @@ -291,12 +293,12 @@ pub unsafe extern "C" fn nemo_flow_atif_exporter_clear( /// # Safety /// All non-null string pointers must be valid C strings. `out` must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_create( +pub unsafe extern "C" fn nemo_relay_atof_exporter_create( output_directory: *const c_char, mode: *const c_char, filename: *const c_char, out: *mut *mut FfiAtofExporter, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if let Err(status) = required_out_ptr(out) { return status; @@ -317,7 +319,7 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_create( let Some(mode) = AtofExporterMode::parse(&mode) else { set_last_error("ATOF exporter mode must be 'append' or 'overwrite'"); - return NemoFlowStatus::InvalidArg; + return NemoRelayStatus::InvalidArg; }; let mut config = AtofExporterConfig::new().with_mode(mode); @@ -331,7 +333,7 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_create( match AtofExporter::new(config) { Ok(exporter) => { unsafe { *out = Box::into_raw(Box::new(FfiAtofExporter(exporter))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(error) => status_from_atof_error(&error), } @@ -342,21 +344,21 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_create( /// # Safety /// `exporter` and `name` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_register( +pub unsafe extern "C" fn nemo_relay_atof_exporter_register( exporter: *const FfiAtofExporter, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match unsafe { &*exporter }.0.register(&name) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(error) => status_from_atof_error(&error), } } @@ -366,14 +368,16 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_register( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_deregister(name: *const c_char) -> NemoFlowStatus { +pub unsafe extern "C" fn nemo_relay_atof_exporter_deregister( + name: *const c_char, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_subscriber_api::deregister_subscriber(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -383,16 +387,16 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_deregister(name: *const c_char) /// # Safety /// `exporter` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_force_flush( +pub unsafe extern "C" fn nemo_relay_atof_exporter_force_flush( exporter: *const FfiAtofExporter, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*exporter }.0.force_flush() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(error) => status_from_atof_error(&error), } } @@ -402,16 +406,16 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_force_flush( /// # Safety /// `exporter` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_shutdown( +pub unsafe extern "C" fn nemo_relay_atof_exporter_shutdown( exporter: *const FfiAtofExporter, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*exporter }.0.shutdown() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(error) => status_from_atof_error(&error), } } @@ -421,22 +425,22 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_shutdown( /// # Safety /// `exporter` and `out` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_path( +pub unsafe extern "C" fn nemo_relay_atof_exporter_path( exporter: *const FfiAtofExporter, out: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if exporter.is_null() { set_last_error("exporter pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let path = unsafe { &*exporter }.0.path().to_string_lossy(); unsafe { *out = str_to_c_string(&path) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } // --------------------------------------------------------------------------- @@ -446,7 +450,7 @@ pub unsafe extern "C" fn nemo_flow_atof_exporter_path( fn parse_string_map_json( json_ptr: *const c_char, field_name: &str, -) -> Result, NemoFlowStatus> { +) -> Result, NemoRelayStatus> { if json_ptr.is_null() { return Ok(std::collections::HashMap::new()); } @@ -454,14 +458,14 @@ fn parse_string_map_json( let json_string = c_str_to_string(json_ptr)?; let value: serde_json::Value = serde_json::from_str(&json_string).map_err(|e| { set_last_error(&format!("invalid {field_name} JSON: {e}")); - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson })?; let serde_json::Value::Object(map) = value else { set_last_error(&format!( "{field_name} must be a JSON object of string values" )); - return Err(NemoFlowStatus::InvalidArg); + return Err(NemoRelayStatus::InvalidArg); }; let mut out = std::collections::HashMap::with_capacity(map.len()); @@ -470,22 +474,22 @@ fn parse_string_map_json( set_last_error(&format!( "{field_name} must be a JSON object of string values" )); - return Err(NemoFlowStatus::InvalidArg); + return Err(NemoRelayStatus::InvalidArg); }; out.insert(key, value); } Ok(out) } -fn required_out_ptr(out: *mut *mut T) -> Result<(), NemoFlowStatus> { +fn required_out_ptr(out: *mut *mut T) -> Result<(), NemoRelayStatus> { if out.is_null() { set_last_error("out pointer is null"); - return Err(NemoFlowStatus::NullPointer); + return Err(NemoRelayStatus::NullPointer); } Ok(()) } -fn parse_optional_string(ptr: *const c_char) -> Result, NemoFlowStatus> { +fn parse_optional_string(ptr: *const c_char) -> Result, NemoRelayStatus> { if ptr.is_null() { Ok(None) } else { @@ -493,11 +497,15 @@ fn parse_optional_string(ptr: *const c_char) -> Result, NemoFlowS } } -fn parse_string_or_default(ptr: *const c_char, default: &str) -> Result { +fn parse_string_or_default(ptr: *const c_char, default: &str) -> Result { parse_optional_string(ptr).map(|value| value.unwrap_or_else(|| default.to_string())) } -fn apply_optional_string(config: T, ptr: *const c_char, apply: F) -> Result +fn apply_optional_string( + config: T, + ptr: *const c_char, + apply: F, +) -> Result where F: FnOnce(T, String) -> T, { @@ -523,7 +531,7 @@ fn apply_string_map( json_ptr: *const c_char, field_name: &str, mut apply: F, -) -> Result +) -> Result where F: FnMut(T, String, String) -> T, { @@ -533,14 +541,14 @@ where Ok(config) } -fn parse_transport(ptr: *const c_char) -> Result { +fn parse_transport(ptr: *const c_char) -> Result { parse_string_or_default(ptr, "http_binary") } fn otel_config_for_transport( transport: &str, service_name: String, -) -> Result { +) -> Result { match transport { "http_binary" => Ok(OpenTelemetryConfig::http_binary(service_name)), "grpc" => Ok(OpenTelemetryConfig::grpc(service_name)), @@ -548,45 +556,45 @@ fn otel_config_for_transport( set_last_error(&format!( "transport must be 'http_binary' or 'grpc', got {other:?}" )); - Err(NemoFlowStatus::InvalidArg) + Err(NemoRelayStatus::InvalidArg) } } } fn openinference_config_for_transport( transport: &str, -) -> Result { +) -> Result { match transport { "http_binary" => Ok(OpenInferenceConfig::new() - .with_transport(nemo_flow::observability::openinference::OtlpTransport::HttpBinary)), + .with_transport(nemo_relay::observability::openinference::OtlpTransport::HttpBinary)), "grpc" => Ok(OpenInferenceConfig::new() - .with_transport(nemo_flow::observability::openinference::OtlpTransport::Grpc)), + .with_transport(nemo_relay::observability::openinference::OtlpTransport::Grpc)), other => { set_last_error(&format!( "transport must be 'http_binary' or 'grpc', got {other:?}" )); - Err(NemoFlowStatus::InvalidArg) + Err(NemoRelayStatus::InvalidArg) } } } fn create_otel_subscriber( config: OpenTelemetryConfig, -) -> Result { +) -> Result { let _runtime_guard = tokio_runtime().enter(); OpenTelemetrySubscriber::new(config).map_err(|error| { set_last_error(&error.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal }) } fn create_openinference_subscriber( config: OpenInferenceConfig, -) -> Result { +) -> Result { let _runtime_guard = tokio_runtime().enter(); OpenInferenceSubscriber::new(config).map_err(|error| { set_last_error(&error.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal }) } @@ -599,7 +607,7 @@ fn create_openinference_subscriber( /// # Safety /// Any non-null C strings must be valid and `out` must be non-null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_create( +pub unsafe extern "C" fn nemo_relay_otel_subscriber_create( transport: *const c_char, endpoint: *const c_char, headers_json: *const c_char, @@ -610,7 +618,7 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_create( instrumentation_scope: *const c_char, timeout_millis: u64, out: *mut *mut FfiOpenTelemetrySubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if let Err(status) = required_out_ptr(out) { return status; @@ -620,7 +628,7 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_create( Ok(value) => value, Err(status) => return status, }; - let service_name = match parse_string_or_default(service_name, "nemo-flow") { + let service_name = match parse_string_or_default(service_name, "nemo-relay") { Ok(value) => value, Err(status) => return status, }; @@ -682,7 +690,7 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_create( Err(status) => return status, }; unsafe { *out = Box::into_raw(Box::new(FfiOpenTelemetrySubscriber(subscriber))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Registers the OpenTelemetry subscriber as an event subscriber. @@ -690,14 +698,14 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_create( /// # Safety /// `subscriber` and `name` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_register( +pub unsafe extern "C" fn nemo_relay_otel_subscriber_register( subscriber: *const FfiOpenTelemetrySubscriber, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -705,10 +713,10 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_register( }; match unsafe { &*subscriber }.0.register(&name) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -718,9 +726,9 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_register( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_deregister( +pub unsafe extern "C" fn nemo_relay_otel_subscriber_deregister( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -728,7 +736,7 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_deregister( }; match core_subscriber_api::deregister_subscriber(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -738,20 +746,20 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_deregister( /// # Safety /// `subscriber` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_force_flush( +pub unsafe extern "C" fn nemo_relay_otel_subscriber_force_flush( subscriber: *const FfiOpenTelemetrySubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*subscriber }.0.force_flush() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -761,20 +769,20 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_force_flush( /// # Safety /// `subscriber` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_shutdown( +pub unsafe extern "C" fn nemo_relay_otel_subscriber_shutdown( subscriber: *const FfiOpenTelemetrySubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*subscriber }.0.shutdown() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -788,7 +796,7 @@ pub unsafe extern "C" fn nemo_flow_otel_subscriber_shutdown( /// # Safety /// Any non-null C strings must be valid and `out` must be non-null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_create( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_create( transport: *const c_char, endpoint: *const c_char, headers_json: *const c_char, @@ -799,7 +807,7 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_create( instrumentation_scope: *const c_char, timeout_millis: u64, out: *mut *mut FfiOpenInferenceSubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if let Err(status) = required_out_ptr(out) { return status; @@ -871,7 +879,7 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_create( Err(status) => return status, }; unsafe { *out = Box::into_raw(Box::new(FfiOpenInferenceSubscriber(subscriber))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Registers the OpenInference subscriber as an event subscriber. @@ -879,14 +887,14 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_create( /// # Safety /// `subscriber` and `name` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_register( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_register( subscriber: *const FfiOpenInferenceSubscriber, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -894,10 +902,10 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_register( }; match unsafe { &*subscriber }.0.register(&name) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -907,9 +915,9 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_register( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_deregister( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_deregister( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -917,7 +925,7 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_deregister( }; match core_subscriber_api::deregister_subscriber(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -927,20 +935,20 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_deregister( /// # Safety /// `subscriber` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_force_flush( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_force_flush( subscriber: *const FfiOpenInferenceSubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*subscriber }.0.force_flush() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } @@ -950,20 +958,20 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_force_flush( /// # Safety /// `subscriber` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_shutdown( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_shutdown( subscriber: *const FfiOpenInferenceSubscriber, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if subscriber.is_null() { set_last_error("subscriber pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match unsafe { &*subscriber }.0.shutdown() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => { set_last_error(&e.to_string()); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } } } diff --git a/crates/ffi/src/api/plugin.rs b/crates/ffi/src/api/plugin.rs index 8a7ad25fb..ad795e494 100644 --- a/crates/ffi/src/api/plugin.rs +++ b/crates/ffi/src/api/plugin.rs @@ -3,23 +3,24 @@ use super::{ Arc, CStr, ConfigDiagnostic, DiagnosticLevel, FfiPluginContext, Future, - NemoFlowEventSubscriberCb, NemoFlowFreeFn, NemoFlowJsonCb, NemoFlowLlmConditionalCb, - NemoFlowLlmExecInterceptCb, NemoFlowLlmRequestCb, NemoFlowLlmRequestInterceptCb, - NemoFlowPluginRegisterCb, NemoFlowPluginValidateCb, NemoFlowStatus, NemoFlowToolConditionalCb, - NemoFlowToolExecInterceptCb, NemoFlowToolSanitizeCb, Pin, Plugin, PluginConfig, PluginError, - PluginRegistrationContext, active_plugin_report, c_char, c_str_to_json, c_str_to_string, - clear_last_error, clear_plugin_configuration, deregister_plugin, initialize_plugins, - json_to_c_string, last_error_message, list_plugin_kinds, nemo_flow_string_free, - register_adaptive_component, register_plugin, set_last_error, status_from_plugin_error, - tokio_runtime, validate_plugin_config, wrap_event_subscriber, wrap_llm_conditional_fn, - wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, wrap_llm_response_fn, - wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_intercept_fn, wrap_tool_conditional_fn, - wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, wrap_tool_sanitize_fn, + NemoRelayEventSubscriberCb, NemoRelayFreeFn, NemoRelayJsonCb, NemoRelayLlmConditionalCb, + NemoRelayLlmExecInterceptCb, NemoRelayLlmRequestCb, NemoRelayLlmRequestInterceptCb, + NemoRelayPluginRegisterCb, NemoRelayPluginValidateCb, NemoRelayStatus, + NemoRelayToolConditionalCb, NemoRelayToolExecInterceptCb, NemoRelayToolSanitizeCb, Pin, Plugin, + PluginConfig, PluginError, PluginRegistrationContext, active_plugin_report, c_char, + c_str_to_json, c_str_to_string, clear_last_error, clear_plugin_configuration, + deregister_plugin, initialize_plugins, json_to_c_string, last_error_message, list_plugin_kinds, + nemo_relay_string_free, register_adaptive_component, register_plugin, set_last_error, + status_from_plugin_error, tokio_runtime, validate_plugin_config, wrap_event_subscriber, + wrap_llm_conditional_fn, wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, + wrap_llm_response_fn, wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_intercept_fn, + wrap_tool_conditional_fn, wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, + wrap_tool_sanitize_fn, }; struct FfiHostedPluginUserData { ptr: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, } unsafe impl Send for FfiHostedPluginUserData {} @@ -35,8 +36,8 @@ impl Drop for FfiHostedPluginUserData { struct FfiHostedPluginAdapter { plugin_kind: String, - validate_cb: Option, - register_cb: NemoFlowPluginRegisterCb, + validate_cb: Option, + register_cb: NemoRelayPluginRegisterCb, user_data: Arc, } @@ -57,7 +58,7 @@ impl Plugin for FfiHostedPluginAdapter { let plugin_config_json = json_to_c_string(&serde_json::Value::Object(plugin_config.clone())); let result_ptr = unsafe { validate_cb(self.user_data.ptr, plugin_config_json) }; - unsafe { nemo_flow_string_free(plugin_config_json) }; + unsafe { nemo_relay_string_free(plugin_config_json) }; if result_ptr.is_null() { let message = last_error_message().unwrap_or_else(|| { @@ -79,7 +80,7 @@ impl Plugin for FfiHostedPluginAdapter { .to_str() .ok() .and_then(|text| serde_json::from_str::>(text).ok()); - unsafe { nemo_flow_string_free(result_ptr) }; + unsafe { nemo_relay_string_free(result_ptr) }; diagnostics.unwrap_or_else(|| { vec![ConfigDiagnostic { level: DiagnosticLevel::Error, @@ -106,8 +107,8 @@ impl Plugin for FfiHostedPluginAdapter { let mut ffi_ctx = FfiPluginContext(ctx as *mut _); let status = unsafe { (self.register_cb)(self.user_data.ptr, plugin_config_json, &mut ffi_ctx) }; - unsafe { nemo_flow_string_free(plugin_config_json) }; - if status == NemoFlowStatus::Ok { + unsafe { nemo_relay_string_free(plugin_config_json) }; + if status == NemoRelayStatus::Ok { Ok(()) } else if let Some(message) = last_error_message() { Err(PluginError::RegistrationFailed(message)) @@ -121,7 +122,7 @@ impl Plugin for FfiHostedPluginAdapter { } } -fn ensure_adaptive_component_registered() -> std::result::Result<(), NemoFlowStatus> { +fn ensure_adaptive_component_registered() -> std::result::Result<(), NemoRelayStatus> { register_adaptive_component().map_err(|err| status_from_plugin_error(&err)) } @@ -130,38 +131,38 @@ fn ensure_adaptive_component_registered() -> std::result::Result<(), NemoFlowSta /// # Safety /// `config_json` must be a valid C string and `out_json` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_validate_plugin_config( +pub unsafe extern "C" fn nemo_relay_validate_plugin_config( config_json: *const c_char, out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } if let Err(status) = ensure_adaptive_component_registered() { return status; } let config_value = match c_str_to_json(config_json) { Some(value) => value, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let config: PluginConfig = match serde_json::from_value(config_value) { Ok(config) => config, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } }; let report_json = match serde_json::to_value(validate_plugin_config(&config)) { Ok(value) => value, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&report_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Initialize the active global plugin components and return the resulting diagnostics report. @@ -169,27 +170,27 @@ pub unsafe extern "C" fn nemo_flow_validate_plugin_config( /// # Safety /// `config_json` must be a valid C string and `out_json` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_initialize_plugins( +pub unsafe extern "C" fn nemo_relay_initialize_plugins( config_json: *const c_char, out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } if let Err(status) = ensure_adaptive_component_registered() { return status; } let config_value = match c_str_to_json(config_json) { Some(value) => value, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let config: PluginConfig = match serde_json::from_value(config_value) { Ok(config) => config, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::InvalidJson; + return NemoRelayStatus::InvalidJson; } }; let report = match tokio_runtime().block_on(initialize_plugins(config)) { @@ -200,19 +201,19 @@ pub unsafe extern "C" fn nemo_flow_initialize_plugins( Ok(value) => value, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&report_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Clear the active global plugin configuration. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_clear_plugin_configuration() -> NemoFlowStatus { +pub extern "C" fn nemo_relay_clear_plugin_configuration() -> NemoRelayStatus { clear_last_error(); match clear_plugin_configuration() { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -222,23 +223,23 @@ pub extern "C" fn nemo_flow_clear_plugin_configuration() -> NemoFlowStatus { /// # Safety /// `out_json` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_active_plugin_report_json( +pub unsafe extern "C" fn nemo_relay_active_plugin_report_json( out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let report_json = match serde_json::to_value(active_plugin_report()) { Ok(value) => value, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&report_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Return the registered plugin kinds as JSON. @@ -246,13 +247,13 @@ pub unsafe extern "C" fn nemo_flow_active_plugin_report_json( /// # Safety /// `out_json` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_list_plugin_kinds_json( +pub unsafe extern "C" fn nemo_relay_list_plugin_kinds_json( out_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out_json.is_null() { set_last_error("out_json pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } if let Err(status) = ensure_adaptive_component_registered() { return status; @@ -261,11 +262,11 @@ pub unsafe extern "C" fn nemo_flow_list_plugin_kinds_json( Ok(value) => value, Err(err) => { set_last_error(&err.to_string()); - return NemoFlowStatus::Internal; + return NemoRelayStatus::Internal; } }; unsafe { *out_json = json_to_c_string(&kinds_json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Register a plugin backed by foreign callbacks. @@ -273,13 +274,13 @@ pub unsafe extern "C" fn nemo_flow_list_plugin_kinds_json( /// # Safety /// `plugin_kind` must be a valid C string and `register_cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_plugin( +pub unsafe extern "C" fn nemo_relay_register_plugin( plugin_kind: *const c_char, - validate_cb: Option, - register_cb: NemoFlowPluginRegisterCb, + validate_cb: Option, + register_cb: NemoRelayPluginRegisterCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let plugin_kind = match c_str_to_string(plugin_kind) { Ok(value) => value, @@ -296,7 +297,7 @@ pub unsafe extern "C" fn nemo_flow_register_plugin( }), }); match register_plugin(plugin) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -306,17 +307,19 @@ pub unsafe extern "C" fn nemo_flow_register_plugin( /// # Safety /// `plugin_kind` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_plugin(plugin_kind: *const c_char) -> NemoFlowStatus { +pub unsafe extern "C" fn nemo_relay_deregister_plugin( + plugin_kind: *const c_char, +) -> NemoRelayStatus { clear_last_error(); let plugin_kind = match c_str_to_string(plugin_kind) { Ok(value) => value, Err(status) => return status, }; if deregister_plugin(&plugin_kind) { - NemoFlowStatus::Ok + NemoRelayStatus::Ok } else { set_last_error(&format!("not found: plugin '{plugin_kind}'")); - NemoFlowStatus::NotFound + NemoRelayStatus::NotFound } } @@ -326,17 +329,17 @@ pub unsafe extern "C" fn nemo_flow_deregister_plugin(plugin_kind: *const c_char) /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_subscriber( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_subscriber( ctx: *mut FfiPluginContext, name: *const c_char, - cb: NemoFlowEventSubscriberCb, + cb: NemoRelayEventSubscriberCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -344,7 +347,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_subscriber( }; let wrapped = wrap_event_subscriber(cb, user_data, free_fn); match unsafe { &mut *((*ctx).0) }.register_subscriber(&name, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -355,18 +358,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_subscriber( /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -376,7 +379,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_request match unsafe { &mut *((*ctx).0) } .register_tool_sanitize_request_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -387,18 +390,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_request /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -408,7 +411,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_respons match unsafe { &mut *((*ctx).0) } .register_tool_sanitize_response_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -419,18 +422,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_sanitize_respons /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowToolConditionalCb, + cb: NemoRelayToolConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -440,7 +443,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_conditional_exec match unsafe { &mut *((*ctx).0) } .register_tool_conditional_execution_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -451,18 +454,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_conditional_exec /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowLlmRequestCb, + cb: NemoRelayLlmRequestCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -472,7 +475,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_request_ match unsafe { &mut *((*ctx).0) } .register_llm_sanitize_request_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -483,18 +486,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_request_ /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowJsonCb, + cb: NemoRelayJsonCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -504,7 +507,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_response match unsafe { &mut *((*ctx).0) } .register_llm_sanitize_response_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -515,18 +518,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_sanitize_response /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowLlmConditionalCb, + cb: NemoRelayLlmConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -536,7 +539,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_conditional_execu match unsafe { &mut *((*ctx).0) } .register_llm_conditional_execution_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -547,19 +550,19 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_conditional_execu /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_request_intercept( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_request_intercept( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowLlmRequestInterceptCb, + cb: NemoRelayLlmRequestInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -572,7 +575,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_request_intercept break_chain, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -583,19 +586,19 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_request_intercept /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_request_intercept( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_tool_request_intercept( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -608,7 +611,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_request_intercep break_chain, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -619,18 +622,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_request_intercep /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_execution_intercept( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_execution_intercept( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowLlmExecInterceptCb, + cb: NemoRelayLlmExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -638,7 +641,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_execution_interce }; let wrapped = wrap_llm_exec_intercept_fn(cb, user_data, free_fn); match unsafe { &mut *((*ctx).0) }.register_llm_execution_intercept(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -649,18 +652,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_execution_interce /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_stream_execution_intercept( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_llm_stream_execution_intercept( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowLlmExecInterceptCb, + cb: NemoRelayLlmExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -670,7 +673,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_stream_execution_ match unsafe { &mut *((*ctx).0) } .register_llm_stream_execution_intercept(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } @@ -681,18 +684,18 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_llm_stream_execution_ /// `ctx` and `name` must be valid pointers and the callback must remain valid for the duration /// of the plugin registration lifetime. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_execution_intercept( +pub unsafe extern "C" fn nemo_relay_plugin_context_register_tool_execution_intercept( ctx: *mut FfiPluginContext, name: *const c_char, priority: i32, - cb: NemoFlowToolExecInterceptCb, + cb: NemoRelayToolExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); if ctx.is_null() { set_last_error("plugin context is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(value) => value, @@ -700,7 +703,7 @@ pub unsafe extern "C" fn nemo_flow_plugin_context_register_tool_execution_interc }; let wrapped = wrap_tool_exec_intercept_fn(cb, user_data, free_fn); match unsafe { &mut *((*ctx).0) }.register_tool_execution_intercept(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(err) => status_from_plugin_error(&err), } } diff --git a/crates/ffi/src/api/scope.rs b/crates/ffi/src/api/scope.rs index 5e00018a3..7b3cfdec0 100644 --- a/crates/ffi/src/api/scope.rs +++ b/crates/ffi/src/api/scope.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - FfiScopeHandle, NemoFlowScopeType, NemoFlowStatus, ScopeAttributes, c_char, c_str_to_opt_json, - c_str_to_string, clear_last_error, core_scope_api, set_last_error, status_from_error, - unix_micros_to_opt_timestamp, + FfiScopeHandle, NemoRelayScopeType, NemoRelayStatus, ScopeAttributes, c_char, + c_str_to_opt_json, c_str_to_string, clear_last_error, core_scope_api, set_last_error, + status_from_error, unix_micros_to_opt_timestamp, }; // --------------------------------------------------------------------------- @@ -15,21 +15,21 @@ use super::{ /// /// # Parameters /// - `out`: On success, receives a heap-allocated `FfiScopeHandle` that must be -/// freed with `nemo_flow_scope_handle_free`. +/// freed with `nemo_relay_scope_handle_free`. /// /// # Safety /// `out` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_get_handle(out: *mut *mut FfiScopeHandle) -> NemoFlowStatus { +pub unsafe extern "C" fn nemo_relay_get_handle(out: *mut *mut FfiScopeHandle) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } match core_scope_api::get_handle() { Ok(h) => { unsafe { *out = Box::into_raw(Box::new(FfiScopeHandle(h))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -55,7 +55,7 @@ pub unsafe extern "C" fn nemo_flow_get_handle(out: *mut *mut FfiScopeHandle) -> /// - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the /// handle start time and start event, or null to use the current UTC time. /// - `out`: On success, receives a heap-allocated `FfiScopeHandle` that must -/// be freed with `nemo_flow_scope_handle_free`. +/// be freed with `nemo_relay_scope_handle_free`. /// /// # Errors /// Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -67,9 +67,9 @@ pub unsafe extern "C" fn nemo_flow_get_handle(out: *mut *mut FfiScopeHandle) -> /// be null; when non-null, optional pointers must be valid for reads for the /// duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_push_scope( +pub unsafe extern "C" fn nemo_relay_push_scope( name: *const c_char, - scope_type: NemoFlowScopeType, + scope_type: NemoRelayScopeType, parent: *const FfiScopeHandle, attributes: u32, data_json: *const c_char, @@ -77,11 +77,11 @@ pub unsafe extern "C" fn nemo_flow_push_scope( input_json: *const c_char, timestamp_unix_micros: *const i64, out: *mut *mut FfiScopeHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -95,19 +95,19 @@ pub unsafe extern "C" fn nemo_flow_push_scope( let attrs = ScopeAttributes::from_bits_truncate(attributes); let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let input = match c_str_to_opt_json(input_json) { Some(v) => v, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_scope_api::push_scope( @@ -124,7 +124,7 @@ pub unsafe extern "C" fn nemo_flow_push_scope( ) { Ok(h) => { unsafe { *out = Box::into_raw(Box::new(FfiScopeHandle(h))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -152,23 +152,23 @@ pub unsafe extern "C" fn nemo_flow_push_scope( /// `timestamp_unix_micros` may be null; when non-null, optional pointers must /// be valid for reads for the duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_pop_scope( +pub unsafe extern "C" fn nemo_relay_pop_scope( handle: *const FfiScopeHandle, output_json: *const c_char, timestamp_unix_micros: *const i64, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if handle.is_null() { set_last_error("handle is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let output = match c_str_to_opt_json(output_json) { Some(v) => v, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_scope_api::pop_scope( core_scope_api::PopScopeParams::builder() @@ -177,7 +177,7 @@ pub unsafe extern "C" fn nemo_flow_pop_scope( .timestamp_opt(timestamp) .build(), ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -206,13 +206,13 @@ pub unsafe extern "C" fn nemo_flow_pop_scope( /// non-null, optional pointers must be valid for reads for the duration of the /// call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event( +pub unsafe extern "C" fn nemo_relay_event( name: *const c_char, parent: *const FfiScopeHandle, data_json: *const c_char, metadata_json: *const c_char, timestamp_unix_micros: *const i64, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -225,15 +225,15 @@ pub unsafe extern "C" fn nemo_flow_event( }; let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_scope_api::event( @@ -245,7 +245,7 @@ pub unsafe extern "C" fn nemo_flow_event( .timestamp_opt(timestamp) .build(), ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } diff --git a/crates/ffi/src/api/scope_registry.rs b/crates/ffi/src/api/scope_registry.rs index 4b6a2ec92..0b2887155 100644 --- a/crates/ffi/src/api/scope_registry.rs +++ b/crates/ffi/src/api/scope_registry.rs @@ -2,14 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - NemoFlowEventSubscriberCb, NemoFlowFreeFn, NemoFlowJsonCb, NemoFlowLlmConditionalCb, - NemoFlowLlmExecInterceptCb, NemoFlowLlmRequestCb, NemoFlowLlmRequestInterceptCb, - NemoFlowStatus, NemoFlowToolConditionalCb, NemoFlowToolExecInterceptCb, NemoFlowToolSanitizeCb, - c_char, c_str_to_string, clear_last_error, core_registry_api, core_subscriber_api, - set_last_error, status_from_error, wrap_event_subscriber, wrap_llm_conditional_fn, - wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, wrap_llm_response_fn, - wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_intercept_fn, wrap_tool_conditional_fn, - wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, wrap_tool_sanitize_fn, + NemoRelayEventSubscriberCb, NemoRelayFreeFn, NemoRelayJsonCb, NemoRelayLlmConditionalCb, + NemoRelayLlmExecInterceptCb, NemoRelayLlmRequestCb, NemoRelayLlmRequestInterceptCb, + NemoRelayStatus, NemoRelayToolConditionalCb, NemoRelayToolExecInterceptCb, + NemoRelayToolSanitizeCb, c_char, c_str_to_string, clear_last_error, core_registry_api, + core_subscriber_api, set_last_error, status_from_error, wrap_event_subscriber, + wrap_llm_conditional_fn, wrap_llm_exec_intercept_fn, wrap_llm_request_intercept_fn, + wrap_llm_response_fn, wrap_llm_sanitize_request_fn, wrap_llm_stream_exec_intercept_fn, + wrap_tool_conditional_fn, wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, + wrap_tool_sanitize_fn, }; // --------------------------------------------------------------------------- @@ -17,11 +18,11 @@ use super::{ // --------------------------------------------------------------------------- /// Helper to parse a scope UUID from a C string. -fn parse_scope_uuid(scope_uuid: *const c_char) -> Result { +fn parse_scope_uuid(scope_uuid: *const c_char) -> Result { let uuid_str = c_str_to_string(scope_uuid)?; uuid::Uuid::parse_str(&uuid_str).map_err(|e| { set_last_error(&format!("invalid scope UUID: {e}")); - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg }) } @@ -35,10 +36,10 @@ macro_rules! ffi_scope_guardrail_tool_api { scope_uuid: *const c_char, name: *const c_char, priority: i32, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, - ) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, + ) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -50,7 +51,7 @@ macro_rules! ffi_scope_guardrail_tool_api { }; let wrapped = $wrapper(cb, user_data, free_fn); match $core_register(&uuid, &name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -60,7 +61,7 @@ macro_rules! ffi_scope_guardrail_tool_api { pub unsafe extern "C" fn $deregister_name( scope_uuid: *const c_char, name: *const c_char, - ) -> NemoFlowStatus { + ) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -71,7 +72,7 @@ macro_rules! ffi_scope_guardrail_tool_api { Err(status) => return status, }; match $core_deregister(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -91,12 +92,12 @@ ffi_scope_guardrail_tool_api!( /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. - nemo_flow_scope_register_tool_sanitize_request_guardrail, + nemo_relay_scope_register_tool_sanitize_request_guardrail, /// Deregister a scope-local tool request sanitization guardrail by name. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. - nemo_flow_scope_deregister_tool_sanitize_request_guardrail, + nemo_relay_scope_deregister_tool_sanitize_request_guardrail, core_registry_api::scope_register_tool_sanitize_request_guardrail, core_registry_api::scope_deregister_tool_sanitize_request_guardrail, wrap_tool_sanitize_fn @@ -115,12 +116,12 @@ ffi_scope_guardrail_tool_api!( /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. - nemo_flow_scope_register_tool_sanitize_response_guardrail, + nemo_relay_scope_register_tool_sanitize_response_guardrail, /// Deregister a scope-local tool response sanitization guardrail by name. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. - nemo_flow_scope_deregister_tool_sanitize_response_guardrail, + nemo_relay_scope_deregister_tool_sanitize_response_guardrail, core_registry_api::scope_register_tool_sanitize_response_guardrail, core_registry_api::scope_deregister_tool_sanitize_response_guardrail, wrap_tool_sanitize_fn @@ -137,20 +138,20 @@ ffi_scope_guardrail_tool_api!( /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal an internal callback failure instead of -/// allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C +/// allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C /// and return null. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_tool_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_register_tool_conditional_execution_guardrail( scope_uuid: *const c_char, name: *const c_char, priority: i32, - cb: NemoFlowToolConditionalCb, + cb: NemoRelayToolConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -164,7 +165,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_tool_conditional_execution_gua match core_registry_api::scope_register_tool_conditional_execution_guardrail( &uuid, &name, priority, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -174,10 +175,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_tool_conditional_execution_gua /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_tool_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_deregister_tool_conditional_execution_guardrail( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -188,7 +189,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_tool_conditional_execution_g Err(status) => return status, }; match core_registry_api::scope_deregister_tool_conditional_execution_guardrail(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -208,10 +209,10 @@ macro_rules! ffi_scope_intercept_tool_api { name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, - ) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, + ) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -223,7 +224,7 @@ macro_rules! ffi_scope_intercept_tool_api { }; let wrapped = $wrapper(cb, user_data, free_fn); match $core_register(&uuid, &name, priority, break_chain, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -233,7 +234,7 @@ macro_rules! ffi_scope_intercept_tool_api { pub unsafe extern "C" fn $deregister_name( scope_uuid: *const c_char, name: *const c_char, - ) -> NemoFlowStatus { + ) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -244,7 +245,7 @@ macro_rules! ffi_scope_intercept_tool_api { Err(status) => return status, }; match $core_deregister(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -264,16 +265,16 @@ ffi_scope_intercept_tool_api!( /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal failure, call - /// [`crate::error::nemo_flow_set_last_error_message`] from C and return null. + /// [`crate::error::nemo_relay_set_last_error_message`] from C and return null. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. - nemo_flow_scope_register_tool_request_intercept, + nemo_relay_scope_register_tool_request_intercept, /// Deregister a scope-local tool request intercept by name. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. - nemo_flow_scope_deregister_tool_request_intercept, + nemo_relay_scope_deregister_tool_request_intercept, core_registry_api::scope_register_tool_request_intercept, core_registry_api::scope_deregister_tool_request_intercept, wrap_tool_request_intercept_fn @@ -293,14 +294,14 @@ ffi_scope_intercept_tool_api!( /// # Safety /// `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_tool_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_register_tool_execution_intercept( scope_uuid: *const c_char, name: *const c_char, priority: i32, - exec_cb: NemoFlowToolExecInterceptCb, + exec_cb: NemoRelayToolExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -312,7 +313,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_tool_execution_intercept( }; let exec = wrap_tool_exec_intercept_fn(exec_cb, exec_user_data, exec_free); match core_registry_api::scope_register_tool_execution_intercept(&uuid, &name, priority, exec) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -322,10 +323,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_tool_execution_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_tool_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_deregister_tool_execution_intercept( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -336,7 +337,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_tool_execution_intercept( Err(status) => return status, }; match core_registry_api::scope_deregister_tool_execution_intercept(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -358,14 +359,14 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_tool_execution_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid: *const c_char, name: *const c_char, priority: i32, - cb: NemoFlowLlmRequestCb, + cb: NemoRelayLlmRequestCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -379,7 +380,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_request_guardrail match core_registry_api::scope_register_llm_sanitize_request_guardrail( &uuid, &name, priority, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -389,10 +390,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_request_guardrail /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_request_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_sanitize_request_guardrail( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -403,7 +404,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_request_guardra Err(status) => return status, }; match core_registry_api::scope_deregister_llm_sanitize_request_guardrail(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -421,14 +422,14 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_request_guardra /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_sanitize_response_guardrail( scope_uuid: *const c_char, name: *const c_char, priority: i32, - cb: NemoFlowJsonCb, + cb: NemoRelayJsonCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -442,7 +443,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_response_guardrai match core_registry_api::scope_register_llm_sanitize_response_guardrail( &uuid, &name, priority, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -452,10 +453,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_sanitize_response_guardrai /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_response_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_sanitize_response_guardrail( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -466,7 +467,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_response_guardr Err(status) => return status, }; match core_registry_api::scope_deregister_llm_sanitize_response_guardrail(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -482,20 +483,20 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_sanitize_response_guardr /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal an internal callback failure instead of -/// allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C +/// allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C /// and return null. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_conditional_execution_guardrail( scope_uuid: *const c_char, name: *const c_char, priority: i32, - cb: NemoFlowLlmConditionalCb, + cb: NemoRelayLlmConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -509,7 +510,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_conditional_execution_guar match core_registry_api::scope_register_llm_conditional_execution_guardrail( &uuid, &name, priority, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -519,10 +520,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_conditional_execution_guar /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_conditional_execution_guardrail( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -533,7 +534,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_conditional_execution_gu Err(status) => return status, }; match core_registry_api::scope_deregister_llm_conditional_execution_guardrail(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -554,20 +555,20 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_conditional_execution_gu /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal failure, call -/// [`crate::error::nemo_flow_set_last_error_message`] from C and return null. +/// [`crate::error::nemo_relay_set_last_error_message`] from C and return null. /// /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_request_intercept( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_request_intercept( scope_uuid: *const c_char, name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowLlmRequestInterceptCb, + cb: NemoRelayLlmRequestInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -585,7 +586,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_request_intercept( break_chain, wrapped, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -595,10 +596,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_request_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_request_intercept( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_request_intercept( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -609,7 +610,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_request_intercept( Err(status) => return status, }; match core_registry_api::scope_deregister_llm_request_intercept(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -628,14 +629,14 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_request_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_execution_intercept( scope_uuid: *const c_char, name: *const c_char, priority: i32, - exec_cb: NemoFlowLlmExecInterceptCb, + exec_cb: NemoRelayLlmExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -647,7 +648,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_execution_intercept( }; let exec = wrap_llm_exec_intercept_fn(exec_cb, exec_user_data, exec_free); match core_registry_api::scope_register_llm_execution_intercept(&uuid, &name, priority, exec) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -657,10 +658,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_execution_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_execution_intercept( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -671,7 +672,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_execution_intercept( Err(status) => return status, }; match core_registry_api::scope_deregister_llm_execution_intercept(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -690,14 +691,14 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_execution_intercept( /// # Safety /// `scope_uuid` and `name` must be valid C strings. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_llm_stream_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_register_llm_stream_execution_intercept( scope_uuid: *const c_char, name: *const c_char, priority: i32, - exec_cb: NemoFlowLlmExecInterceptCb, + exec_cb: NemoRelayLlmExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -711,7 +712,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_stream_execution_intercept match core_registry_api::scope_register_llm_stream_execution_intercept( &uuid, &name, priority, exec, ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -721,10 +722,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_llm_stream_execution_intercept /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_stream_execution_intercept( +pub unsafe extern "C" fn nemo_relay_scope_deregister_llm_stream_execution_intercept( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -735,7 +736,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_stream_execution_interce Err(status) => return status, }; match core_registry_api::scope_deregister_llm_stream_execution_intercept(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -756,13 +757,13 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_llm_stream_execution_interce /// # Safety /// `scope_uuid` and `name` must be valid C strings. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_register_subscriber( +pub unsafe extern "C" fn nemo_relay_scope_register_subscriber( scope_uuid: *const c_char, name: *const c_char, - cb: NemoFlowEventSubscriberCb, + cb: NemoRelayEventSubscriberCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -774,7 +775,7 @@ pub unsafe extern "C" fn nemo_flow_scope_register_subscriber( }; let wrapped = wrap_event_subscriber(cb, user_data, free_fn); match core_subscriber_api::scope_register_subscriber(&uuid, &name, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -784,10 +785,10 @@ pub unsafe extern "C" fn nemo_flow_scope_register_subscriber( /// # Safety /// `scope_uuid` and `name` must be valid C strings. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_deregister_subscriber( +pub unsafe extern "C" fn nemo_relay_scope_deregister_subscriber( scope_uuid: *const c_char, name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let uuid = match parse_scope_uuid(scope_uuid) { Ok(u) => u, @@ -798,7 +799,7 @@ pub unsafe extern "C" fn nemo_flow_scope_deregister_subscriber( Err(status) => return status, }; match core_subscriber_api::scope_deregister_subscriber(&uuid, &name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } diff --git a/crates/ffi/src/api/scope_stack.rs b/crates/ffi/src/api/scope_stack.rs index f638b1755..abaa761b1 100644 --- a/crates/ffi/src/api/scope_stack.rs +++ b/crates/ffi/src/api/scope_stack.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - FfiScopeStack, FfiThreadScopeStackBinding, NemoFlowStatus, capture_thread_scope_stack, + FfiScopeStack, FfiThreadScopeStackBinding, NemoRelayStatus, capture_thread_scope_stack, clear_last_error, create_scope_stack, restore_thread_scope_stack, scope_stack_active, set_last_error, set_thread_scope_stack, }; @@ -14,38 +14,38 @@ use super::{ /// Create a new isolated scope stack with its own root scope. /// /// Each scope stack is independent: scopes pushed on one do not appear on another. -/// Use `nemo_flow_scope_stack_set_thread` to bind a stack to the current thread -/// before making other NeMo Flow API calls. +/// Use `nemo_relay_scope_stack_set_thread` to bind a stack to the current thread +/// before making other NeMo Relay API calls. /// /// # Parameters /// - `out`: On success, receives a heap-allocated `FfiScopeStack` that must be -/// freed with `nemo_flow_scope_stack_free`. +/// freed with `nemo_relay_scope_stack_free`. /// /// # Returns -/// - Returns [`NemoFlowStatus::Ok`] on success and writes the new scope stack +/// - Returns [`NemoRelayStatus::Ok`] on success and writes the new scope stack /// to `out`. -/// - Returns [`NemoFlowStatus::NullPointer`] when `out` is null. +/// - Returns [`NemoRelayStatus::NullPointer`] when `out` is null. /// /// # Safety /// `out` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_stack_create( +pub unsafe extern "C" fn nemo_relay_scope_stack_create( out: *mut *mut FfiScopeStack, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let handle = create_scope_stack(); unsafe { *out = Box::into_raw(Box::new(FfiScopeStack(handle))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Bind an isolated scope stack to the current OS thread. /// -/// After this call, all NeMo Flow scope operations on the current thread -/// (e.g. `nemo_flow_push_scope`, `nemo_flow_get_handle`) will use the +/// After this call, all NeMo Relay scope operations on the current thread +/// (e.g. `nemo_relay_push_scope`, `nemo_relay_get_handle`) will use the /// given scope stack. This is typically used from Go goroutines that have /// called `runtime.LockOSThread()`. /// @@ -56,30 +56,30 @@ pub unsafe extern "C" fn nemo_flow_scope_stack_create( /// - `stack`: Scope stack to bind to the current OS thread. /// /// # Returns -/// - Returns [`NemoFlowStatus::Ok`] when the thread-local scope stack was +/// - Returns [`NemoRelayStatus::Ok`] when the thread-local scope stack was /// updated successfully. -/// - Returns [`NemoFlowStatus::NullPointer`] when `stack` is null. +/// - Returns [`NemoRelayStatus::NullPointer`] when `stack` is null. /// /// # Safety /// `stack` must be a valid, non-null `FfiScopeStack` pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_stack_set_thread( +pub unsafe extern "C" fn nemo_relay_scope_stack_set_thread( stack: *const FfiScopeStack, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if stack.is_null() { set_last_error("stack pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let handle = unsafe { &*stack }.0.clone(); set_thread_scope_stack(handle); - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Capture the current thread-local scope stack binding. /// /// The returned binding must be restored with -/// `nemo_flow_scope_stack_restore_thread`. +/// `nemo_relay_scope_stack_restore_thread`. /// /// # Parameters /// - `out`: On success, receives a heap-allocated binding handle. @@ -87,42 +87,42 @@ pub unsafe extern "C" fn nemo_flow_scope_stack_set_thread( /// # Safety /// `out` must be a valid, non-null pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_stack_capture_thread( +pub unsafe extern "C" fn nemo_relay_scope_stack_capture_thread( out: *mut *mut FfiThreadScopeStackBinding, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let binding = capture_thread_scope_stack(); unsafe { *out = Box::into_raw(Box::new(FfiThreadScopeStackBinding(binding))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Restore and free a captured thread-local scope stack binding. /// /// # Safety /// `binding` must be a valid pointer returned by -/// `nemo_flow_scope_stack_capture_thread`. +/// `nemo_relay_scope_stack_capture_thread`. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_stack_restore_thread( +pub unsafe extern "C" fn nemo_relay_scope_stack_restore_thread( binding: *mut FfiThreadScopeStackBinding, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if binding.is_null() { set_last_error("binding pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let binding = unsafe { Box::from_raw(binding) }; restore_thread_scope_stack(binding.0); - NemoFlowStatus::Ok + NemoRelayStatus::Ok } /// Returns whether the current execution context has an explicitly-initialized /// scope stack. /// -/// Returns `true` if `nemo_flow_scope_stack_set_thread` has been called on the +/// Returns `true` if `nemo_relay_scope_stack_set_thread` has been called on the /// current OS thread (or the caller is inside a tokio task-local scope). /// Returns `false` when only the auto-created default is present. /// @@ -130,6 +130,6 @@ pub unsafe extern "C" fn nemo_flow_scope_stack_restore_thread( /// This helper does not allocate or install a scope stack. It only reports /// whether one is already explicit in the current execution context. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_scope_stack_active() -> bool { +pub extern "C" fn nemo_relay_scope_stack_active() -> bool { scope_stack_active() } diff --git a/crates/ffi/src/api/tool_lifecycle.rs b/crates/ffi/src/api/tool_lifecycle.rs index d27732789..c8a0fd644 100644 --- a/crates/ffi/src/api/tool_lifecycle.rs +++ b/crates/ffi/src/api/tool_lifecycle.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - Arc, FfiScopeHandle, FfiToolHandle, NemoFlowFreeFn, NemoFlowStatus, NemoFlowToolExecCb, + Arc, FfiScopeHandle, FfiToolHandle, NemoRelayFreeFn, NemoRelayStatus, NemoRelayToolExecCb, TASK_SCOPE_STACK, ToolAttributes, ToolExecutionNextFn, c_char, c_str_to_json, c_str_to_opt_json, c_str_to_string, clear_last_error, core_tool_api, current_scope_stack, json_to_c_string, set_last_error, status_from_error, tokio_runtime, @@ -17,7 +17,7 @@ use super::{ /// /// This emits a tool Start event after applying sanitize-request guardrails to /// the observability payload. Request and execution intercepts only run through -/// `nemo_flow_tool_call_execute`. +/// `nemo_relay_tool_call_execute`. /// /// # Parameters /// - `name`: Null-terminated tool name. @@ -35,7 +35,7 @@ use super::{ /// - `timestamp_unix_micros`: Optional Unix microseconds timestamp for the /// handle start time and start event, or null to use the current UTC time. /// - `out`: On success, receives a heap-allocated `FfiToolHandle` that must be -/// freed with `nemo_flow_tool_handle_free`. +/// freed with `nemo_relay_tool_handle_free`. /// /// # Errors /// Returns `InvalidJson` for invalid JSON inputs and `InvalidArg` when @@ -46,7 +46,7 @@ use super::{ /// Optional pointer arguments may be null; when non-null, they must be valid /// for reads for the duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_call( +pub unsafe extern "C" fn nemo_relay_tool_call( name: *const c_char, args_json: *const c_char, parent: *const FfiScopeHandle, @@ -56,11 +56,11 @@ pub unsafe extern "C" fn nemo_flow_tool_call( tool_call_id: *const c_char, timestamp_unix_micros: *const i64, out: *mut *mut FfiToolHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -68,7 +68,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call( }; let args = match c_str_to_json(args_json) { Some(a) => a, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let parent_ref = if parent.is_null() { None @@ -78,11 +78,11 @@ pub unsafe extern "C" fn nemo_flow_tool_call( let attrs = ToolAttributes::from_bits_truncate(attributes); let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let tool_call_id_opt = if tool_call_id.is_null() { None @@ -94,7 +94,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call( }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_tool_api::tool_call( @@ -111,7 +111,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call( ) { Ok(h) => { unsafe { *out = Box::into_raw(Box::new(FfiToolHandle(h))) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } @@ -121,10 +121,10 @@ pub unsafe extern "C" fn nemo_flow_tool_call( /// /// This emits a tool End event after applying sanitize-response guardrails to /// the observability payload. Response intercepts only run through -/// `nemo_flow_tool_call_execute`. +/// `nemo_relay_tool_call_execute`. /// /// # Parameters -/// - `handle`: The tool handle from `nemo_flow_tool_call`. +/// - `handle`: The tool handle from `nemo_relay_tool_call`. /// - `result_json`: Tool result as a null-terminated JSON C string. This /// result becomes the end-event data after sanitize-response guardrails unless /// it sanitizes to JSON null. @@ -144,33 +144,33 @@ pub unsafe extern "C" fn nemo_flow_tool_call( /// pointer arguments may be null; when non-null, they must be valid for reads /// for the duration of the call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_call_end( +pub unsafe extern "C" fn nemo_relay_tool_call_end( handle: *const FfiToolHandle, result_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, timestamp_unix_micros: *const i64, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if handle.is_null() { set_last_error("handle is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let result = match c_str_to_json(result_json) { Some(r) => r, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) { Some(v) => v, - None => return NemoFlowStatus::InvalidArg, + None => return NemoRelayStatus::InvalidArg, }; match core_tool_api::tool_call_end( @@ -182,7 +182,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call_end( .timestamp_opt(timestamp) .build(), ) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -205,27 +205,27 @@ pub unsafe extern "C" fn nemo_flow_tool_call_end( /// - `data_json`: Optional JSON data, or null. /// - `metadata_json`: Optional JSON metadata, or null. /// - `out`: On success, receives the result as a JSON C string. Caller must free -/// with `nemo_flow_string_free`. +/// with `nemo_relay_string_free`. /// /// # Safety /// `name`, `args_json`, and `out` must be valid, non-null pointers. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_call_execute( +pub unsafe extern "C" fn nemo_relay_tool_call_execute( name: *const c_char, args_json: *const c_char, - func: NemoFlowToolExecCb, + func: NemoRelayToolExecCb, func_user_data: *mut libc::c_void, - func_free: NemoFlowFreeFn, + func_free: NemoRelayFreeFn, parent: *const FfiScopeHandle, attributes: u32, data_json: *const c_char, metadata_json: *const c_char, out: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); if out.is_null() { set_last_error("out pointer is null"); - return NemoFlowStatus::NullPointer; + return NemoRelayStatus::NullPointer; } let name = match c_str_to_string(name) { Ok(s) => s, @@ -233,7 +233,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call_execute( }; let args = match c_str_to_json(args_json) { Some(a) => a, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let parent_handle = if parent.is_null() { None @@ -243,11 +243,11 @@ pub unsafe extern "C" fn nemo_flow_tool_call_execute( let attrs = ToolAttributes::from_bits_truncate(attributes); let data = match c_str_to_opt_json(data_json) { Some(d) => d, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let metadata = match c_str_to_opt_json(metadata_json) { Some(m) => m, - None => return NemoFlowStatus::InvalidJson, + None => return NemoRelayStatus::InvalidJson, }; let exec_fn = wrap_tool_exec_fn(func, func_user_data, func_free); @@ -272,7 +272,7 @@ pub unsafe extern "C" fn nemo_flow_tool_call_execute( match result { Ok(json) => { unsafe { *out = json_to_c_string(&json) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } Err(e) => status_from_error(&e), } diff --git a/crates/ffi/src/api/tool_registry.rs b/crates/ffi/src/api/tool_registry.rs index e44198be5..5d5cefb40 100644 --- a/crates/ffi/src/api/tool_registry.rs +++ b/crates/ffi/src/api/tool_registry.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use super::{ - NemoFlowFreeFn, NemoFlowStatus, NemoFlowToolConditionalCb, NemoFlowToolExecInterceptCb, - NemoFlowToolSanitizeCb, c_char, c_str_to_string, clear_last_error, core_registry_api, + NemoRelayFreeFn, NemoRelayStatus, NemoRelayToolConditionalCb, NemoRelayToolExecInterceptCb, + NemoRelayToolSanitizeCb, c_char, c_str_to_string, clear_last_error, core_registry_api, status_from_error, wrap_tool_conditional_fn, wrap_tool_exec_intercept_fn, wrap_tool_request_intercept_fn, wrap_tool_sanitize_fn, }; @@ -21,10 +21,10 @@ macro_rules! ffi_guardrail_tool_api { pub unsafe extern "C" fn $register_name( name: *const c_char, priority: i32, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, - ) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, + ) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -32,7 +32,7 @@ macro_rules! ffi_guardrail_tool_api { }; let wrapped = $wrapper(cb, user_data, free_fn); match $core_register(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -41,14 +41,14 @@ macro_rules! ffi_guardrail_tool_api { #[unsafe(no_mangle)] pub unsafe extern "C" fn $deregister_name( name: *const c_char, - ) -> NemoFlowStatus { + ) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match $core_deregister(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -68,12 +68,12 @@ ffi_guardrail_tool_api!( /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. - nemo_flow_register_tool_sanitize_request_guardrail, + nemo_relay_register_tool_sanitize_request_guardrail, /// Deregister a tool request sanitization guardrail by name. /// /// # Safety /// `name` must be a valid C string. - nemo_flow_deregister_tool_sanitize_request_guardrail, + nemo_relay_deregister_tool_sanitize_request_guardrail, core_registry_api::register_tool_sanitize_request_guardrail, core_registry_api::deregister_tool_sanitize_request_guardrail, wrap_tool_sanitize_fn @@ -92,12 +92,12 @@ ffi_guardrail_tool_api!( /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. - nemo_flow_register_tool_sanitize_response_guardrail, + nemo_relay_register_tool_sanitize_response_guardrail, /// Deregister a tool response sanitization guardrail by name. /// /// # Safety /// `name` must be a valid C string. - nemo_flow_deregister_tool_sanitize_response_guardrail, + nemo_relay_deregister_tool_sanitize_response_guardrail, core_registry_api::register_tool_sanitize_response_guardrail, core_registry_api::deregister_tool_sanitize_response_guardrail, wrap_tool_sanitize_fn @@ -114,19 +114,19 @@ ffi_guardrail_tool_api!( /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal an internal callback failure instead of -/// allow/reject, call [`crate::error::nemo_flow_set_last_error_message`] from C +/// allow/reject, call [`crate::error::nemo_relay_set_last_error_message`] from C /// and return null. /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_tool_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_register_tool_conditional_execution_guardrail( name: *const c_char, priority: i32, - cb: NemoFlowToolConditionalCb, + cb: NemoRelayToolConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, -) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -135,7 +135,7 @@ pub unsafe extern "C" fn nemo_flow_register_tool_conditional_execution_guardrail let wrapped = wrap_tool_conditional_fn(cb, user_data, free_fn); match core_registry_api::register_tool_conditional_execution_guardrail(&name, priority, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -145,16 +145,16 @@ pub unsafe extern "C" fn nemo_flow_register_tool_conditional_execution_guardrail /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_tool_conditional_execution_guardrail( +pub unsafe extern "C" fn nemo_relay_deregister_tool_conditional_execution_guardrail( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_tool_conditional_execution_guardrail(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -173,10 +173,10 @@ macro_rules! ffi_intercept_tool_api { name: *const c_char, priority: i32, break_chain: bool, - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, - ) -> NemoFlowStatus { + free_fn: NemoRelayFreeFn, + ) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -184,7 +184,7 @@ macro_rules! ffi_intercept_tool_api { }; let wrapped = $wrapper(cb, user_data, free_fn); match $core_register(&name, priority, break_chain, wrapped) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -193,14 +193,14 @@ macro_rules! ffi_intercept_tool_api { #[unsafe(no_mangle)] pub unsafe extern "C" fn $deregister_name( name: *const c_char, - ) -> NemoFlowStatus { + ) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match $core_deregister(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -221,16 +221,16 @@ ffi_intercept_tool_api!( /// - `free_fn`: Optional destructor for `user_data`. /// /// The callback is fallible. To signal failure, call - /// [`crate::error::nemo_flow_set_last_error_message`] from C and return null. + /// [`crate::error::nemo_relay_set_last_error_message`] from C and return null. /// /// # Safety /// `name` must be a valid C string. `cb` must be a valid function pointer. - nemo_flow_register_tool_request_intercept, + nemo_relay_register_tool_request_intercept, /// Deregister a tool request intercept by name. /// /// # Safety /// `name` must be a valid C string. - nemo_flow_deregister_tool_request_intercept, + nemo_relay_deregister_tool_request_intercept, core_registry_api::register_tool_request_intercept, core_registry_api::deregister_tool_request_intercept, wrap_tool_request_intercept_fn @@ -251,13 +251,13 @@ ffi_intercept_tool_api!( /// # Safety /// `name` must be a valid C string. Callback pointers must be valid. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_register_tool_execution_intercept( +pub unsafe extern "C" fn nemo_relay_register_tool_execution_intercept( name: *const c_char, priority: i32, - exec_cb: NemoFlowToolExecInterceptCb, + exec_cb: NemoRelayToolExecInterceptCb, exec_user_data: *mut libc::c_void, - exec_free: NemoFlowFreeFn, -) -> NemoFlowStatus { + exec_free: NemoRelayFreeFn, +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, @@ -265,7 +265,7 @@ pub unsafe extern "C" fn nemo_flow_register_tool_execution_intercept( }; let exec = wrap_tool_exec_intercept_fn(exec_cb, exec_user_data, exec_free); match core_registry_api::register_tool_execution_intercept(&name, priority, exec) { - Ok(()) => NemoFlowStatus::Ok, + Ok(()) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } @@ -275,16 +275,16 @@ pub unsafe extern "C" fn nemo_flow_register_tool_execution_intercept( /// # Safety /// `name` must be a valid C string. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_deregister_tool_execution_intercept( +pub unsafe extern "C" fn nemo_relay_deregister_tool_execution_intercept( name: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { clear_last_error(); let name = match c_str_to_string(name) { Ok(s) => s, Err(status) => return status, }; match core_registry_api::deregister_tool_execution_intercept(&name) { - Ok(_) => NemoFlowStatus::Ok, + Ok(_) => NemoRelayStatus::Ok, Err(e) => status_from_error(&e), } } diff --git a/crates/ffi/src/callable.rs b/crates/ffi/src/callable.rs index c55fad3e6..ea3bf4c28 100644 --- a/crates/ffi/src/callable.rs +++ b/crates/ffi/src/callable.rs @@ -7,7 +7,7 @@ //! This module defines the callback signatures used by the C API for tool and //! LLM guardrails, intercepts, execution functions, and event subscribers. Each //! `pub type` alias corresponds to a C function pointer that appears in the -//! generated `nemo_flow.h` header. +//! generated `nemo_relay.h` header. //! //! The `wrap_*` functions convert C callbacks (with opaque `user_data` pointers) //! into Rust closures that the core runtime can invoke. Registry-stored @@ -22,7 +22,7 @@ use std::pin::Pin; use std::sync::Arc; use libc::c_char; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ EventSubscriberFn, LlmConditionalFn, LlmExecutionNextFn, LlmRequestInterceptFn, LlmSanitizeRequestFn, LlmSanitizeResponseFn, LlmStreamExecutionNextFn, ToolConditionalFn, ToolExecutionNextFn, ToolInterceptFn, ToolSanitizeFn, @@ -30,14 +30,14 @@ use nemo_flow::api::runtime::{ use serde_json::Value as Json; use tokio_stream::{Stream, StreamExt}; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; -use nemo_flow::codec::traits::LlmCodec; -use nemo_flow::error::{FlowError, Result}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; +use nemo_relay::codec::traits::LlmCodec; +use nemo_relay::error::{FlowError, Result}; use crate::convert::json_to_c_string; -use crate::error::{NemoFlowStatus, clear_last_error, last_error_message, set_last_error}; +use crate::error::{NemoRelayStatus, clear_last_error, last_error_message, set_last_error}; use crate::types::{FfiEvent, FfiLLMRequest, FfiPluginContext}; // --------------------------------------------------------------------------- @@ -46,12 +46,12 @@ use crate::types::{FfiEvent, FfiLLMRequest, FfiPluginContext}; /// Optional destructor for user data passed to callbacks. /// Called when the runtime no longer needs the associated callback. -pub type NemoFlowFreeFn = Option; +pub type NemoRelayFreeFn = Option; /// Callback for tool request/response sanitization guardrails and intercepts. /// Receives tool name and arguments as JSON, returns sanitized arguments as JSON. /// The returned string must be allocated with `malloc` or equivalent. -pub type NemoFlowToolSanitizeCb = unsafe extern "C" fn( +pub type NemoRelayToolSanitizeCb = unsafe extern "C" fn( user_data: *mut libc::c_void, name: *const c_char, args_json: *const c_char, @@ -60,7 +60,7 @@ pub type NemoFlowToolSanitizeCb = unsafe extern "C" fn( /// Callback for tool conditional execution guardrails. /// Receives tool name and arguments as JSON. /// Returns NULL to allow execution, or an error message string to reject. -pub type NemoFlowToolConditionalCb = unsafe extern "C" fn( +pub type NemoRelayToolConditionalCb = unsafe extern "C" fn( user_data: *mut libc::c_void, name: *const c_char, args_json: *const c_char, @@ -69,79 +69,79 @@ pub type NemoFlowToolConditionalCb = unsafe extern "C" fn( /// Callback for tool execution (default callable). Receives arguments as JSON, /// returns result as JSON. The returned string must be allocated with `malloc` /// or equivalent. -pub type NemoFlowToolExecCb = +pub type NemoRelayToolExecCb = unsafe extern "C" fn(user_data: *mut libc::c_void, args_json: *const c_char) -> *mut c_char; /// Runtime-provided "next" callback for tool execution middleware chain. /// Call this from an intercept to invoke the next layer (or original function). /// `next_ctx` is an opaque pointer managed by the runtime. -pub type NemoFlowToolExecNextFn = +pub type NemoRelayToolExecNextFn = unsafe extern "C" fn(args_json: *const c_char, next_ctx: *mut libc::c_void) -> *mut c_char; /// Callback for tool execution intercepts. Receives arguments as JSON plus /// a `next` callback and its context. Call `next_fn(args, next_ctx)` to invoke /// the next layer in the middleware chain, or return directly to short-circuit. -pub type NemoFlowToolExecInterceptCb = unsafe extern "C" fn( +pub type NemoRelayToolExecInterceptCb = unsafe extern "C" fn( user_data: *mut libc::c_void, args_json: *const c_char, - next_fn: NemoFlowToolExecNextFn, + next_fn: NemoRelayToolExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char; /// Generic JSON-to-JSON callback, used for LLM response sanitization and intercepts. /// The returned string must be allocated with `malloc` or equivalent. -pub type NemoFlowJsonCb = +pub type NemoRelayJsonCb = unsafe extern "C" fn(user_data: *mut libc::c_void, json: *const c_char) -> *mut c_char; /// Callback for LLM request sanitization. Receives an `FfiLLMRequest` and returns /// a new (possibly modified) `FfiLLMRequest`. Return null to use defaults. -pub type NemoFlowLlmRequestCb = unsafe extern "C" fn( +pub type NemoRelayLlmRequestCb = unsafe extern "C" fn( user_data: *mut libc::c_void, request: *const FfiLLMRequest, ) -> *mut FfiLLMRequest; /// Callback for LLM conditional execution guardrails. /// Returns NULL to allow execution, or an error message string to reject. -pub type NemoFlowLlmConditionalCb = unsafe extern "C" fn( +pub type NemoRelayLlmConditionalCb = unsafe extern "C" fn( user_data: *mut libc::c_void, request: *const FfiLLMRequest, ) -> *mut c_char; /// Callback for LLM execution (default callable). Receives a native JSON C string, /// returns the response as a JSON C string. -pub type NemoFlowLlmExecCb = +pub type NemoRelayLlmExecCb = unsafe extern "C" fn(user_data: *mut libc::c_void, native_json: *const c_char) -> *mut c_char; /// Runtime-provided "next" callback for LLM execution middleware chain. /// Takes a native JSON C string, returns a response JSON C string. -pub type NemoFlowLlmExecNextFn = +pub type NemoRelayLlmExecNextFn = unsafe extern "C" fn(native_json: *const c_char, next_ctx: *mut libc::c_void) -> *mut c_char; /// Callback for LLM execution intercepts with middleware chain support. /// Receives native JSON C string plus a `next` callback and its context. -pub type NemoFlowLlmExecInterceptCb = unsafe extern "C" fn( +pub type NemoRelayLlmExecInterceptCb = unsafe extern "C" fn( user_data: *mut libc::c_void, native_json: *const c_char, - next_fn: NemoFlowLlmExecNextFn, + next_fn: NemoRelayLlmExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char; /// Callback for event subscribers. Invoked on each lifecycle event emitted by /// the runtime. The `FfiEvent` pointer is only valid for the duration of the call. -pub type NemoFlowEventSubscriberCb = +pub type NemoRelayEventSubscriberCb = unsafe extern "C" fn(user_data: *mut libc::c_void, event: *const FfiEvent); /// Callback for Codec decode: translates an opaque `FfiLLMRequest` into /// an `AnnotatedLLMRequest` JSON string. Returns a heap-allocated C string /// on success, or null on error (after setting the last error message). -pub type NemoFlowCodecDecodeCb = unsafe extern "C" fn( +pub type NemoRelayCodecDecodeCb = unsafe extern "C" fn( user_data: *mut libc::c_void, request: *const FfiLLMRequest, ) -> *mut c_char; -/// Nullable version of [`NemoFlowCodecDecodeCb`] for use as an optional +/// Nullable version of [`NemoRelayCodecDecodeCb`] for use as an optional /// parameter in FFI execute functions. Pass null to indicate no codec. -pub type NemoFlowCodecDecodeFn = Option< +pub type NemoRelayCodecDecodeFn = Option< unsafe extern "C" fn( user_data: *mut libc::c_void, request: *const FfiLLMRequest, @@ -152,15 +152,15 @@ pub type NemoFlowCodecDecodeFn = Option< /// request content. Receives the annotated request as a JSON C string and /// the original `FfiLLMRequest`. Returns a heap-allocated JSON C string /// representing the new `LlmRequest` content on success, or null on error. -pub type NemoFlowCodecEncodeCb = unsafe extern "C" fn( +pub type NemoRelayCodecEncodeCb = unsafe extern "C" fn( user_data: *mut libc::c_void, annotated_json: *const c_char, original_request: *const FfiLLMRequest, ) -> *mut c_char; -/// Nullable version of [`NemoFlowCodecEncodeCb`] for use as an optional +/// Nullable version of [`NemoRelayCodecEncodeCb`] for use as an optional /// parameter in FFI execute functions. Pass null to indicate no codec. -pub type NemoFlowCodecEncodeFn = Option< +pub type NemoRelayCodecEncodeFn = Option< unsafe extern "C" fn( user_data: *mut libc::c_void, annotated_json: *const c_char, @@ -172,30 +172,30 @@ pub type NemoFlowCodecEncodeFn = Option< /// signature. Receives the intercept name, the opaque `FfiLLMRequest`, and /// optionally the annotated request as a JSON C string (null if no Codec /// resolved). Writes transformed outputs to `out_request` and -/// `out_annotated_json`. Returns `NemoFlowStatus`. -pub type NemoFlowLlmRequestInterceptCb = unsafe extern "C" fn( +/// `out_annotated_json`. Returns `NemoRelayStatus`. +pub type NemoRelayLlmRequestInterceptCb = unsafe extern "C" fn( user_data: *mut libc::c_void, name: *const c_char, request: *const FfiLLMRequest, annotated_json: *const c_char, out_request: *mut *mut FfiLLMRequest, out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus; +) -> NemoRelayStatus; /// Callback for collecting intercepted stream chunks. Invoked with each chunk /// (after stream execution intercepts have been applied) as a null-terminated /// C string. The string is only valid for the duration of the call. -pub type NemoFlowCollectorCb = unsafe extern "C" fn(chunk: *const c_char); +pub type NemoRelayCollectorCb = unsafe extern "C" fn(chunk: *const c_char); /// Callback for finalizing a collected stream. Invoked once when the stream is /// exhausted. Must return a JSON C string representing the aggregated response. /// The returned string must be allocated with `malloc` or equivalent; the /// runtime will free it. -pub type NemoFlowFinalizerCb = unsafe extern "C" fn() -> *mut c_char; +pub type NemoRelayFinalizerCb = unsafe extern "C" fn() -> *mut c_char; /// Callback for plugin validation. /// Receives plugin config JSON and returns a JSON array of diagnostics. -pub type NemoFlowPluginValidateCb = unsafe extern "C" fn( +pub type NemoRelayPluginValidateCb = unsafe extern "C" fn( user_data: *mut libc::c_void, plugin_config_json: *const c_char, ) -> *mut c_char; @@ -203,11 +203,11 @@ pub type NemoFlowPluginValidateCb = unsafe extern "C" fn( /// Callback for plugin registration. /// Receives plugin config JSON and a plugin context pointer that is /// only valid for the duration of the call. -pub type NemoFlowPluginRegisterCb = unsafe extern "C" fn( +pub type NemoRelayPluginRegisterCb = unsafe extern "C" fn( user_data: *mut libc::c_void, plugin_config_json: *const c_char, ctx: *mut FfiPluginContext, -) -> NemoFlowStatus; +) -> NemoRelayStatus; // --------------------------------------------------------------------------- // Shared user_data wrapper (ensures cleanup) @@ -217,7 +217,7 @@ pub type NemoFlowPluginRegisterCb = unsafe extern "C" fn( /// Ensures the free function is called exactly once when dropped. struct UserData { ptr: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, } unsafe impl Send for UserData {} @@ -233,7 +233,7 @@ impl Drop for UserData { fn make_user_data( user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> std::sync::Arc { std::sync::Arc::new(UserData { ptr: user_data, @@ -247,27 +247,27 @@ fn make_user_data( /// Wrap a C tool sanitize callback into a Rust closure for use by the core runtime. pub fn wrap_tool_sanitize_fn( - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> ToolSanitizeFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |name: &str, args: Json| { let c_name = CString::new(name).unwrap_or_default(); let c_args = json_to_c_string(&args); let result_ptr = unsafe { cb(ud.ptr, c_name.as_ptr(), c_args) }; - unsafe { nemo_flow_string_free_internal(c_args) }; + unsafe { nemo_relay_string_free_internal(c_args) }; let result = ptr_to_json(result_ptr); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } /// Wrap a C tool conditional callback into a Rust closure for use by the core runtime. pub fn wrap_tool_conditional_fn( - cb: NemoFlowToolConditionalCb, + cb: NemoRelayToolConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> ToolConditionalFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |name: &str, args: &Json| { @@ -275,7 +275,7 @@ pub fn wrap_tool_conditional_fn( let c_name = CString::new(name).unwrap_or_default(); let c_args = json_to_c_string(args); let result_ptr = unsafe { cb(ud.ptr, c_name.as_ptr(), c_args) }; - unsafe { nemo_flow_string_free_internal(c_args) }; + unsafe { nemo_relay_string_free_internal(c_args) }; let result = if result_ptr.is_null() { match last_error_message() { Some(message) => Err(FlowError::Internal(message)), @@ -284,16 +284,16 @@ pub fn wrap_tool_conditional_fn( } else { Ok(ptr_to_opt_string(result_ptr)) }; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } /// Wrap a C tool request intercept callback into a Rust closure for use by the core runtime. pub fn wrap_tool_request_intercept_fn( - cb: NemoFlowToolSanitizeCb, + cb: NemoRelayToolSanitizeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> ToolInterceptFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |name: &str, args: Json| { @@ -301,19 +301,19 @@ pub fn wrap_tool_request_intercept_fn( let c_name = CString::new(name).unwrap_or_default(); let c_args = json_to_c_string(&args); let result_ptr = unsafe { cb(ud.ptr, c_name.as_ptr(), c_args) }; - unsafe { nemo_flow_string_free_internal(c_args) }; + unsafe { nemo_relay_string_free_internal(c_args) }; let result = json_result_from_ptr(result_ptr, "tool request intercept callback returned null"); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } /// Wrap a C tool execution callback into an async Rust closure. pub fn wrap_tool_exec_fn( - cb: NemoFlowToolExecCb, + cb: NemoRelayToolExecCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Box Pin> + Send>> + Send + Sync> { let ud = make_user_data(user_data, free_fn); Box::new(move |args: Json| { @@ -321,9 +321,9 @@ pub fn wrap_tool_exec_fn( Box::pin(async move { let c_args = json_to_c_string(&args); let result_ptr = unsafe { cb(ud.ptr, c_args) }; - unsafe { nemo_flow_string_free_internal(c_args) }; + unsafe { nemo_relay_string_free_internal(c_args) }; let result = json_result_from_ptr(result_ptr, "tool execution callback failed")?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(result) }) }) @@ -334,9 +334,9 @@ pub fn wrap_tool_exec_fn( /// The wrapper packages the Rust `ToolExecutionNextFn` into a C-callable /// `(next_fn, next_ctx)` pair and passes both to the C intercept callback. pub fn wrap_tool_exec_intercept_fn( - cb: NemoFlowToolExecInterceptCb, + cb: NemoRelayToolExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Arc< dyn Fn(&str, Json, ToolExecutionNextFn) -> Pin> + Send>> + Send @@ -365,7 +365,7 @@ pub fn wrap_tool_exec_intercept_fn( }; // Use block_in_place to allow nested block_on within the // multi-threaded tokio runtime (the outer block_on in - // nemo_flow_tool_call_execute already occupies this worker). + // nemo_relay_tool_call_execute already occupies this worker). let handle = tokio::runtime::Handle::current(); let result = tokio::task::block_in_place(|| handle.block_on(next(args))); match result { @@ -380,10 +380,10 @@ pub fn wrap_tool_exec_intercept_fn( let c_args = json_to_c_string(&args); let result_ptr = unsafe { cb(ud.ptr, c_args, tool_next_trampoline, next_ctx) }; unsafe { drop(Box::from_raw(next_ctx as *mut ToolExecutionNextFn)) }; - unsafe { nemo_flow_string_free_internal(c_args) }; + unsafe { nemo_relay_string_free_internal(c_args) }; let result = json_result_from_ptr(result_ptr, "tool execution intercept callback failed")?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(result) }) }) @@ -391,9 +391,9 @@ pub fn wrap_tool_exec_intercept_fn( /// Wrap a C LLM execution intercept callback into an `Arc ...>`. pub fn wrap_llm_exec_intercept_fn( - cb: NemoFlowLlmExecInterceptCb, + cb: NemoRelayLlmExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Arc< dyn Fn( &str, @@ -447,10 +447,10 @@ pub fn wrap_llm_exec_intercept_fn( let c_request = json_to_c_string(&request_json); let result_ptr = unsafe { cb(ud.ptr, c_request, llm_next_trampoline, next_ctx) }; unsafe { drop(Box::from_raw(next_ctx as *mut LlmExecutionNextFn)) }; - unsafe { nemo_flow_string_free_internal(c_request) }; + unsafe { nemo_relay_string_free_internal(c_request) }; let result = json_result_from_ptr(result_ptr, "LLM execution intercept callback failed")?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(result) }) }, @@ -461,9 +461,9 @@ pub fn wrap_llm_exec_intercept_fn( /// Since the C callback returns a single string (not a real stream), this wraps /// it as a single-item stream, same as `wrap_llm_stream_exec_fn`. pub fn wrap_llm_stream_exec_intercept_fn( - cb: NemoFlowLlmExecInterceptCb, + cb: NemoRelayLlmExecInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Arc< dyn Fn( &str, @@ -527,12 +527,12 @@ pub fn wrap_llm_stream_exec_intercept_fn( let result_ptr = unsafe { cb(ud.ptr, c_request, llm_stream_next_trampoline, next_ctx) }; unsafe { drop(Box::from_raw(next_ctx as *mut LlmStreamExecutionNextFn)) }; - unsafe { nemo_flow_string_free_internal(c_request) }; + unsafe { nemo_relay_string_free_internal(c_request) }; let result = json_result_from_ptr( result_ptr, "LLM stream execution intercept callback failed", )?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; let stream = tokio_stream::once(Ok(result)); Ok(Box::pin(stream) as Pin> + Send>>) }) @@ -542,17 +542,17 @@ pub fn wrap_llm_stream_exec_intercept_fn( /// Wrap a generic C JSON callback into a Rust closure. pub fn wrap_json_fn( - cb: NemoFlowJsonCb, + cb: NemoRelayJsonCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Box Json + Send + Sync> { let ud = make_user_data(user_data, free_fn); Box::new(move |value: Json| { let c_json = json_to_c_string(&value); let result_ptr = unsafe { cb(ud.ptr, c_json) }; - unsafe { nemo_flow_string_free_internal(c_json) }; + unsafe { nemo_relay_string_free_internal(c_json) }; let result = ptr_to_json(result_ptr); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } @@ -562,9 +562,9 @@ pub fn wrap_json_fn( /// the opaque `FfiLLMRequest`, and the annotated JSON (or null). It writes /// the transformed request and annotated JSON to output pointers. pub fn wrap_llm_request_intercept_fn( - cb: NemoFlowLlmRequestInterceptCb, + cb: NemoRelayLlmRequestInterceptCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> LlmRequestInterceptFn { let ud = make_user_data(user_data, free_fn); Arc::new( @@ -605,7 +605,7 @@ pub fn wrap_llm_request_intercept_fn( // Free the input request unsafe { drop(Box::from_raw(ffi_req)) }; - if status != NemoFlowStatus::Ok { + if status != NemoRelayStatus::Ok { let message = last_error_message() .unwrap_or_else(|| "request intercept callback failed".to_string()); return Err(FlowError::Internal(message)); @@ -627,7 +627,7 @@ pub fn wrap_llm_request_intercept_fn( } else { let s = unsafe { CStr::from_ptr(out_annotated) }.to_string_lossy(); let parsed: Option = serde_json::from_str(&s).ok(); - unsafe { nemo_flow_string_free_internal(out_annotated) }; + unsafe { nemo_relay_string_free_internal(out_annotated) }; parsed }; @@ -640,26 +640,26 @@ pub fn wrap_llm_request_intercept_fn( /// sanitization. The callback receives the response as a JSON string and /// returns the (possibly modified) JSON string. pub fn wrap_llm_response_fn( - cb: NemoFlowJsonCb, + cb: NemoRelayJsonCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> LlmSanitizeResponseFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |response: Json| { let c_json = json_to_c_string(&response); let result_ptr = unsafe { cb(ud.ptr, c_json) }; - unsafe { nemo_flow_string_free_internal(c_json) }; + unsafe { nemo_relay_string_free_internal(c_json) }; let result_json = ptr_to_json(result_ptr); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result_json }) } /// Wrap a C LLM request sanitize callback into a Rust closure. pub fn wrap_llm_sanitize_request_fn( - cb: NemoFlowLlmRequestCb, + cb: NemoRelayLlmRequestCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> LlmSanitizeRequestFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |request: LlmRequest| { @@ -682,9 +682,9 @@ pub fn wrap_llm_sanitize_request_fn( /// Wrap a C LLM conditional callback into a Rust closure. pub fn wrap_llm_conditional_fn( - cb: NemoFlowLlmConditionalCb, + cb: NemoRelayLlmConditionalCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> LlmConditionalFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |request: &LlmRequest| { @@ -699,7 +699,7 @@ pub fn wrap_llm_conditional_fn( } else { Ok(ptr_to_opt_string(result_ptr)) }; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } @@ -707,9 +707,9 @@ pub fn wrap_llm_conditional_fn( /// Wrap a C LLM execution callback into an async Rust closure. /// The C callback receives an `LlmRequest` serialized as a JSON string. pub fn wrap_llm_exec_fn( - cb: NemoFlowLlmExecCb, + cb: NemoRelayLlmExecCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Box Pin> + Send>> + Send + Sync> { let ud = make_user_data(user_data, free_fn); Box::new(move |request: LlmRequest| { @@ -718,9 +718,9 @@ pub fn wrap_llm_exec_fn( let request_json = serde_json::to_value(&request).unwrap_or(Json::Null); let c_request = json_to_c_string(&request_json); let result_ptr = unsafe { cb(ud.ptr, c_request) }; - unsafe { nemo_flow_string_free_internal(c_request) }; + unsafe { nemo_relay_string_free_internal(c_request) }; let result = json_result_from_ptr(result_ptr, "LLM execution callback failed")?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(result) }) }) @@ -730,9 +730,9 @@ pub fn wrap_llm_exec_fn( /// The C callback returns the full response as a single JSON string, which is emitted /// as a single-item stream of Json values. pub fn wrap_llm_stream_exec_fn( - cb: NemoFlowLlmExecCb, + cb: NemoRelayLlmExecCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Box< dyn Fn( LlmRequest, @@ -751,9 +751,9 @@ pub fn wrap_llm_stream_exec_fn( let request_json = serde_json::to_value(&request).unwrap_or(Json::Null); let c_request = json_to_c_string(&request_json); let result_ptr = unsafe { cb(ud.ptr, c_request) }; - unsafe { nemo_flow_string_free_internal(c_request) }; + unsafe { nemo_relay_string_free_internal(c_request) }; let result = json_result_from_ptr(result_ptr, "LLM stream execution callback failed")?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; // The C callback returns the full response as a single JSON value for stream // We emit it as a single-item stream let stream = tokio_stream::once(Ok(result)); @@ -775,13 +775,13 @@ pub fn wrap_llm_stream_exec_fn( /// The caller must ensure `cb` remains valid for the lifetime of the returned /// closure. The C callback is invoked synchronously from the stream-consumption /// task. -pub fn wrap_collector_fn(cb: NemoFlowCollectorCb) -> Box Result<()> + Send> { - // NemoFlowCollectorCb is a plain `extern "C" fn` pointer (no user_data), +pub fn wrap_collector_fn(cb: NemoRelayCollectorCb) -> Box Result<()> + Send> { + // NemoRelayCollectorCb is a plain `extern "C" fn` pointer (no user_data), // which is Copy + Send, so it can be moved into the closure directly. Box::new(move |chunk: Json| { let c_chunk = json_to_c_string(&chunk); unsafe { cb(c_chunk) }; - unsafe { nemo_flow_string_free_internal(c_chunk) }; + unsafe { nemo_relay_string_free_internal(c_chunk) }; Ok(()) }) } @@ -794,20 +794,20 @@ pub fn wrap_collector_fn(cb: NemoFlowCollectorCb) -> Box Resu /// The caller must ensure `cb` remains valid until the returned closure is /// invoked. The C callback must return a valid, heap-allocated JSON C string /// (or null, in which case `Json::Null` is returned). -pub fn wrap_finalizer_fn(cb: NemoFlowFinalizerCb) -> Box Json + Send> { +pub fn wrap_finalizer_fn(cb: NemoRelayFinalizerCb) -> Box Json + Send> { Box::new(move || { let result_ptr = unsafe { cb() }; let result = ptr_to_json(result_ptr); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result }) } /// Wrap a C event subscriber callback into a Rust closure. pub fn wrap_event_subscriber( - cb: NemoFlowEventSubscriberCb, + cb: NemoRelayEventSubscriberCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> EventSubscriberFn { let ud = make_user_data(user_data, free_fn); Arc::new(move |event: &Event| { @@ -822,8 +822,8 @@ pub fn wrap_event_subscriber( /// FFI-backed Codec that delegates `decode`/`encode` to C callback pointers. struct FfiCodec { - decode_cb: NemoFlowCodecDecodeCb, - encode_cb: NemoFlowCodecEncodeCb, + decode_cb: NemoRelayCodecDecodeCb, + encode_cb: NemoRelayCodecEncodeCb, user_data: Arc, } @@ -844,10 +844,10 @@ impl LlmCodec for FfiCodec { } let result_str = unsafe { CStr::from_ptr(result_ptr) }.to_string_lossy(); let annotated: AnnotatedLLMRequest = serde_json::from_str(&result_str).map_err(|e| { - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; FlowError::Internal(format!("codec decode: invalid JSON: {e}")) })?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(annotated) } @@ -869,10 +869,10 @@ impl LlmCodec for FfiCodec { } let result_str = unsafe { CStr::from_ptr(result_ptr) }.to_string_lossy(); let content: serde_json::Value = serde_json::from_str(&result_str).map_err(|e| { - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; FlowError::Internal(format!("codec encode: invalid result JSON: {e}")) })?; - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; Ok(LlmRequest { headers: original.headers.clone(), content, @@ -882,10 +882,10 @@ impl LlmCodec for FfiCodec { /// Wrap a pair of C codec callbacks into an `Arc`. pub fn wrap_codec_fn( - decode_cb: NemoFlowCodecDecodeCb, - encode_cb: NemoFlowCodecEncodeCb, + decode_cb: NemoRelayCodecDecodeCb, + encode_cb: NemoRelayCodecEncodeCb, user_data: *mut libc::c_void, - free_fn: NemoFlowFreeFn, + free_fn: NemoRelayFreeFn, ) -> Arc { let ud = make_user_data(user_data, free_fn); Arc::new(FfiCodec { @@ -927,7 +927,7 @@ fn ptr_to_opt_string(ptr: *mut c_char) -> Option { } /// Internal helper to free C strings we allocated. -unsafe fn nemo_flow_string_free_internal(ptr: *mut c_char) { +unsafe fn nemo_relay_string_free_internal(ptr: *mut c_char) { if !ptr.is_null() { drop(unsafe { CString::from_raw(ptr) }); } diff --git a/crates/ffi/src/convert.rs b/crates/ffi/src/convert.rs index 20ddf47d1..6105203f6 100644 --- a/crates/ffi/src/convert.rs +++ b/crates/ffi/src/convert.rs @@ -16,7 +16,7 @@ use serde_json::Value as Json; #[cfg(test)] use crate::error; -use crate::error::{NemoFlowStatus, set_last_error}; +use crate::error::{NemoRelayStatus, set_last_error}; /// Parse a null-terminated C string as JSON. Returns `None` on error and sets last_error. pub fn c_str_to_json(ptr: *const c_char) -> Option { @@ -62,7 +62,7 @@ pub fn unix_micros_to_opt_timestamp(ptr: *const i64) -> Option *mut c_char { match serde_json::to_string(value) { Ok(s) => CString::new(s).unwrap_or_default().into_raw(), @@ -76,28 +76,28 @@ pub fn str_to_c_string(s: &str) -> *mut c_char { } /// Parse a C string to a Rust String. Returns Err status on failure. -pub fn c_str_to_string(ptr: *const c_char) -> Result { +pub fn c_str_to_string(ptr: *const c_char) -> Result { if ptr.is_null() { set_last_error("null string pointer"); - return Err(NemoFlowStatus::NullPointer); + return Err(NemoRelayStatus::NullPointer); } unsafe { CStr::from_ptr(ptr) } .to_str() .map(|s| s.to_string()) .map_err(|e| { set_last_error(&format!("invalid UTF-8: {e}")); - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 }) } -/// Free a C string previously returned by any `nemo_flow_*` accessor function. +/// Free a C string previously returned by any `nemo_relay_*` accessor function. /// Passing null is a safe no-op. /// /// # Safety /// `ptr` must be a pointer returned by this library, or null. Double-free is /// undefined behavior. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_string_free(ptr: *mut c_char) { +pub unsafe extern "C" fn nemo_relay_string_free(ptr: *mut c_char) { if !ptr.is_null() { drop(unsafe { CString::from_raw(ptr) }); } diff --git a/crates/ffi/src/error.rs b/crates/ffi/src/error.rs index 99145d108..f014c847c 100644 --- a/crates/ffi/src/error.rs +++ b/crates/ffi/src/error.rs @@ -3,10 +3,10 @@ //! Error handling for the FFI layer. //! -//! This module defines the [`NemoFlowStatus`] enum returned by every exported +//! This module defines the [`NemoRelayStatus`] enum returned by every exported //! FFI function, along with thread-local storage for human-readable error //! messages. After any non-`Ok` return, the caller should invoke -//! [`nemo_flow_last_error`] on the same thread to obtain a diagnostic string. +//! [`nemo_relay_last_error`] on the same thread to obtain a diagnostic string. //! The error message remains valid until the next FFI call on that thread clears //! it via [`clear_last_error`]. @@ -16,17 +16,17 @@ use std::ffi::CString; use libc::c_char; -use nemo_flow::error::FlowError; -use nemo_flow::plugin::PluginError; +use nemo_relay::error::FlowError; +use nemo_relay::plugin::PluginError; /// Status codes returned by all FFI functions. /// -/// Every `extern "C"` function in this library returns an `NemoFlowStatus`. -/// On non-`Ok` returns, call [`nemo_flow_last_error`] on the same thread to +/// Every `extern "C"` function in this library returns an `NemoRelayStatus`. +/// On non-`Ok` returns, call [`nemo_relay_last_error`] on the same thread to /// retrieve a human-readable error message. #[repr(i32)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NemoFlowStatus { +pub enum NemoRelayStatus { /// Operation completed successfully. Ok = 0, /// A resource with the given name already exists. @@ -83,7 +83,7 @@ pub fn last_error_message() -> Option { /// until the next FFI call on the same thread. Do **not** free the returned /// pointer. #[unsafe(no_mangle)] -pub extern "C" fn nemo_flow_last_error() -> *const c_char { +pub extern "C" fn nemo_relay_last_error() -> *const c_char { LAST_ERROR.with(|cell| { cell.borrow() .as_ref() @@ -101,7 +101,7 @@ pub extern "C" fn nemo_flow_last_error() -> *const c_char { /// `msg` must be either null or a valid, null-terminated C string for the /// duration of this call. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_set_last_error_message(msg: *const c_char) { +pub unsafe extern "C" fn nemo_relay_set_last_error_message(msg: *const c_char) { if msg.is_null() { set_last_error("unknown callback error"); return; @@ -112,34 +112,36 @@ pub unsafe extern "C" fn nemo_flow_set_last_error_message(msg: *const c_char) { } } -impl From<&FlowError> for NemoFlowStatus { +impl From<&FlowError> for NemoRelayStatus { fn from(e: &FlowError) -> Self { match e { - FlowError::AlreadyExists(_) => NemoFlowStatus::AlreadyExists, - FlowError::NotFound(_) => NemoFlowStatus::NotFound, - FlowError::InvalidArgument(_) => NemoFlowStatus::InvalidArg, - FlowError::ScopeStackEmpty => NemoFlowStatus::ScopeStackEmpty, - FlowError::GuardrailRejected(_) => NemoFlowStatus::GuardrailRejected, - FlowError::Internal(_) => NemoFlowStatus::Internal, + FlowError::AlreadyExists(_) => NemoRelayStatus::AlreadyExists, + FlowError::NotFound(_) => NemoRelayStatus::NotFound, + FlowError::InvalidArgument(_) => NemoRelayStatus::InvalidArg, + FlowError::ScopeStackEmpty => NemoRelayStatus::ScopeStackEmpty, + FlowError::GuardrailRejected(_) => NemoRelayStatus::GuardrailRejected, + FlowError::Internal(_) => NemoRelayStatus::Internal, } } } -/// Convert an `FlowError` to an `NemoFlowStatus`, storing the error message +/// Convert an `FlowError` to an `NemoRelayStatus`, storing the error message /// in thread-local storage. -pub fn status_from_error(e: &FlowError) -> NemoFlowStatus { +pub fn status_from_error(e: &FlowError) -> NemoRelayStatus { set_last_error(&e.to_string()); - NemoFlowStatus::from(e) + NemoRelayStatus::from(e) } -/// Convert a `PluginError` to an `NemoFlowStatus`, storing the error message +/// Convert a `PluginError` to an `NemoRelayStatus`, storing the error message /// in thread-local storage. -pub fn status_from_plugin_error(e: &PluginError) -> NemoFlowStatus { +pub fn status_from_plugin_error(e: &PluginError) -> NemoRelayStatus { set_last_error(&e.to_string()); match e { - PluginError::NotFound(_) => NemoFlowStatus::NotFound, - PluginError::InvalidConfig(_) | PluginError::Serialization(_) => NemoFlowStatus::InvalidArg, - PluginError::Internal(_) | PluginError::RegistrationFailed(_) => NemoFlowStatus::Internal, + PluginError::NotFound(_) => NemoRelayStatus::NotFound, + PluginError::InvalidConfig(_) | PluginError::Serialization(_) => { + NemoRelayStatus::InvalidArg + } + PluginError::Internal(_) | PluginError::RegistrationFailed(_) => NemoRelayStatus::Internal, } } diff --git a/crates/ffi/src/lib.rs b/crates/ffi/src/lib.rs index bc4083c19..3271aa146 100644 --- a/crates/ffi/src/lib.rs +++ b/crates/ffi/src/lib.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! C FFI layer for NeMo Flow. +//! C FFI layer for NeMo Relay. //! -//! This crate exposes the NeMo Flow core runtime as a C-compatible shared library. +//! This crate exposes the NeMo Relay core runtime as a C-compatible shared library. //! It is consumed by the Go bindings via CGo and regenerates the committed -//! `nemo_flow.h` header through `cbindgen` during Cargo builds. All exported -//! symbols use the `nemo_flow_` prefix. +//! `nemo_relay.h` header through `cbindgen` during Cargo builds. All exported +//! symbols use the `nemo_relay_` prefix. //! //! # Middleware Pipeline //! @@ -21,8 +21,8 @@ //! //! # Error Handling //! -//! Every `extern "C"` function returns an [`error::NemoFlowStatus`] code. On -//! failure, call [`error::nemo_flow_last_error`] on the same thread to retrieve +//! Every `extern "C"` function returns an [`error::NemoRelayStatus`] code. On +//! failure, call [`error::nemo_relay_last_error`] on the same thread to retrieve //! a human-readable error description. The error is stored in thread-local //! storage and is valid until the next FFI call on that thread. //! @@ -30,18 +30,18 @@ //! //! All opaque handles (`FfiScopeHandle`, `FfiToolHandle`, `FfiLLMHandle`, etc.) //! are heap-allocated and must be freed through their corresponding -//! `nemo_flow_*_free` functions. C strings returned by accessor functions must -//! be freed with `nemo_flow_string_free`. +//! `nemo_relay_*_free` functions. C strings returned by accessor functions must +//! be freed with `nemo_relay_string_free`. //! //! # Modules //! //! - [`api`] -- Top-level FFI entry points (scope, tool, LLM, guardrail, intercept, //! subscriber, ATIF exporter). Tool calls accept an optional `tool_call_id` and //! LLM calls accept an optional `model_name` for ATIF trajectory correlation. -//! ATIF exporter functions (`nemo_flow_atif_exporter_*`) create, register, +//! ATIF exporter functions (`nemo_relay_atif_exporter_*`) create, register, //! export, and clear trajectory data. //! - [`types`] -- C-compatible struct and enum definitions, plus event accessor -//! functions (`nemo_flow_event_input`, `_output`, `_model_name`, `_tool_call_id`, +//! functions (`nemo_relay_event_input`, `_output`, `_model_name`, `_tool_call_id`, //! `_parent_uuid`, `_scope_type`) and the `FfiAtifExporter` //! opaque handle. //! - [`error`] -- Status codes and thread-local error storage. diff --git a/crates/ffi/src/types/mod.rs b/crates/ffi/src/types/mod.rs index e99d13686..fa9c6bd51 100644 --- a/crates/ffi/src/types/mod.rs +++ b/crates/ffi/src/types/mod.rs @@ -7,25 +7,25 @@ //! and free functions for all types that cross the C FFI boundary. Each opaque //! struct wraps a corresponding core type and is heap-allocated; the C consumer //! sees only an opaque pointer. All returned C strings must be freed with -//! [`crate::convert::nemo_flow_string_free`], and all handles must be freed -//! with their corresponding `nemo_flow_*_free` function. +//! [`crate::convert::nemo_relay_string_free`], and all handles must be freed +//! with their corresponding `nemo_relay_*_free` function. use libc::c_char; -use nemo_flow::api::runtime::{ScopeStackHandle, ThreadScopeStackBinding}; -use nemo_flow::plugin::PluginRegistrationContext; +use nemo_relay::api::runtime::{ScopeStackHandle, ThreadScopeStackBinding}; +use nemo_relay::plugin::PluginRegistrationContext; use serde_json::Value as Json; -use nemo_flow::api::event::Event; +use nemo_relay::api::event::Event; #[cfg(test)] -use nemo_flow::api::llm::LlmAttributes; -use nemo_flow::api::llm::{LlmHandle, LlmRequest}; +use nemo_relay::api::llm::LlmAttributes; +use nemo_relay::api::llm::{LlmHandle, LlmRequest}; #[cfg(test)] -use nemo_flow::api::scope::ScopeAttributes; -use nemo_flow::api::scope::{ScopeHandle, ScopeType}; +use nemo_relay::api::scope::ScopeAttributes; +use nemo_relay::api::scope::{ScopeHandle, ScopeType}; #[cfg(test)] -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::api::tool::ToolHandle; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::api::tool::ToolHandle; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; use crate::convert::{json_to_c_string, str_to_c_string}; use crate::error::set_last_error; @@ -52,31 +52,31 @@ pub struct FfiScopeStack(pub ScopeStackHandle); /// Opaque handle to a captured thread-local scope stack binding. pub struct FfiThreadScopeStackBinding(pub ThreadScopeStackBinding); /// Opaque ATIF exporter handle. -pub struct FfiAtifExporter(pub nemo_flow::observability::atif::AtifExporter); +pub struct FfiAtifExporter(pub nemo_relay::observability::atif::AtifExporter); /// Opaque ATOF JSONL exporter handle. -pub struct FfiAtofExporter(pub nemo_flow::observability::atof::AtofExporter); +pub struct FfiAtofExporter(pub nemo_relay::observability::atof::AtofExporter); /// Opaque OpenTelemetry subscriber handle. -pub struct FfiOpenTelemetrySubscriber(pub nemo_flow::observability::otel::OpenTelemetrySubscriber); +pub struct FfiOpenTelemetrySubscriber(pub nemo_relay::observability::otel::OpenTelemetrySubscriber); /// Opaque OpenInference subscriber handle. pub struct FfiOpenInferenceSubscriber( - pub nemo_flow::observability::openinference::OpenInferenceSubscriber, + pub nemo_relay::observability::openinference::OpenInferenceSubscriber, ); /// Opaque plugin registration context. /// /// This wrapper contains a borrowed raw pointer to an -/// `nemo_flow::plugin::PluginRegistrationContext`, not an owned heap allocation. +/// `nemo_relay::plugin::PluginRegistrationContext`, not an owned heap allocation. /// It is only valid for the duration of the plugin registration callback that receives /// it. C callers must not store the pointer, use it after the callback returns, or attempt to /// free or drop it. /// -/// There is intentionally no `nemo_flow_plugin_context_free` function because this FFI +/// There is intentionally no `nemo_relay_plugin_context_free` function because this FFI /// wrapper does not own the underlying registration context. pub struct FfiPluginContext(pub *mut PluginRegistrationContext); /// Opaque handle carrying both request and response codec trait objects. /// -/// Created by `nemo_flow_openai_chat_codec_new` (and similar constructors). -/// Freed by `nemo_flow_codec_free`. The handle carries two `Arc`s pointing +/// Created by `nemo_relay_openai_chat_codec_new` (and similar constructors). +/// Freed by `nemo_relay_codec_free`. The handle carries two `Arc`s pointing /// to the same underlying codec instance: one for the `LlmCodec` trait and /// one for the `LlmResponseCodec` trait. pub struct FfiCodecHandle { @@ -92,7 +92,7 @@ pub struct FfiCodecHandle { /// The type of scope in the agent execution hierarchy. #[repr(i32)] #[derive(Debug, Clone, Copy)] -pub enum NemoFlowScopeType { +pub enum NemoRelayScopeType { /// Top-level agent scope. Agent = 0, /// Generic function scope. @@ -117,38 +117,38 @@ pub enum NemoFlowScopeType { Unknown = 10, } -impl From for ScopeType { - fn from(v: NemoFlowScopeType) -> Self { +impl From for ScopeType { + fn from(v: NemoRelayScopeType) -> Self { match v { - NemoFlowScopeType::Agent => ScopeType::Agent, - NemoFlowScopeType::Function => ScopeType::Function, - NemoFlowScopeType::Tool => ScopeType::Tool, - NemoFlowScopeType::Llm => ScopeType::Llm, - NemoFlowScopeType::Retriever => ScopeType::Retriever, - NemoFlowScopeType::Embedder => ScopeType::Embedder, - NemoFlowScopeType::Reranker => ScopeType::Reranker, - NemoFlowScopeType::Guardrail => ScopeType::Guardrail, - NemoFlowScopeType::Evaluator => ScopeType::Evaluator, - NemoFlowScopeType::Custom => ScopeType::Custom, - NemoFlowScopeType::Unknown => ScopeType::Unknown, + NemoRelayScopeType::Agent => ScopeType::Agent, + NemoRelayScopeType::Function => ScopeType::Function, + NemoRelayScopeType::Tool => ScopeType::Tool, + NemoRelayScopeType::Llm => ScopeType::Llm, + NemoRelayScopeType::Retriever => ScopeType::Retriever, + NemoRelayScopeType::Embedder => ScopeType::Embedder, + NemoRelayScopeType::Reranker => ScopeType::Reranker, + NemoRelayScopeType::Guardrail => ScopeType::Guardrail, + NemoRelayScopeType::Evaluator => ScopeType::Evaluator, + NemoRelayScopeType::Custom => ScopeType::Custom, + NemoRelayScopeType::Unknown => ScopeType::Unknown, } } } -impl From for NemoFlowScopeType { +impl From for NemoRelayScopeType { fn from(v: ScopeType) -> Self { match v { - ScopeType::Agent => NemoFlowScopeType::Agent, - ScopeType::Function => NemoFlowScopeType::Function, - ScopeType::Tool => NemoFlowScopeType::Tool, - ScopeType::Llm => NemoFlowScopeType::Llm, - ScopeType::Retriever => NemoFlowScopeType::Retriever, - ScopeType::Embedder => NemoFlowScopeType::Embedder, - ScopeType::Reranker => NemoFlowScopeType::Reranker, - ScopeType::Guardrail => NemoFlowScopeType::Guardrail, - ScopeType::Evaluator => NemoFlowScopeType::Evaluator, - ScopeType::Custom => NemoFlowScopeType::Custom, - ScopeType::Unknown => NemoFlowScopeType::Unknown, + ScopeType::Agent => NemoRelayScopeType::Agent, + ScopeType::Function => NemoRelayScopeType::Function, + ScopeType::Tool => NemoRelayScopeType::Tool, + ScopeType::Llm => NemoRelayScopeType::Llm, + ScopeType::Retriever => NemoRelayScopeType::Retriever, + ScopeType::Embedder => NemoRelayScopeType::Embedder, + ScopeType::Reranker => NemoRelayScopeType::Reranker, + ScopeType::Guardrail => NemoRelayScopeType::Guardrail, + ScopeType::Evaluator => NemoRelayScopeType::Evaluator, + ScopeType::Custom => NemoRelayScopeType::Custom, + ScopeType::Unknown => NemoRelayScopeType::Unknown, } } } @@ -160,9 +160,9 @@ impl From for NemoFlowScopeType { /// Free a scope handle previously returned by the runtime. /// /// # Safety -/// `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. +/// `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_free(ptr: *mut FfiScopeHandle) { +pub unsafe extern "C" fn nemo_relay_scope_handle_free(ptr: *mut FfiScopeHandle) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } @@ -171,9 +171,9 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_free(ptr: *mut FfiScopeHandle) { /// Free a tool handle previously returned by the runtime. /// /// # Safety -/// `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. +/// `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_handle_free(ptr: *mut FfiToolHandle) { +pub unsafe extern "C" fn nemo_relay_tool_handle_free(ptr: *mut FfiToolHandle) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } @@ -182,9 +182,9 @@ pub unsafe extern "C" fn nemo_flow_tool_handle_free(ptr: *mut FfiToolHandle) { /// Free an LLM handle previously returned by the runtime. /// /// # Safety -/// `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. +/// `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_handle_free(ptr: *mut FfiLLMHandle) { +pub unsafe extern "C" fn nemo_relay_llm_handle_free(ptr: *mut FfiLLMHandle) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } @@ -193,9 +193,9 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_free(ptr: *mut FfiLLMHandle) { /// Free an LLM request object. /// /// # Safety -/// `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. +/// `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_request_free(ptr: *mut FfiLLMRequest) { +pub unsafe extern "C" fn nemo_relay_llm_request_free(ptr: *mut FfiLLMRequest) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } @@ -204,67 +204,67 @@ pub unsafe extern "C" fn nemo_flow_llm_request_free(ptr: *mut FfiLLMRequest) { /// Free an event object. /// /// # Safety -/// `ptr` must be a valid pointer returned by an `nemo_flow_*` function, or null. +/// `ptr` must be a valid pointer returned by an `nemo_relay_*` function, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_free(ptr: *mut FfiEvent) { +pub unsafe extern "C" fn nemo_relay_event_free(ptr: *mut FfiEvent) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } } -/// Free a scope stack handle previously returned by `nemo_flow_scope_stack_create`. +/// Free a scope stack handle previously returned by `nemo_relay_scope_stack_create`. /// /// # Safety -/// `ptr` must be a valid pointer returned by `nemo_flow_scope_stack_create`, or null. +/// `ptr` must be a valid pointer returned by `nemo_relay_scope_stack_create`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_stack_free(ptr: *mut FfiScopeStack) { +pub unsafe extern "C" fn nemo_relay_scope_stack_free(ptr: *mut FfiScopeStack) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } } -/// Free an ATIF exporter handle previously returned by `nemo_flow_atif_exporter_create`. +/// Free an ATIF exporter handle previously returned by `nemo_relay_atif_exporter_create`. /// /// # Safety -/// `ptr` must be a valid pointer returned by `nemo_flow_atif_exporter_create`, or null. +/// `ptr` must be a valid pointer returned by `nemo_relay_atif_exporter_create`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atif_exporter_free(ptr: *mut FfiAtifExporter) { +pub unsafe extern "C" fn nemo_relay_atif_exporter_free(ptr: *mut FfiAtifExporter) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } } -/// Free an ATOF JSONL exporter handle previously returned by `nemo_flow_atof_exporter_create`. +/// Free an ATOF JSONL exporter handle previously returned by `nemo_relay_atof_exporter_create`. /// /// # Safety -/// `ptr` must be a valid pointer returned by `nemo_flow_atof_exporter_create`, or null. +/// `ptr` must be a valid pointer returned by `nemo_relay_atof_exporter_create`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_atof_exporter_free(ptr: *mut FfiAtofExporter) { +pub unsafe extern "C" fn nemo_relay_atof_exporter_free(ptr: *mut FfiAtofExporter) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } } /// Free an OpenTelemetry subscriber handle previously returned by -/// `nemo_flow_otel_subscriber_create`. +/// `nemo_relay_otel_subscriber_create`. /// /// # Safety -/// `ptr` must be a valid pointer returned by `nemo_flow_otel_subscriber_create`, or null. +/// `ptr` must be a valid pointer returned by `nemo_relay_otel_subscriber_create`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_otel_subscriber_free(ptr: *mut FfiOpenTelemetrySubscriber) { +pub unsafe extern "C" fn nemo_relay_otel_subscriber_free(ptr: *mut FfiOpenTelemetrySubscriber) { if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }); } } /// Free an OpenInference subscriber handle previously returned by -/// `nemo_flow_openinference_subscriber_create`. +/// `nemo_relay_openinference_subscriber_create`. /// /// # Safety /// `ptr` must be a valid pointer returned by -/// `nemo_flow_openinference_subscriber_create`, or null. +/// `nemo_relay_openinference_subscriber_create`, or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_openinference_subscriber_free( +pub unsafe extern "C" fn nemo_relay_openinference_subscriber_free( ptr: *mut FfiOpenInferenceSubscriber, ) { if !ptr.is_null() { @@ -273,13 +273,13 @@ pub unsafe extern "C" fn nemo_flow_openinference_subscriber_free( } /// Free a codec handle previously returned by one of the codec constructor -/// functions (`nemo_flow_openai_chat_codec_new`, etc.). +/// functions (`nemo_relay_openai_chat_codec_new`, etc.). /// /// # Safety /// `handle` must be a valid pointer returned by one of the codec constructor /// functions, or null. Double-free is undefined behavior. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_codec_free(handle: *mut FfiCodecHandle) { +pub unsafe extern "C" fn nemo_relay_codec_free(handle: *mut FfiCodecHandle) { if !handle.is_null() { drop(unsafe { Box::from_raw(handle) }); } @@ -290,12 +290,12 @@ pub unsafe extern "C" fn nemo_flow_codec_free(handle: *mut FfiCodecHandle) { // --------------------------------------------------------------------------- /// Return the UUID of a scope handle as a C string. Caller must free the result -/// with `nemo_flow_string_free`. Returns null if `ptr` is null. +/// with `nemo_relay_string_free`. Returns null if `ptr` is null. /// /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_uuid(ptr: *const FfiScopeHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_scope_handle_uuid(ptr: *const FfiScopeHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -308,7 +308,7 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_uuid(ptr: *const FfiScopeHandle) /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_name(ptr: *const FfiScopeHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_scope_handle_name(ptr: *const FfiScopeHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -320,11 +320,11 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_name(ptr: *const FfiScopeHandle) /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_scope_type( +pub unsafe extern "C" fn nemo_relay_scope_handle_scope_type( ptr: *const FfiScopeHandle, -) -> NemoFlowScopeType { +) -> NemoRelayScopeType { if ptr.is_null() { - return NemoFlowScopeType::Unknown; + return NemoRelayScopeType::Unknown; } unsafe { &*ptr }.0.scope_type.into() } @@ -334,7 +334,7 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_scope_type( /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_attributes(ptr: *const FfiScopeHandle) -> u32 { +pub unsafe extern "C" fn nemo_relay_scope_handle_attributes(ptr: *const FfiScopeHandle) -> u32 { if ptr.is_null() { return 0; } @@ -342,12 +342,12 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_attributes(ptr: *const FfiScopeH } /// Return the parent scope UUID as a C string, or null if there is no parent. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_parent_uuid( +pub unsafe extern "C" fn nemo_relay_scope_handle_parent_uuid( ptr: *const FfiScopeHandle, ) -> *mut c_char { if ptr.is_null() { @@ -360,12 +360,12 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_parent_uuid( } /// Return the scope data as a JSON C string, or null if no data is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_data(ptr: *const FfiScopeHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_scope_handle_data(ptr: *const FfiScopeHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -376,12 +376,12 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_data(ptr: *const FfiScopeHandle) } /// Return the scope metadata as a JSON C string, or null if no metadata is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiScopeHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_scope_handle_metadata( +pub unsafe extern "C" fn nemo_relay_scope_handle_metadata( ptr: *const FfiScopeHandle, ) -> *mut c_char { if ptr.is_null() { @@ -402,7 +402,7 @@ pub unsafe extern "C" fn nemo_flow_scope_handle_metadata( /// # Safety /// `ptr` must be a valid `FfiToolHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_handle_uuid(ptr: *const FfiToolHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_tool_handle_uuid(ptr: *const FfiToolHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -414,7 +414,7 @@ pub unsafe extern "C" fn nemo_flow_tool_handle_uuid(ptr: *const FfiToolHandle) - /// # Safety /// `ptr` must be a valid `FfiToolHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_handle_name(ptr: *const FfiToolHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_tool_handle_name(ptr: *const FfiToolHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -426,7 +426,7 @@ pub unsafe extern "C" fn nemo_flow_tool_handle_name(ptr: *const FfiToolHandle) - /// # Safety /// `ptr` must be a valid `FfiToolHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_handle_attributes(ptr: *const FfiToolHandle) -> u32 { +pub unsafe extern "C" fn nemo_relay_tool_handle_attributes(ptr: *const FfiToolHandle) -> u32 { if ptr.is_null() { return 0; } @@ -434,12 +434,12 @@ pub unsafe extern "C" fn nemo_flow_tool_handle_attributes(ptr: *const FfiToolHan } /// Return the parent scope UUID of a tool handle, or null if none. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiToolHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_tool_handle_parent_uuid( +pub unsafe extern "C" fn nemo_relay_tool_handle_parent_uuid( ptr: *const FfiToolHandle, ) -> *mut c_char { if ptr.is_null() { @@ -460,7 +460,7 @@ pub unsafe extern "C" fn nemo_flow_tool_handle_parent_uuid( /// # Safety /// `ptr` must be a valid `FfiLLMHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_handle_uuid(ptr: *const FfiLLMHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_llm_handle_uuid(ptr: *const FfiLLMHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -472,7 +472,7 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_uuid(ptr: *const FfiLLMHandle) -> /// # Safety /// `ptr` must be a valid `FfiLLMHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_handle_name(ptr: *const FfiLLMHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_llm_handle_name(ptr: *const FfiLLMHandle) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -484,7 +484,7 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_name(ptr: *const FfiLLMHandle) -> /// # Safety /// `ptr` must be a valid `FfiLLMHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_handle_attributes(ptr: *const FfiLLMHandle) -> u32 { +pub unsafe extern "C" fn nemo_relay_llm_handle_attributes(ptr: *const FfiLLMHandle) -> u32 { if ptr.is_null() { return 0; } @@ -492,12 +492,14 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_attributes(ptr: *const FfiLLMHandl } /// Return the parent scope UUID of an LLM handle, or null if none. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiLLMHandle` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_handle_parent_uuid(ptr: *const FfiLLMHandle) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_llm_handle_parent_uuid( + ptr: *const FfiLLMHandle, +) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -512,7 +514,7 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_parent_uuid(ptr: *const FfiLLMHand // --------------------------------------------------------------------------- /// Create a new LLM request object. Returns a heap-allocated `FfiLLMRequest` -/// that must be freed with `nemo_flow_llm_request_free`. Returns null on +/// that must be freed with `nemo_relay_llm_request_free`. Returns null on /// invalid input. /// /// # Parameters @@ -522,7 +524,7 @@ pub unsafe extern "C" fn nemo_flow_llm_handle_parent_uuid(ptr: *const FfiLLMHand /// # Safety /// All string arguments must be valid null-terminated C strings or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_request_new( +pub unsafe extern "C" fn nemo_relay_llm_request_new( headers_json: *const c_char, content_json: *const c_char, ) -> *mut FfiLLMRequest { @@ -540,7 +542,7 @@ pub unsafe extern "C" fn nemo_flow_llm_request_new( /// # Safety /// `ptr` must be a valid `FfiLLMRequest` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_request_headers(ptr: *const FfiLLMRequest) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_llm_request_headers(ptr: *const FfiLLMRequest) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -552,7 +554,7 @@ pub unsafe extern "C" fn nemo_flow_llm_request_headers(ptr: *const FfiLLMRequest /// # Safety /// `ptr` must be a valid `FfiLLMRequest` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_llm_request_content(ptr: *const FfiLLMRequest) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_llm_request_content(ptr: *const FfiLLMRequest) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -568,7 +570,7 @@ pub unsafe extern "C" fn nemo_flow_llm_request_content(ptr: *const FfiLLMRequest /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_uuid(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_uuid(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -576,12 +578,12 @@ pub unsafe extern "C" fn nemo_flow_event_uuid(ptr: *const FfiEvent) -> *mut c_ch } /// Return the name of an event as a C string, or null if unnamed. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_name(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_name(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -589,12 +591,12 @@ pub unsafe extern "C" fn nemo_flow_event_name(ptr: *const FfiEvent) -> *mut c_ch } /// Return the event discriminator as a C string. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_kind(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_kind(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -602,12 +604,12 @@ pub unsafe extern "C" fn nemo_flow_event_kind(ptr: *const FfiEvent) -> *mut c_ch } /// Return the canonical subscriber event JSON as a C string. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_json(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_json(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -625,7 +627,7 @@ pub unsafe extern "C" fn nemo_flow_event_json(ptr: *const FfiEvent) -> *mut c_ch /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_atof_version(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_atof_version(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -640,13 +642,13 @@ pub unsafe extern "C" fn nemo_flow_event_atof_version(ptr: *const FfiEvent) -> * /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_scope_category(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_scope_category(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } match unsafe { &*ptr }.0.scope_category() { - Some(nemo_flow::api::event::ScopeCategory::Start) => str_to_c_string("start"), - Some(nemo_flow::api::event::ScopeCategory::End) => str_to_c_string("end"), + Some(nemo_relay::api::event::ScopeCategory::Start) => str_to_c_string("start"), + Some(nemo_relay::api::event::ScopeCategory::End) => str_to_c_string("end"), None => std::ptr::null_mut(), } } @@ -656,7 +658,7 @@ pub unsafe extern "C" fn nemo_flow_event_scope_category(ptr: *const FfiEvent) -> /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_category(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_category(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -671,7 +673,7 @@ pub unsafe extern "C" fn nemo_flow_event_category(ptr: *const FfiEvent) -> *mut /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_attributes_json(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_attributes_json(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -686,7 +688,7 @@ pub unsafe extern "C" fn nemo_flow_event_attributes_json(ptr: *const FfiEvent) - /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_category_profile(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_category_profile(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -705,7 +707,7 @@ pub unsafe extern "C" fn nemo_flow_event_category_profile(ptr: *const FfiEvent) /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_data_schema(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_data_schema(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -723,7 +725,7 @@ pub unsafe extern "C" fn nemo_flow_event_data_schema(ptr: *const FfiEvent) -> *m /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_attributes(ptr: *const FfiEvent) -> u32 { +pub unsafe extern "C" fn nemo_relay_event_attributes(ptr: *const FfiEvent) -> u32 { if ptr.is_null() { return 0; } @@ -731,12 +733,12 @@ pub unsafe extern "C" fn nemo_flow_event_attributes(ptr: *const FfiEvent) -> u32 } /// Return the event data as a JSON C string, or null if no data is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_data(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_data(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -747,12 +749,12 @@ pub unsafe extern "C" fn nemo_flow_event_data(ptr: *const FfiEvent) -> *mut c_ch } /// Return the event metadata as a JSON C string, or null if no metadata is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_metadata(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_metadata(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -767,7 +769,7 @@ pub unsafe extern "C" fn nemo_flow_event_metadata(ptr: *const FfiEvent) -> *mut /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_timestamp(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_timestamp(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -775,12 +777,12 @@ pub unsafe extern "C" fn nemo_flow_event_timestamp(ptr: *const FfiEvent) -> *mut } /// Return the event input as a JSON C string, or null if no input is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_input(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_input(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -791,12 +793,12 @@ pub unsafe extern "C" fn nemo_flow_event_input(ptr: *const FfiEvent) -> *mut c_c } /// Return the event output as a JSON C string, or null if no output is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_output(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_output(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -807,12 +809,12 @@ pub unsafe extern "C" fn nemo_flow_event_output(ptr: *const FfiEvent) -> *mut c_ } /// Return the event model name as a C string, or null if no model name is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_model_name(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_model_name(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -823,12 +825,12 @@ pub unsafe extern "C" fn nemo_flow_event_model_name(ptr: *const FfiEvent) -> *mu } /// Return the event tool call ID as a C string, or null if no tool call ID is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_tool_call_id(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_tool_call_id(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -839,12 +841,12 @@ pub unsafe extern "C" fn nemo_flow_event_tool_call_id(ptr: *const FfiEvent) -> * } /// Return the event parent UUID as a C string, or null if no parent UUID is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_parent_uuid(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_parent_uuid(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -855,12 +857,12 @@ pub unsafe extern "C" fn nemo_flow_event_parent_uuid(ptr: *const FfiEvent) -> *m } /// Return the event scope type as a C string, or null if no scope type is set. -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_scope_type(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_scope_type(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -872,12 +874,12 @@ pub unsafe extern "C" fn nemo_flow_event_scope_type(ptr: *const FfiEvent) -> *mu /// Return the annotated request from an LLM start event as a JSON C string, /// or null if not available (non-LLM events, or no codec was active). -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_annotated_request(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_annotated_request(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -892,12 +894,12 @@ pub unsafe extern "C" fn nemo_flow_event_annotated_request(ptr: *const FfiEvent) /// Return the annotated response from an LLM end event as a JSON C string, /// or null if not available (non-LLM events, or no response codec was active). -/// Caller must free the result with `nemo_flow_string_free`. +/// Caller must free the result with `nemo_relay_string_free`. /// /// # Safety /// `ptr` must be a valid `FfiEvent` pointer or null. #[unsafe(no_mangle)] -pub unsafe extern "C" fn nemo_flow_event_annotated_response(ptr: *const FfiEvent) -> *mut c_char { +pub unsafe extern "C" fn nemo_relay_event_annotated_response(ptr: *const FfiEvent) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } diff --git a/crates/ffi/tests/coverage/convert_tests.rs b/crates/ffi/tests/coverage/convert_tests.rs index 1b38330fb..8c7af4387 100644 --- a/crates/ffi/tests/coverage/convert_tests.rs +++ b/crates/ffi/tests/coverage/convert_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for convert in the NeMo Flow FFI crate. +//! Coverage tests for convert in the NeMo Relay FFI crate. use super::*; use std::ffi::CString; @@ -42,14 +42,14 @@ fn test_string_to_c_string_round_trip_and_validation() { serde_json::from_str::(&json_text).unwrap(), json!({"ok": true}) ); - unsafe { nemo_flow_string_free(json_ptr) }; + unsafe { nemo_relay_string_free(json_ptr) }; let string_ptr = str_to_c_string("ffi-string"); assert_eq!( unsafe { CStr::from_ptr(string_ptr) }.to_str().unwrap(), "ffi-string" ); - unsafe { nemo_flow_string_free(string_ptr) }; + unsafe { nemo_relay_string_free(string_ptr) }; clear_last_error(); assert_eq!( @@ -58,16 +58,16 @@ fn test_string_to_c_string_round_trip_and_validation() { ); assert_eq!( c_str_to_string(std::ptr::null()), - Err(NemoFlowStatus::NullPointer) + Err(NemoRelayStatus::NullPointer) ); assert_eq!(last_error_message(), Some("null string pointer".into())); let invalid_utf8 = [0xffu8, 0]; assert_eq!( c_str_to_string(invalid_utf8.as_ptr() as *const c_char), - Err(NemoFlowStatus::InvalidUtf8) + Err(NemoRelayStatus::InvalidUtf8) ); assert!(last_error_message().unwrap().contains("invalid UTF-8")); - unsafe { nemo_flow_string_free(std::ptr::null_mut()) }; + unsafe { nemo_relay_string_free(std::ptr::null_mut()) }; } diff --git a/crates/ffi/tests/coverage/error_tests.rs b/crates/ffi/tests/coverage/error_tests.rs index ab4622e0b..c66fa5151 100644 --- a/crates/ffi/tests/coverage/error_tests.rs +++ b/crates/ffi/tests/coverage/error_tests.rs @@ -1,23 +1,23 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for error in the NeMo Flow FFI crate. +//! Coverage tests for error in the NeMo Relay FFI crate. use super::*; use std::ffi::{CStr, CString}; -use nemo_flow::plugin::PluginError; +use nemo_relay::plugin::PluginError; #[test] fn test_last_error_round_trip_and_clear() { clear_last_error(); assert_eq!(last_error_message(), None); - assert!(nemo_flow_last_error().is_null()); + assert!(nemo_relay_last_error().is_null()); set_last_error("ffi failure"); assert_eq!(last_error_message(), Some("ffi failure".into())); - let raw = nemo_flow_last_error(); + let raw = nemo_relay_last_error(); assert_eq!( unsafe { CStr::from_ptr(raw) }.to_str().unwrap(), "ffi failure" @@ -25,17 +25,17 @@ fn test_last_error_round_trip_and_clear() { clear_last_error(); assert_eq!(last_error_message(), None); - assert!(nemo_flow_last_error().is_null()); + assert!(nemo_relay_last_error().is_null()); } #[test] fn test_set_last_error_message_handles_null_and_invalid_utf8() { - unsafe { nemo_flow_set_last_error_message(std::ptr::null()) }; + unsafe { nemo_relay_set_last_error_message(std::ptr::null()) }; assert_eq!(last_error_message(), Some("unknown callback error".into())); let invalid_utf8 = [0xffu8, 0]; unsafe { - nemo_flow_set_last_error_message(invalid_utf8.as_ptr() as *const c_char); + nemo_relay_set_last_error_message(invalid_utf8.as_ptr() as *const c_char); } assert_eq!( last_error_message(), @@ -43,7 +43,7 @@ fn test_set_last_error_message_handles_null_and_invalid_utf8() { ); let valid = CString::new("callback failed").unwrap(); - unsafe { nemo_flow_set_last_error_message(valid.as_ptr()) }; + unsafe { nemo_relay_set_last_error_message(valid.as_ptr()) }; assert_eq!(last_error_message(), Some("callback failed".into())); } @@ -52,29 +52,32 @@ fn test_status_from_error_maps_variants_and_sets_message() { let cases = [ ( FlowError::AlreadyExists("dup".into()), - NemoFlowStatus::AlreadyExists, + NemoRelayStatus::AlreadyExists, ), ( FlowError::NotFound("missing".into()), - NemoFlowStatus::NotFound, + NemoRelayStatus::NotFound, ), ( FlowError::InvalidArgument("bad arg".into()), - NemoFlowStatus::InvalidArg, + NemoRelayStatus::InvalidArg, ), ( FlowError::GuardrailRejected("blocked".into()), - NemoFlowStatus::GuardrailRejected, + NemoRelayStatus::GuardrailRejected, ), - (FlowError::Internal("boom".into()), NemoFlowStatus::Internal), - (FlowError::ScopeStackEmpty, NemoFlowStatus::ScopeStackEmpty), + ( + FlowError::Internal("boom".into()), + NemoRelayStatus::Internal, + ), + (FlowError::ScopeStackEmpty, NemoRelayStatus::ScopeStackEmpty), ]; for (error, expected_status) in cases { clear_last_error(); let status = status_from_error(&error); assert_eq!(status, expected_status); - assert_eq!(NemoFlowStatus::from(&error), expected_status); + assert_eq!(NemoRelayStatus::from(&error), expected_status); assert!(last_error_message().unwrap().contains(&error.to_string())); } } @@ -85,27 +88,27 @@ fn test_status_from_plugin_error_maps_variants_and_sets_message() { let cases = [ ( PluginError::NotFound("missing plugin".into()), - NemoFlowStatus::NotFound, + NemoRelayStatus::NotFound, "missing plugin", ), ( PluginError::InvalidConfig("bad config".into()), - NemoFlowStatus::InvalidArg, + NemoRelayStatus::InvalidArg, "bad config", ), ( PluginError::Serialization(serialization_error), - NemoFlowStatus::InvalidArg, + NemoRelayStatus::InvalidArg, "serialization error", ), ( PluginError::Internal("plugin blew up".into()), - NemoFlowStatus::Internal, + NemoRelayStatus::Internal, "plugin blew up", ), ( PluginError::RegistrationFailed("register failed".into()), - NemoFlowStatus::Internal, + NemoRelayStatus::Internal, "register failed", ), ]; diff --git a/crates/ffi/tests/integration/api/coverage_sweeps_tests.rs b/crates/ffi/tests/integration/api/coverage_sweeps_tests.rs index fba320312..ebc1dadaf 100644 --- a/crates/ffi/tests/integration/api/coverage_sweeps_tests.rs +++ b/crates/ffi/tests/integration/api/coverage_sweeps_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for coverage sweeps in the NeMo Flow FFI crate. +//! Integration tests for coverage sweeps in the NeMo Relay FFI crate. use super::*; use std::ptr; @@ -14,7 +14,7 @@ fn test_ffi_scope_and_event_remaining_error_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let scope_name = cstring("ffi_child_scope_with_parent"); let data = cstring(r#"{"scope":"child"}"#); @@ -25,9 +25,9 @@ fn test_ffi_scope_and_event_remaining_error_paths() { let mut child = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 3, data.as_ptr(), @@ -35,13 +35,13 @@ fn test_ffi_scope_and_event_remaining_error_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_scope_handle_parent_uuid(child)).is_some()); + assert!(take_string(nemo_relay_scope_handle_parent_uuid(child)).is_some()); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( invalid, - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, ptr::null(), @@ -49,12 +49,12 @@ fn test_ffi_scope_and_event_remaining_error_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, invalid_json.as_ptr(), @@ -62,12 +62,12 @@ fn test_ffi_scope_and_event_remaining_error_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, ptr::null(), @@ -75,55 +75,58 @@ fn test_ffi_scope_and_event_remaining_error_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); let event_name = cstring("ffi_event_with_parent"); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, data.as_ptr(), metadata.as_ptr() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_event(invalid, parent, ptr::null(), ptr::null()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_event(invalid, parent, ptr::null(), ptr::null()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, invalid_json.as_ptr(), ptr::null() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, ptr::null(), invalid_json.as_ptr() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_pop_scope(ptr::null(), ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_pop_scope(ptr::null(), ptr::null()), + NemoRelayStatus::NullPointer ); - assert_eq!(nemo_flow_pop_scope(child, ptr::null()), NemoFlowStatus::Ok); assert_eq!( - nemo_flow_pop_scope(child, ptr::null()), - NemoFlowStatus::NotFound + nemo_relay_pop_scope(child, ptr::null()), + NemoRelayStatus::Ok + ); + assert_eq!( + nemo_relay_pop_scope(child, ptr::null()), + NemoRelayStatus::NotFound ); - nemo_flow_scope_handle_free(child); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_handle_free(child); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -135,7 +138,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let tool_name = cstring("ffi_tool_call_utf8"); let tool_args = cstring(r#"{"value":1}"#); @@ -149,7 +152,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { let mut tool_handle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), parent, @@ -159,11 +162,11 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { tool_call_id.as_ptr(), &mut tool_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_tool_handle_parent_uuid(tool_handle)).is_some()); + assert!(take_string(nemo_relay_tool_handle_parent_uuid(tool_handle)).is_some()); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( invalid, tool_args.as_ptr(), parent, @@ -173,10 +176,10 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { ptr::null(), &mut tool_handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), parent, @@ -186,25 +189,25 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { invalid, &mut tool_handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_tool_call_end( + nemo_relay_tool_call_end( tool_handle, tool_result.as_ptr(), ptr::null(), invalid_json.as_ptr(), ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call_end( + nemo_relay_tool_call_end( tool_handle, tool_result.as_ptr(), tool_data.as_ptr(), tool_metadata.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_name = cstring("ffi_llm_call_utf8"); @@ -219,7 +222,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { let mut llm_handle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), request.as_ptr(), parent, @@ -229,11 +232,11 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { model_name.as_ptr(), &mut llm_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_llm_handle_parent_uuid(llm_handle)).is_some()); + assert!(take_string(nemo_relay_llm_handle_parent_uuid(llm_handle)).is_some()); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( invalid, request.as_ptr(), parent, @@ -243,10 +246,10 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), request.as_ptr(), parent, @@ -256,30 +259,30 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { invalid, &mut llm_handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call_end( + nemo_relay_llm_call_end( llm_handle, response.as_ptr(), ptr::null(), invalid_json.as_ptr(), ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_end( + nemo_relay_llm_call_end( llm_handle, response.as_ptr(), data.as_ptr(), metadata.as_ptr() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( llm_name.as_ptr(), invalid_shape.as_ptr(), llm_exec_cb, @@ -297,7 +300,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { ptr::null(), &mut out, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -307,7 +310,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { let mut stream = ptr::null_mut(); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( llm_name.as_ptr(), invalid_shape.as_ptr(), llm_exec_cb, @@ -327,7 +330,7 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -335,10 +338,10 @@ fn test_ffi_tool_and_llm_parent_utf8_and_shape_paths() { .contains("failed to parse native_json as LlmRequest") ); - nemo_flow_tool_handle_free(tool_handle); - nemo_flow_llm_handle_free(llm_handle); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_tool_handle_free(tool_handle); + nemo_relay_llm_handle_free(llm_handle); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -352,49 +355,49 @@ fn test_ffi_global_registry_invalid_utf8_name_sweep() { unsafe { assert_eq!( - nemo_flow_register_tool_sanitize_request_guardrail( + nemo_relay_register_tool_sanitize_request_guardrail( invalid, 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_sanitize_request_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_sanitize_response_guardrail( + nemo_relay_register_tool_sanitize_response_guardrail( invalid, 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_sanitize_response_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_sanitize_response_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_conditional_execution_guardrail( + nemo_relay_register_tool_conditional_execution_guardrail( invalid, 1, tool_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_conditional_execution_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_request_intercept( + nemo_relay_register_tool_request_intercept( invalid, 1, false, @@ -402,71 +405,71 @@ fn test_ffi_global_registry_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_request_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_request_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_execution_intercept( + nemo_relay_register_tool_execution_intercept( invalid, 1, tool_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_sanitize_request_guardrail( + nemo_relay_register_llm_sanitize_request_guardrail( invalid, 1, llm_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_sanitize_request_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_sanitize_request_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_sanitize_response_guardrail( + nemo_relay_register_llm_sanitize_response_guardrail( invalid, 1, llm_response_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_sanitize_response_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_sanitize_response_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_conditional_execution_guardrail( + nemo_relay_register_llm_conditional_execution_guardrail( invalid, 1, llm_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_conditional_execution_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( invalid, 1, false, @@ -474,47 +477,47 @@ fn test_ffi_global_registry_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_request_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_execution_intercept( + nemo_relay_register_llm_execution_intercept( invalid, 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_stream_execution_intercept( + nemo_relay_register_llm_stream_execution_intercept( invalid, 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_stream_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_stream_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_subscriber(invalid, subscriber_cb, ptr::null_mut(), None), - NemoFlowStatus::InvalidUtf8 + nemo_relay_register_subscriber(invalid, subscriber_cb, ptr::null_mut(), None), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_subscriber(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_subscriber(invalid), + NemoRelayStatus::InvalidUtf8 ); } } @@ -532,9 +535,9 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { let scope_name = cstring("scope-registry-invalid"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -542,14 +545,14 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let invalid_name = invalid_utf8.as_ptr() as *const c_char; let valid_name = cstring("scope-registry-valid-name"); assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( invalid_scope, valid_name.as_ptr(), 1, @@ -557,17 +560,17 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( invalid_scope, valid_name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid_name, 1, @@ -575,18 +578,18 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid_name ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( invalid_scope, valid_name.as_ptr(), 1, @@ -594,14 +597,17 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept(invalid_scope, valid_name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_execution_intercept( + invalid_scope, + valid_name.as_ptr() + ), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( scope_uuid.as_ptr(), invalid_name, 1, @@ -609,15 +615,15 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept(scope_uuid.as_ptr(), invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_execution_intercept(scope_uuid.as_ptr(), invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( invalid_scope, valid_name.as_ptr(), 1, @@ -625,17 +631,17 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( invalid_scope, valid_name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid_name, 1, @@ -643,18 +649,18 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid_name ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( invalid_scope, valid_name.as_ptr(), 1, @@ -662,14 +668,14 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept(invalid_scope, valid_name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_execution_intercept(invalid_scope, valid_name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( scope_uuid.as_ptr(), invalid_name, 1, @@ -677,44 +683,47 @@ fn test_ffi_scope_registry_invalid_utf8_scope_and_name_sweeps() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept(scope_uuid.as_ptr(), invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_execution_intercept(scope_uuid.as_ptr(), invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( invalid_scope, valid_name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_subscriber(invalid_scope, valid_name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_subscriber(invalid_scope, valid_name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( scope_uuid.as_ptr(), invalid_name, subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid_name), + NemoRelayStatus::InvalidUtf8 ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/integration/api_tests.rs b/crates/ffi/tests/integration/api_tests.rs index 0a5afbb4f..1eb04f77d 100644 --- a/crates/ffi/tests/integration/api_tests.rs +++ b/crates/ffi/tests/integration/api_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for the NeMo Flow FFI API surface. +//! Integration tests for the NeMo Relay FFI API surface. use super::*; use std::ffi::{CStr, CString}; @@ -10,31 +10,31 @@ use std::ptr; use std::sync::{Mutex, OnceLock}; use std::time::{SystemTime, UNIX_EPOCH}; -use nemo_flow::plugin::PluginRegistrationContext; +use nemo_relay::plugin::PluginRegistrationContext; use serde_json::{Value as Json, json}; use uuid::Uuid; -use nemo_flow_ffi::callable::{NemoFlowLlmExecNextFn, NemoFlowToolExecNextFn}; -use nemo_flow_ffi::convert::nemo_flow_string_free; -use nemo_flow_ffi::error::{NemoFlowStatus, nemo_flow_last_error, set_last_error}; -use nemo_flow_ffi::types::{ +use nemo_relay_ffi::callable::{NemoRelayLlmExecNextFn, NemoRelayToolExecNextFn}; +use nemo_relay_ffi::convert::nemo_relay_string_free; +use nemo_relay_ffi::error::{NemoRelayStatus, nemo_relay_last_error, set_last_error}; +use nemo_relay_ffi::types::{ FfiAtifExporter, FfiAtofExporter, FfiEvent, FfiLLMHandle, FfiLLMRequest, - FfiOpenTelemetrySubscriber, FfiScopeStack, FfiToolHandle, nemo_flow_atif_exporter_free, - nemo_flow_atof_exporter_free, nemo_flow_event_data, nemo_flow_event_input, - nemo_flow_event_metadata, nemo_flow_event_model_name, nemo_flow_event_name, - nemo_flow_event_output, nemo_flow_event_parent_uuid, nemo_flow_event_scope_type, - nemo_flow_event_timestamp, nemo_flow_event_tool_call_id, nemo_flow_event_uuid, - nemo_flow_llm_handle_attributes, nemo_flow_llm_handle_free, nemo_flow_llm_handle_name, - nemo_flow_llm_handle_parent_uuid, nemo_flow_llm_handle_uuid, nemo_flow_llm_request_content, - nemo_flow_llm_request_free, nemo_flow_llm_request_headers, nemo_flow_llm_request_new, - nemo_flow_otel_subscriber_free, nemo_flow_scope_handle_attributes, nemo_flow_scope_handle_data, - nemo_flow_scope_handle_free, nemo_flow_scope_handle_metadata, nemo_flow_scope_handle_name, - nemo_flow_scope_handle_parent_uuid, nemo_flow_scope_handle_scope_type, - nemo_flow_scope_handle_uuid, nemo_flow_scope_stack_free, nemo_flow_tool_handle_attributes, - nemo_flow_tool_handle_free, nemo_flow_tool_handle_name, nemo_flow_tool_handle_parent_uuid, - nemo_flow_tool_handle_uuid, + FfiOpenTelemetrySubscriber, FfiScopeStack, FfiToolHandle, nemo_relay_atif_exporter_free, + nemo_relay_atof_exporter_free, nemo_relay_event_data, nemo_relay_event_input, + nemo_relay_event_metadata, nemo_relay_event_model_name, nemo_relay_event_name, + nemo_relay_event_output, nemo_relay_event_parent_uuid, nemo_relay_event_scope_type, + nemo_relay_event_timestamp, nemo_relay_event_tool_call_id, nemo_relay_event_uuid, + nemo_relay_llm_handle_attributes, nemo_relay_llm_handle_free, nemo_relay_llm_handle_name, + nemo_relay_llm_handle_parent_uuid, nemo_relay_llm_handle_uuid, nemo_relay_llm_request_content, + nemo_relay_llm_request_free, nemo_relay_llm_request_headers, nemo_relay_llm_request_new, + nemo_relay_otel_subscriber_free, nemo_relay_scope_handle_attributes, + nemo_relay_scope_handle_data, nemo_relay_scope_handle_free, nemo_relay_scope_handle_metadata, + nemo_relay_scope_handle_name, nemo_relay_scope_handle_parent_uuid, + nemo_relay_scope_handle_scope_type, nemo_relay_scope_handle_uuid, nemo_relay_scope_stack_free, + nemo_relay_tool_handle_attributes, nemo_relay_tool_handle_free, nemo_relay_tool_handle_name, + nemo_relay_tool_handle_parent_uuid, nemo_relay_tool_handle_uuid, }; -use nemo_flow_ffi::{api, callable, types}; +use nemo_relay_ffi::{api, callable, types}; static TEST_MUTEX: Mutex<()> = Mutex::new(()); static EVENT_LOG: OnceLock>> = OnceLock::new(); @@ -75,24 +75,24 @@ fn temp_dir(prefix: &str) -> std::path::PathBuf { .duration_since(UNIX_EPOCH) .unwrap() .as_nanos(); - let path = std::env::temp_dir().join(format!("nemo-flow-{prefix}-{id}")); + let path = std::env::temp_dir().join(format!("nemo-relay-{prefix}-{id}")); fs::create_dir_all(&path).unwrap(); path } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_push_scope( +unsafe fn nemo_relay_push_scope( name: *const c_char, - scope_type: NemoFlowScopeType, + scope_type: NemoRelayScopeType, parent: *const FfiScopeHandle, attributes: u32, data_json: *const c_char, metadata_json: *const c_char, input_json: *const c_char, out: *mut *mut FfiScopeHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_push_scope( + api::nemo_relay_push_scope( name, scope_type, parent, @@ -106,24 +106,24 @@ unsafe fn nemo_flow_push_scope( } } -unsafe fn nemo_flow_pop_scope( +unsafe fn nemo_relay_pop_scope( handle: *const FfiScopeHandle, output_json: *const c_char, -) -> NemoFlowStatus { - unsafe { api::nemo_flow_pop_scope(handle, output_json, ptr::null()) } +) -> NemoRelayStatus { + unsafe { api::nemo_relay_pop_scope(handle, output_json, ptr::null()) } } -unsafe fn nemo_flow_event( +unsafe fn nemo_relay_event( name: *const c_char, parent: *const FfiScopeHandle, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { - unsafe { api::nemo_flow_event(name, parent, data_json, metadata_json, ptr::null()) } +) -> NemoRelayStatus { + unsafe { api::nemo_relay_event(name, parent, data_json, metadata_json, ptr::null()) } } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_tool_call( +unsafe fn nemo_relay_tool_call( name: *const c_char, args_json: *const c_char, parent: *const FfiScopeHandle, @@ -132,9 +132,9 @@ unsafe fn nemo_flow_tool_call( metadata_json: *const c_char, tool_call_id: *const c_char, out: *mut *mut FfiToolHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_tool_call( + api::nemo_relay_tool_call( name, args_json, parent, @@ -148,19 +148,19 @@ unsafe fn nemo_flow_tool_call( } } -unsafe fn nemo_flow_tool_call_end( +unsafe fn nemo_relay_tool_call_end( handle: *const FfiToolHandle, result_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_tool_call_end(handle, result_json, data_json, metadata_json, ptr::null()) + api::nemo_relay_tool_call_end(handle, result_json, data_json, metadata_json, ptr::null()) } } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_llm_call( +unsafe fn nemo_relay_llm_call( name: *const c_char, native_json: *const c_char, parent: *const FfiScopeHandle, @@ -169,9 +169,9 @@ unsafe fn nemo_flow_llm_call( metadata_json: *const c_char, model_name: *const c_char, out: *mut *mut FfiLLMHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_llm_call( + api::nemo_relay_llm_call( name, native_json, parent, @@ -185,14 +185,14 @@ unsafe fn nemo_flow_llm_call( } } -unsafe fn nemo_flow_llm_call_end( +unsafe fn nemo_relay_llm_call_end( handle: *const FfiLLMHandle, response_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_llm_call_end(handle, response_json, data_json, metadata_json, ptr::null()) + api::nemo_relay_llm_call_end(handle, response_json, data_json, metadata_json, ptr::null()) } } @@ -203,12 +203,12 @@ unsafe fn take_string(ptr: *mut c_char) -> Option { let s = unsafe { CStr::from_ptr(ptr) } .to_string_lossy() .into_owned(); - unsafe { nemo_flow_string_free(ptr) }; + unsafe { nemo_relay_string_free(ptr) }; Some(s) } unsafe fn read_last_error() -> Option { - let ptr = nemo_flow_last_error(); + let ptr = nemo_relay_last_error(); if ptr.is_null() { None } else { @@ -227,13 +227,13 @@ unsafe fn returned_json(ptr: *mut c_char) -> Json { unsafe fn fresh_scope_stack() -> *mut FfiScopeStack { let mut stack = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_scope_stack_create(&mut stack) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_scope_stack_create(&mut stack) }, + NemoRelayStatus::Ok ); assert!(!stack.is_null()); assert_eq!( - unsafe { nemo_flow_scope_stack_set_thread(stack) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_scope_stack_set_thread(stack) }, + NemoRelayStatus::Ok ); stack } @@ -247,24 +247,24 @@ fn reset_globals() { unsafe extern "C" fn subscriber_cb(_user_data: *mut libc::c_void, event: *const FfiEvent) { let payload = json!({ - "uuid": unsafe { take_string(nemo_flow_event_uuid(event)) }.unwrap_or_default(), - "name": unsafe { take_string(nemo_flow_event_name(event)) }.unwrap_or_default(), - "kind": unsafe { take_string(nemo_flow_ffi::types::nemo_flow_event_kind(event)) }.unwrap_or_default(), - "json": unsafe { take_string(nemo_flow_ffi::types::nemo_flow_event_json(event)) } + "uuid": unsafe { take_string(nemo_relay_event_uuid(event)) }.unwrap_or_default(), + "name": unsafe { take_string(nemo_relay_event_name(event)) }.unwrap_or_default(), + "kind": unsafe { take_string(nemo_relay_ffi::types::nemo_relay_event_kind(event)) }.unwrap_or_default(), + "json": unsafe { take_string(nemo_relay_ffi::types::nemo_relay_event_json(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "data": unsafe { take_string(nemo_flow_event_data(event)) } + "data": unsafe { take_string(nemo_relay_event_data(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "metadata": unsafe { take_string(nemo_flow_event_metadata(event)) } + "metadata": unsafe { take_string(nemo_relay_event_metadata(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "timestamp": unsafe { take_string(nemo_flow_event_timestamp(event)) }.unwrap_or_default(), - "input": unsafe { take_string(nemo_flow_event_input(event)) } + "timestamp": unsafe { take_string(nemo_relay_event_timestamp(event)) }.unwrap_or_default(), + "input": unsafe { take_string(nemo_relay_event_input(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "output": unsafe { take_string(nemo_flow_event_output(event)) } + "output": unsafe { take_string(nemo_relay_event_output(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "model_name": unsafe { take_string(nemo_flow_event_model_name(event)) }, - "tool_call_id": unsafe { take_string(nemo_flow_event_tool_call_id(event)) }, - "parent_uuid": unsafe { take_string(nemo_flow_event_parent_uuid(event)) }, - "scope_type": unsafe { take_string(nemo_flow_event_scope_type(event)) }, + "model_name": unsafe { take_string(nemo_relay_event_model_name(event)) }, + "tool_call_id": unsafe { take_string(nemo_relay_event_tool_call_id(event)) }, + "parent_uuid": unsafe { take_string(nemo_relay_event_parent_uuid(event)) }, + "scope_type": unsafe { take_string(nemo_relay_event_scope_type(event)) }, }); lock_unpoisoned(event_log()).push(payload); } @@ -325,7 +325,7 @@ unsafe extern "C" fn tool_exec_fail_cb( unsafe extern "C" fn tool_exec_intercept_cb( _user_data: *mut libc::c_void, args_json: *const c_char, - next_fn: NemoFlowToolExecNextFn, + next_fn: NemoRelayToolExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(args_json, next_ctx) } @@ -379,9 +379,9 @@ unsafe extern "C" fn llm_request_intercept_cb( _annotated_json: *const c_char, out_request: *mut *mut FfiLLMRequest, _out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { *out_request = llm_request_cb(ptr::null_mut(), request) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } unsafe extern "C" fn llm_exec_cb( @@ -511,7 +511,7 @@ unsafe extern "C" fn codec_encode_cb( unsafe extern "C" fn llm_exec_intercept_cb( _user_data: *mut libc::c_void, native_json: *const c_char, - next_fn: NemoFlowLlmExecNextFn, + next_fn: NemoRelayLlmExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(native_json, next_ctx) } @@ -576,10 +576,10 @@ unsafe extern "C" fn plugin_register_subscriber( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { +) -> NemoRelayStatus { let name = CString::new("subscriber").unwrap(); unsafe { - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( ctx, name.as_ptr(), subscriber_cb, @@ -593,17 +593,17 @@ unsafe extern "C" fn plugin_register_fail( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, _ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { - NemoFlowStatus::Internal +) -> NemoRelayStatus { + NemoRelayStatus::Internal } unsafe extern "C" fn plugin_register_fail_with_last_error( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, _ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { +) -> NemoRelayStatus { set_last_error("plugin register callback set last error explicitly"); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } #[path = "../unit/api/core_tests.rs"] @@ -621,15 +621,15 @@ mod registry_tests; fn scope_stack_api_round_trip() { let mut stack: *mut FfiScopeStack = ptr::null_mut(); - let create_status = unsafe { nemo_flow_scope_stack_create(&mut stack) }; - assert_eq!(create_status, NemoFlowStatus::Ok); + let create_status = unsafe { nemo_relay_scope_stack_create(&mut stack) }; + assert_eq!(create_status, NemoRelayStatus::Ok); assert!(!stack.is_null()); - let bind_status = unsafe { nemo_flow_scope_stack_set_thread(stack) }; - assert_eq!(bind_status, NemoFlowStatus::Ok); - assert!(nemo_flow_scope_stack_active()); + let bind_status = unsafe { nemo_relay_scope_stack_set_thread(stack) }; + assert_eq!(bind_status, NemoRelayStatus::Ok); + assert!(nemo_relay_scope_stack_active()); - unsafe { nemo_flow_scope_stack_free(stack) }; + unsafe { nemo_relay_scope_stack_free(stack) }; } #[test] @@ -637,11 +637,11 @@ fn llm_request_accessors_round_trip() { let headers = cstring(r#"{"x-trace":"1"}"#); let content = cstring(r#"{"model":"test-model","messages":[]}"#); - let request = unsafe { nemo_flow_llm_request_new(headers.as_ptr(), content.as_ptr()) }; + let request = unsafe { nemo_relay_llm_request_new(headers.as_ptr(), content.as_ptr()) }; assert!(!request.is_null()); - let headers_json = unsafe { take_string(nemo_flow_llm_request_headers(request)) }.unwrap(); - let content_json = unsafe { take_string(nemo_flow_llm_request_content(request)) }.unwrap(); + let headers_json = unsafe { take_string(nemo_relay_llm_request_headers(request)) }.unwrap(); + let content_json = unsafe { take_string(nemo_relay_llm_request_content(request)) }.unwrap(); assert_eq!( serde_json::from_str::(&headers_json).unwrap(), @@ -652,15 +652,15 @@ fn llm_request_accessors_round_trip() { json!({"model": "test-model", "messages": []}) ); - unsafe { nemo_flow_llm_request_free(request) }; + unsafe { nemo_relay_llm_request_free(request) }; } #[test] fn scope_stack_create_reports_null_pointer_errors() { - let status = unsafe { nemo_flow_scope_stack_create(ptr::null_mut()) }; - assert_eq!(status, NemoFlowStatus::NullPointer); + let status = unsafe { nemo_relay_scope_stack_create(ptr::null_mut()) }; + assert_eq!(status, NemoRelayStatus::NullPointer); - let message = unsafe { CStr::from_ptr(nemo_flow_last_error()) } + let message = unsafe { CStr::from_ptr(nemo_relay_last_error()) } .to_string_lossy() .into_owned(); assert!(message.contains("out pointer is null")); @@ -678,29 +678,29 @@ fn atof_exporter_writes_raw_jsonl_events() { assert_eq!( unsafe { - api::nemo_flow_atof_exporter_create( + api::nemo_relay_atof_exporter_create( output_directory.as_ptr(), mode.as_ptr(), filename.as_ptr(), &mut exporter, ) }, - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert!(!exporter.is_null()); let mut path_ptr = ptr::null_mut(); assert_eq!( - unsafe { api::nemo_flow_atof_exporter_path(exporter, &mut path_ptr) }, - NemoFlowStatus::Ok + unsafe { api::nemo_relay_atof_exporter_path(exporter, &mut path_ptr) }, + NemoRelayStatus::Ok ); let path = unsafe { take_string(path_ptr) }.unwrap(); assert!(path.ends_with("events.jsonl")); let subscriber_name = cstring("ffi_atof_exporter"); assert_eq!( - unsafe { api::nemo_flow_atof_exporter_register(exporter, subscriber_name.as_ptr()) }, - NemoFlowStatus::Ok + unsafe { api::nemo_relay_atof_exporter_register(exporter, subscriber_name.as_ptr()) }, + NemoRelayStatus::Ok ); let scope_name = cstring("ffi_atof_scope"); @@ -708,9 +708,9 @@ fn atof_exporter_writes_raw_jsonl_events() { let mut scope = ptr::null_mut(); assert_eq!( unsafe { - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -719,34 +719,34 @@ fn atof_exporter_writes_raw_jsonl_events() { &mut scope, ) }, - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let event_name = cstring("ffi_atof_mark"); let event_data = cstring(r#"{"step":1}"#); assert_eq!( - unsafe { nemo_flow_event(event_name.as_ptr(), scope, event_data.as_ptr(), ptr::null()) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_event(event_name.as_ptr(), scope, event_data.as_ptr(), ptr::null()) }, + NemoRelayStatus::Ok ); let output = cstring(r#"{"done":true}"#); assert_eq!( - unsafe { nemo_flow_pop_scope(scope, output.as_ptr()) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_pop_scope(scope, output.as_ptr()) }, + NemoRelayStatus::Ok ); - unsafe { nemo_flow_scope_handle_free(scope) }; + unsafe { nemo_relay_scope_handle_free(scope) }; assert_eq!( - unsafe { api::nemo_flow_atof_exporter_deregister(subscriber_name.as_ptr()) }, - NemoFlowStatus::Ok + unsafe { api::nemo_relay_atof_exporter_deregister(subscriber_name.as_ptr()) }, + NemoRelayStatus::Ok ); assert_eq!( - unsafe { api::nemo_flow_atof_exporter_force_flush(exporter) }, - NemoFlowStatus::Ok + unsafe { api::nemo_relay_atof_exporter_force_flush(exporter) }, + NemoRelayStatus::Ok ); assert_eq!( - unsafe { api::nemo_flow_atof_exporter_shutdown(exporter) }, - NemoFlowStatus::Ok + unsafe { api::nemo_relay_atof_exporter_shutdown(exporter) }, + NemoRelayStatus::Ok ); let records = fs::read_to_string(&path) @@ -760,7 +760,7 @@ fn atof_exporter_writes_raw_jsonl_events() { assert_eq!(records[2]["scope_category"], "end"); unsafe { - nemo_flow_atof_exporter_free(exporter); - nemo_flow_scope_stack_free(stack); + nemo_relay_atof_exporter_free(exporter); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/integration/callable_extra_tests.rs b/crates/ffi/tests/integration/callable_extra_tests.rs index 7541b81e9..0401abe2b 100644 --- a/crates/ffi/tests/integration/callable_extra_tests.rs +++ b/crates/ffi/tests/integration/callable_extra_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for callable extra in the NeMo Flow FFI crate. +//! Integration tests for callable extra in the NeMo Relay FFI crate. use super::*; use std::ptr; @@ -20,7 +20,7 @@ unsafe extern "C" fn tool_conditional_error_cb( unsafe extern "C" fn tool_exec_intercept_null_next_cb( _user_data: *mut libc::c_void, _args_json: *const c_char, - next_fn: NemoFlowToolExecNextFn, + next_fn: NemoRelayToolExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(ptr::null(), next_ctx) } @@ -29,7 +29,7 @@ unsafe extern "C" fn tool_exec_intercept_null_next_cb( unsafe extern "C" fn llm_exec_intercept_null_next_cb( _user_data: *mut libc::c_void, _native_json: *const c_char, - next_fn: NemoFlowLlmExecNextFn, + next_fn: NemoRelayLlmExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(ptr::null(), next_ctx) } @@ -42,8 +42,8 @@ unsafe extern "C" fn llm_request_intercept_status_error_cb( _annotated_json: *const c_char, _out_request: *mut *mut FfiLLMRequest, _out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { - NemoFlowStatus::Internal +) -> NemoRelayStatus { + NemoRelayStatus::Internal } unsafe extern "C" fn llm_request_intercept_null_out_request_cb( @@ -53,8 +53,8 @@ unsafe extern "C" fn llm_request_intercept_null_out_request_cb( _annotated_json: *const c_char, _out_request: *mut *mut FfiLLMRequest, _out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { - NemoFlowStatus::Ok +) -> NemoRelayStatus { + NemoRelayStatus::Ok } unsafe extern "C" fn llm_request_intercept_invalid_annotated_cb( @@ -64,12 +64,12 @@ unsafe extern "C" fn llm_request_intercept_invalid_annotated_cb( _annotated_json: *const c_char, out_request: *mut *mut FfiLLMRequest, out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { *out_request = Box::into_raw(Box::new(FfiLLMRequest((&*request).0.clone()))); *out_annotated_json = CString::new("not-json").unwrap().into_raw(); } - NemoFlowStatus::Ok + NemoRelayStatus::Ok } unsafe extern "C" fn llm_request_passthrough_cb( diff --git a/crates/ffi/tests/integration/main.rs b/crates/ffi/tests/integration/main.rs index 4911b2234..04e80d2d4 100644 --- a/crates/ffi/tests/integration/main.rs +++ b/crates/ffi/tests/integration/main.rs @@ -1,30 +1,30 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration test support for the NeMo Flow FFI crate. +//! Integration test support for the NeMo Relay FFI crate. use libc::c_char; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::scope::{ScopeAttributes, ScopeHandle, ScopeType}; -use nemo_flow::api::tool::{ToolAttributes, ToolHandle}; -use nemo_flow::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; -use nemo_flow::error::{FlowError, Result}; -use nemo_flow_ffi::api::*; -use nemo_flow_ffi::callable::*; -use nemo_flow_ffi::convert::*; -use nemo_flow_ffi::error::*; -use nemo_flow_ffi::types::*; -use nemo_flow_ffi::{api, convert, error}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::scope::{ScopeAttributes, ScopeHandle, ScopeType}; +use nemo_relay::api::tool::{ToolAttributes, ToolHandle}; +use nemo_relay::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; +use nemo_relay::error::{FlowError, Result}; +use nemo_relay_ffi::api::*; +use nemo_relay_ffi::callable::*; +use nemo_relay_ffi::convert::*; +use nemo_relay_ffi::error::*; +use nemo_relay_ffi::types::*; +use nemo_relay_ffi::{api, convert, error}; use serde_json::{Value as Json, json}; use std::ffi::{CStr, CString}; use std::pin::Pin; use std::sync::Arc; use tokio_stream::Stream; -unsafe fn nemo_flow_string_free_internal(ptr: *mut c_char) { - unsafe { nemo_flow_string_free(ptr) }; +unsafe fn nemo_relay_string_free_internal(ptr: *mut c_char) { + unsafe { nemo_relay_string_free(ptr) }; } mod api_tests; diff --git a/crates/ffi/tests/unit/api/core_tests.rs b/crates/ffi/tests/unit/api/core_tests.rs index c399dd93f..630deab62 100644 --- a/crates/ffi/tests/unit/api/core_tests.rs +++ b/crates/ffi/tests/unit/api/core_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for core in the NeMo Flow FFI crate. +//! Unit tests for core in the NeMo Relay FFI crate. use super::*; @@ -9,7 +9,7 @@ use super::*; fn test_ffi_plugin_config_validate_initialize_and_clear() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let config = cstring( &json!({ @@ -40,16 +40,16 @@ fn test_ffi_plugin_config_validate_initialize_and_clear() { let mut report_json = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_validate_plugin_config(config.as_ptr(), &mut report_json) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_validate_plugin_config(config.as_ptr(), &mut report_json) }, + NemoRelayStatus::Ok ); let report = unsafe { returned_json(report_json) }; assert_eq!(report["diagnostics"], json!([])); let mut kinds_json = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_list_plugin_kinds_json(&mut kinds_json) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_list_plugin_kinds_json(&mut kinds_json) }, + NemoRelayStatus::Ok ); let kinds = unsafe { returned_json(kinds_json) }; assert!( @@ -65,26 +65,26 @@ fn test_ffi_plugin_config_validate_initialize_and_clear() { let mut configured_json = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_initialize_plugins(config.as_ptr(), &mut configured_json) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_initialize_plugins(config.as_ptr(), &mut configured_json) }, + NemoRelayStatus::Ok ); let configured_report = unsafe { returned_json(configured_json) }; assert_eq!(configured_report["diagnostics"], json!([])); let mut active_json = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_active_plugin_report_json(&mut active_json) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_active_plugin_report_json(&mut active_json) }, + NemoRelayStatus::Ok ); let active_report = unsafe { returned_json(active_json) }; assert_eq!(active_report["diagnostics"], json!([])); - assert_eq!(nemo_flow_clear_plugin_configuration(), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_clear_plugin_configuration(), NemoRelayStatus::Ok); let mut cleared_json = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_active_plugin_report_json(&mut cleared_json) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_active_plugin_report_json(&mut cleared_json) }, + NemoRelayStatus::Ok ); assert_eq!(unsafe { returned_json(cleared_json) }, Json::Null); } @@ -93,7 +93,7 @@ fn test_ffi_plugin_config_validate_initialize_and_clear() { fn test_ffi_observability_plugin_file_sinks() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let dir = std::env::temp_dir().join(unique_name("ffi_observability_plugin")); std::fs::create_dir_all(&dir).unwrap(); let dir_text = dir.to_string_lossy().into_owned(); @@ -132,19 +132,19 @@ fn test_ffi_observability_plugin_file_sinks() { unsafe { assert_eq!( - take_string(nemo_flow_observability_plugin_kind()).unwrap(), + take_string(nemo_relay_observability_plugin_kind()).unwrap(), "observability" ); let mut default_config_json = ptr::null_mut(); assert_eq!( - nemo_flow_observability_default_config_json(&mut default_config_json), - NemoFlowStatus::Ok + nemo_relay_observability_default_config_json(&mut default_config_json), + NemoRelayStatus::Ok ); assert_eq!(returned_json(default_config_json)["version"], json!(1)); let mut component_json = ptr::null_mut(); assert_eq!( - nemo_flow_observability_component_spec_json(ptr::null(), true, &mut component_json), - NemoFlowStatus::Ok + nemo_relay_observability_component_spec_json(ptr::null(), true, &mut component_json), + NemoRelayStatus::Ok ); let component = returned_json(component_json); assert_eq!(component["kind"], "observability"); @@ -152,15 +152,15 @@ fn test_ffi_observability_plugin_file_sinks() { let mut report_json = ptr::null_mut(); assert_eq!( - nemo_flow_validate_plugin_config(config.as_ptr(), &mut report_json), - NemoFlowStatus::Ok + nemo_relay_validate_plugin_config(config.as_ptr(), &mut report_json), + NemoRelayStatus::Ok ); assert_eq!(returned_json(report_json)["diagnostics"], json!([])); let mut initialized_json = ptr::null_mut(); assert_eq!( - nemo_flow_initialize_plugins(config.as_ptr(), &mut initialized_json), - NemoFlowStatus::Ok + nemo_relay_initialize_plugins(config.as_ptr(), &mut initialized_json), + NemoRelayStatus::Ok ); assert_eq!(returned_json(initialized_json)["diagnostics"], json!([])); @@ -169,9 +169,9 @@ fn test_ffi_observability_plugin_file_sinks() { let input = cstring(r#"{"agent":true}"#); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -179,20 +179,23 @@ fn test_ffi_observability_plugin_file_sinks() { input.as_ptr(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = take_string(nemo_flow_scope_handle_uuid(scope)).unwrap(); + let scope_uuid = take_string(nemo_relay_scope_handle_uuid(scope)).unwrap(); let mark_name = cstring("ffi-observability-mark"); let mark_data = cstring(r#"{"step":1}"#); assert_eq!( - nemo_flow_event(mark_name.as_ptr(), scope, mark_data.as_ptr(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_event(mark_name.as_ptr(), scope, mark_data.as_ptr(), ptr::null()), + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); - assert_eq!(nemo_flow_clear_plugin_configuration(), NemoFlowStatus::Ok); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); + assert_eq!(nemo_relay_clear_plugin_configuration(), NemoRelayStatus::Ok); let jsonl = std::fs::read_to_string(dir.join("events.jsonl")).unwrap(); assert_eq!(jsonl.trim().lines().count(), 3); @@ -215,7 +218,7 @@ fn test_ffi_observability_plugin_file_sinks() { fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let dir = std::env::temp_dir().join(unique_name("ffi_observability_plugin_multi_agent")); std::fs::create_dir_all(&dir).unwrap(); let dir_text = dir.to_string_lossy().into_owned(); @@ -244,8 +247,8 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { unsafe { let mut initialized_json = ptr::null_mut(); assert_eq!( - nemo_flow_initialize_plugins(config.as_ptr(), &mut initialized_json), - NemoFlowStatus::Ok + nemo_relay_initialize_plugins(config.as_ptr(), &mut initialized_json), + NemoRelayStatus::Ok ); assert_eq!(returned_json(initialized_json)["diagnostics"], json!([])); @@ -255,9 +258,9 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { let first_input = cstring(r#"{"agent":"first"}"#); let mut first = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( first_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -265,29 +268,29 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { first_input.as_ptr(), &mut first, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let first_uuid = take_string(nemo_flow_scope_handle_uuid(first)).unwrap(); + let first_uuid = take_string(nemo_relay_scope_handle_uuid(first)).unwrap(); let first_mark = cstring("ffi-first-mark"); let first_mark_data = cstring(r#"{"agent":"first"}"#); assert_eq!( - nemo_flow_event( + nemo_relay_event( first_mark.as_ptr(), first, first_mark_data.as_ptr(), ptr::null() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let nested_name = cstring("ffi-nested-agent"); let nested_input = cstring(r#"{"agent":"nested"}"#); let mut nested = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( nested_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -295,31 +298,37 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { nested_input.as_ptr(), &mut nested, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let nested_mark = cstring("ffi-nested-mark"); let nested_mark_data = cstring(r#"{"agent":"nested"}"#); assert_eq!( - nemo_flow_event( + nemo_relay_event( nested_mark.as_ptr(), nested, nested_mark_data.as_ptr(), ptr::null() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok + ); + assert_eq!( + nemo_relay_pop_scope(nested, ptr::null()), + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_pop_scope(nested, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(nested); - assert_eq!(nemo_flow_pop_scope(first, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(first); + nemo_relay_scope_handle_free(nested); + assert_eq!( + nemo_relay_pop_scope(first, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(first); let second_name = cstring("ffi-second-agent"); let second_input = cstring(r#"{"agent":"second"}"#); let mut second = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( second_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -327,24 +336,27 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { second_input.as_ptr(), &mut second, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let second_uuid = take_string(nemo_flow_scope_handle_uuid(second)).unwrap(); + let second_uuid = take_string(nemo_relay_scope_handle_uuid(second)).unwrap(); let second_mark = cstring("ffi-second-mark"); let second_mark_data = cstring(r#"{"agent":"second"}"#); assert_eq!( - nemo_flow_event( + nemo_relay_event( second_mark.as_ptr(), second, second_mark_data.as_ptr(), ptr::null() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_pop_scope(second, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(second); - nemo_flow_scope_stack_free(stack); - assert_eq!(nemo_flow_clear_plugin_configuration(), NemoFlowStatus::Ok); + assert_eq!( + nemo_relay_pop_scope(second, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(second); + nemo_relay_scope_stack_free(stack); + assert_eq!(nemo_relay_clear_plugin_configuration(), NemoRelayStatus::Ok); let files = std::fs::read_dir(&dir) .unwrap() @@ -375,7 +387,7 @@ fn test_ffi_observability_plugin_atif_splits_multiple_top_level_agents() { fn test_ffi_plugin_top_level_null_and_invalid_paths() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let valid_config = cstring( &json!({ @@ -389,8 +401,8 @@ fn test_ffi_plugin_top_level_null_and_invalid_paths() { unsafe { assert_eq!( - nemo_flow_validate_plugin_config(valid_config.as_ptr(), ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_validate_plugin_config(valid_config.as_ptr(), ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert!( read_last_error() @@ -400,12 +412,12 @@ fn test_ffi_plugin_top_level_null_and_invalid_paths() { let mut out_json = ptr::null_mut(); assert_eq!( - nemo_flow_validate_plugin_config(invalid_json.as_ptr(), &mut out_json), - NemoFlowStatus::InvalidJson + nemo_relay_validate_plugin_config(invalid_json.as_ptr(), &mut out_json), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_validate_plugin_config(invalid_shape.as_ptr(), &mut out_json), - NemoFlowStatus::InvalidJson + nemo_relay_validate_plugin_config(invalid_shape.as_ptr(), &mut out_json), + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -414,39 +426,39 @@ fn test_ffi_plugin_top_level_null_and_invalid_paths() { ); assert_eq!( - nemo_flow_initialize_plugins(valid_config.as_ptr(), ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_initialize_plugins(valid_config.as_ptr(), ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_initialize_plugins(invalid_json.as_ptr(), &mut out_json), - NemoFlowStatus::InvalidJson + nemo_relay_initialize_plugins(invalid_json.as_ptr(), &mut out_json), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_initialize_plugins(invalid_shape.as_ptr(), &mut out_json), - NemoFlowStatus::InvalidJson + nemo_relay_initialize_plugins(invalid_shape.as_ptr(), &mut out_json), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_active_plugin_report_json(ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_active_plugin_report_json(ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_list_plugin_kinds_json(ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_list_plugin_kinds_json(ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( ptr::null(), None, plugin_register_fail, ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_deregister_plugin(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_deregister_plugin(ptr::null()), + NemoRelayStatus::NullPointer ); } } @@ -458,8 +470,8 @@ fn test_ffi_error_paths_and_scope_stack() { unsafe { assert_eq!( - nemo_flow_get_handle(ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_get_handle(ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert!(read_last_error().unwrap().contains("out pointer is null")); @@ -467,9 +479,9 @@ fn test_ffi_error_paths_and_scope_stack() { let invalid_json = cstring("{"); let mut handle = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, invalid_json.as_ptr(), @@ -477,31 +489,31 @@ fn test_ffi_error_paths_and_scope_stack() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); let stack = fresh_scope_stack(); - assert!(nemo_flow_scope_stack_active()); + assert!(nemo_relay_scope_stack_active()); let mut root = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut root), NemoFlowStatus::Ok); - let root_uuid = take_string(nemo_flow_scope_handle_uuid(root)).unwrap(); + assert_eq!(nemo_relay_get_handle(&mut root), NemoRelayStatus::Ok); + let root_uuid = take_string(nemo_relay_scope_handle_uuid(root)).unwrap(); assert!(!root_uuid.is_empty()); assert_eq!( - nemo_flow_scope_handle_scope_type(root) as i32, - NemoFlowScopeType::Agent as i32 + nemo_relay_scope_handle_scope_type(root) as i32, + NemoRelayScopeType::Agent as i32 ); - assert_eq!(nemo_flow_scope_handle_attributes(root), 0); - nemo_flow_scope_handle_free(root); + assert_eq!(nemo_relay_scope_handle_attributes(root), 0); + nemo_relay_scope_handle_free(root); let scope_name = cstring("ffi_scope"); let scope_data = cstring(r#"{"scope":true}"#); let scope_metadata = cstring(r#"{"meta":"ok"}"#); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 1, scope_data.as_ptr(), @@ -509,41 +521,46 @@ fn test_ffi_error_paths_and_scope_stack() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - take_string(nemo_flow_scope_handle_name(scope)).unwrap(), + take_string(nemo_relay_scope_handle_name(scope)).unwrap(), "ffi_scope" ); assert_eq!( - nemo_flow_scope_handle_scope_type(scope) as i32, - NemoFlowScopeType::Function as i32 + nemo_relay_scope_handle_scope_type(scope) as i32, + NemoRelayScopeType::Function as i32 ); - assert_eq!(nemo_flow_scope_handle_attributes(scope), 1); - assert!(take_string(nemo_flow_scope_handle_parent_uuid(scope)).is_some()); + assert_eq!(nemo_relay_scope_handle_attributes(scope), 1); + assert!(take_string(nemo_relay_scope_handle_parent_uuid(scope)).is_some()); assert_eq!( - serde_json::from_str::(&take_string(nemo_flow_scope_handle_data(scope)).unwrap()) - .unwrap(), + serde_json::from_str::( + &take_string(nemo_relay_scope_handle_data(scope)).unwrap() + ) + .unwrap(), json!({"scope": true}) ); assert_eq!( serde_json::from_str::( - &take_string(nemo_flow_scope_handle_metadata(scope)).unwrap() + &take_string(nemo_relay_scope_handle_metadata(scope)).unwrap() ) .unwrap(), json!({"meta": "ok"}) ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } #[test] fn test_ffi_event_json_null_pointer_returns_null() { unsafe { - assert!(types::nemo_flow_event_json(ptr::null::()).is_null()); + assert!(types::nemo_relay_event_json(ptr::null::()).is_null()); } } @@ -557,19 +574,19 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { let subscriber_name = unique_name("ffi_subscriber"); let subscriber_name_c = cstring(&subscriber_name); assert_eq!( - nemo_flow_register_subscriber( + nemo_relay_register_subscriber( subscriber_name_c.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let intercept_name = unique_name("ffi_tool_intercept"); let intercept_name_c = cstring(&intercept_name); assert_eq!( - nemo_flow_register_tool_request_intercept( + nemo_relay_register_tool_request_intercept( intercept_name_c.as_ptr(), 1, false, @@ -577,46 +594,46 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let conditional_name = unique_name("ffi_tool_conditional"); let conditional_name_c = cstring(&conditional_name); assert_eq!( - nemo_flow_register_tool_conditional_execution_guardrail( + nemo_relay_register_tool_conditional_execution_guardrail( conditional_name_c.as_ptr(), 1, tool_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_name = cstring("ffi_tool"); let args = cstring(r#"{"value": 1}"#); let mut intercepted_out = ptr::null_mut(); assert_eq!( - nemo_flow_tool_request_intercepts( + nemo_relay_tool_request_intercepts( tool_name.as_ptr(), args.as_ptr(), &mut intercepted_out ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let intercepted_json = returned_json(intercepted_out); assert_eq!(intercepted_json["intercepted"], json!(true)); assert_eq!( - nemo_flow_tool_conditional_execution(tool_name.as_ptr(), args.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_tool_conditional_execution(tool_name.as_ptr(), args.as_ptr()), + NemoRelayStatus::Ok ); let tool_call_id = cstring("call_ffi_123"); let metadata = cstring(r#"{"source":"ffi-test"}"#); let mut handle: *mut FfiToolHandle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), args.as_ptr(), ptr::null(), @@ -626,26 +643,26 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { tool_call_id.as_ptr(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_tool_handle_uuid(handle)).is_some()); + assert!(take_string(nemo_relay_tool_handle_uuid(handle)).is_some()); assert_eq!( - take_string(nemo_flow_tool_handle_name(handle)).unwrap(), + take_string(nemo_relay_tool_handle_name(handle)).unwrap(), "ffi_tool" ); - assert_eq!(nemo_flow_tool_handle_attributes(handle), 1); - assert!(take_string(nemo_flow_tool_handle_parent_uuid(handle)).is_some()); + assert_eq!(nemo_relay_tool_handle_attributes(handle), 1); + assert!(take_string(nemo_relay_tool_handle_parent_uuid(handle)).is_some()); let result = cstring(r#"{"ok": true}"#); assert_eq!( - nemo_flow_tool_call_end(handle, result.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_tool_call_end(handle, result.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(handle); + nemo_relay_tool_handle_free(handle); let mut execute_out = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( tool_name.as_ptr(), args.as_ptr(), tool_exec_cb, @@ -657,7 +674,7 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { ptr::null(), &mut execute_out, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let executed_json = returned_json(execute_out); assert_eq!(executed_json["intercepted"], json!(true)); @@ -685,13 +702,13 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { let mark_data = cstring(r#"{"mark":true}"#); let mark_metadata = cstring(r#"{"origin":"ffi"}"#); assert_eq!( - nemo_flow_event( + nemo_relay_event( mark_name.as_ptr(), ptr::null(), mark_data.as_ptr(), mark_metadata.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let events = lock_unpoisoned(event_log()).clone(); assert!(events.iter().any(|event| { @@ -704,18 +721,18 @@ fn test_ffi_tool_lifecycle_execute_and_helpers() { })); assert_eq!( - nemo_flow_deregister_tool_request_intercept(intercept_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_request_intercept(intercept_name_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(conditional_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_conditional_execution_guardrail(conditional_name_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_subscriber(subscriber_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_subscriber(subscriber_name_c.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } @@ -741,13 +758,13 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { let subscriber_name = unique_name("ffi_timestamp_subscriber"); let subscriber_name_c = cstring(&subscriber_name); assert_eq!( - nemo_flow_register_subscriber( + nemo_relay_register_subscriber( subscriber_name_c.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let timestamps = [ @@ -763,9 +780,9 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { let scope_name = cstring("ffi_ts_scope"); let mut scope: *mut FfiScopeHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_push_scope( + api::nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -774,26 +791,26 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { ×tamps[0], &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mark_name = cstring("ffi_ts_mark"); assert_eq!( - api::nemo_flow_event( + api::nemo_relay_event( mark_name.as_ptr(), scope, ptr::null(), ptr::null(), ×tamps[1], ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_name = cstring("ffi_ts_tool"); let tool_args = cstring(r#"{"x":1}"#); let mut tool: *mut FfiToolHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_tool_call( + api::nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), ptr::null(), @@ -804,18 +821,18 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { ×tamps[2], &mut tool, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_result = cstring(r#"{"ok":true}"#); assert_eq!( - api::nemo_flow_tool_call_end( + api::nemo_relay_tool_call_end( tool, tool_result.as_ptr(), ptr::null(), ptr::null(), ×tamps[3], ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_name = cstring("ffi_ts_llm"); @@ -823,7 +840,7 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { cstring(r#"{"headers":{},"content":{"messages":[],"model":"test-model"}}"#); let mut llm: *mut FfiLLMHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_llm_call( + api::nemo_relay_llm_call( llm_name.as_ptr(), llm_request.as_ptr(), ptr::null(), @@ -834,23 +851,23 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { ×tamps[4], &mut llm, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_response = cstring(r#"{"ok":true}"#); assert_eq!( - api::nemo_flow_llm_call_end( + api::nemo_relay_llm_call_end( llm, llm_response.as_ptr(), ptr::null(), ptr::null(), ×tamps[5], ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - api::nemo_flow_pop_scope(scope, ptr::null(), ×tamps[6]), - NemoFlowStatus::Ok + api::nemo_relay_pop_scope(scope, ptr::null(), ×tamps[6]), + NemoRelayStatus::Ok ); let events = lock_unpoisoned(event_log()).clone(); @@ -882,13 +899,13 @@ fn test_ffi_manual_lifecycle_timestamps_accept_unix_micros() { ); assert_eq!( - nemo_flow_deregister_subscriber(subscriber_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_subscriber(subscriber_name_c.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(tool); - nemo_flow_llm_handle_free(llm); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + nemo_relay_tool_handle_free(tool); + nemo_relay_llm_handle_free(llm); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -897,8 +914,8 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let _lock = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); reset_globals(); - fn assert_invalid_timestamp(status: NemoFlowStatus) { - assert_eq!(status, NemoFlowStatus::InvalidArg); + fn assert_invalid_timestamp(status: NemoRelayStatus) { + assert_eq!(status, NemoRelayStatus::InvalidArg); assert!( unsafe { read_last_error() } .unwrap_or_default() @@ -912,9 +929,9 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let invalid_scope_name = cstring("ffi_bad_ts_scope"); let mut invalid_scope: *mut FfiScopeHandle = ptr::null_mut(); - assert_invalid_timestamp(api::nemo_flow_push_scope( + assert_invalid_timestamp(api::nemo_relay_push_scope( invalid_scope_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -928,9 +945,9 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let scope_name = cstring("ffi_valid_ts_scope"); let mut scope: *mut FfiScopeHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_push_scope( + api::nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Agent, + NemoRelayScopeType::Agent, ptr::null(), 0, ptr::null(), @@ -939,11 +956,11 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mark_name = cstring("ffi_bad_ts_mark"); - assert_invalid_timestamp(api::nemo_flow_event( + assert_invalid_timestamp(api::nemo_relay_event( mark_name.as_ptr(), scope, ptr::null(), @@ -954,7 +971,7 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let invalid_tool_name = cstring("ffi_bad_ts_tool"); let tool_args = cstring(r#"{"x":1}"#); let mut invalid_tool: *mut FfiToolHandle = ptr::null_mut(); - assert_invalid_timestamp(api::nemo_flow_tool_call( + assert_invalid_timestamp(api::nemo_relay_tool_call( invalid_tool_name.as_ptr(), tool_args.as_ptr(), ptr::null(), @@ -970,7 +987,7 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let tool_name = cstring("ffi_valid_ts_tool"); let mut tool: *mut FfiToolHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_tool_call( + api::nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), ptr::null(), @@ -981,10 +998,10 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { ptr::null(), &mut tool, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_result = cstring(r#"{"ok":true}"#); - assert_invalid_timestamp(api::nemo_flow_tool_call_end( + assert_invalid_timestamp(api::nemo_relay_tool_call_end( tool, tool_result.as_ptr(), ptr::null(), @@ -992,21 +1009,21 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { &invalid_timestamp, )); assert_eq!( - api::nemo_flow_tool_call_end( + api::nemo_relay_tool_call_end( tool, tool_result.as_ptr(), ptr::null(), ptr::null(), ptr::null(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let invalid_llm_name = cstring("ffi_bad_ts_llm"); let llm_request = cstring(r#"{"headers":{},"content":{"messages":[],"model":"test-model"}}"#); let mut invalid_llm: *mut FfiLLMHandle = ptr::null_mut(); - assert_invalid_timestamp(api::nemo_flow_llm_call( + assert_invalid_timestamp(api::nemo_relay_llm_call( invalid_llm_name.as_ptr(), llm_request.as_ptr(), ptr::null(), @@ -1022,7 +1039,7 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { let llm_name = cstring("ffi_valid_ts_llm"); let mut llm: *mut FfiLLMHandle = ptr::null_mut(); assert_eq!( - api::nemo_flow_llm_call( + api::nemo_relay_llm_call( llm_name.as_ptr(), llm_request.as_ptr(), ptr::null(), @@ -1033,10 +1050,10 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { ptr::null(), &mut llm, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_response = cstring(r#"{"ok":true}"#); - assert_invalid_timestamp(api::nemo_flow_llm_call_end( + assert_invalid_timestamp(api::nemo_relay_llm_call_end( llm, llm_response.as_ptr(), ptr::null(), @@ -1044,30 +1061,30 @@ fn test_ffi_manual_lifecycle_timestamps_reject_out_of_range_unix_micros() { &invalid_timestamp, )); assert_eq!( - api::nemo_flow_llm_call_end( + api::nemo_relay_llm_call_end( llm, llm_response.as_ptr(), ptr::null(), ptr::null(), ptr::null(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_invalid_timestamp(api::nemo_flow_pop_scope( + assert_invalid_timestamp(api::nemo_relay_pop_scope( scope, ptr::null(), &invalid_timestamp, )); assert_eq!( - api::nemo_flow_pop_scope(scope, ptr::null(), ptr::null()), - NemoFlowStatus::Ok + api::nemo_relay_pop_scope(scope, ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(tool); - nemo_flow_llm_handle_free(llm); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + nemo_relay_tool_handle_free(tool); + nemo_relay_llm_handle_free(llm); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -1089,7 +1106,7 @@ fn test_ffi_additional_null_and_invalid_json_paths() { let mut stream: *mut FfiStream = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), args.as_ptr(), ptr::null(), @@ -1099,10 +1116,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), invalid_json.as_ptr(), ptr::null(), @@ -1112,10 +1129,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), args.as_ptr(), ptr::null(), @@ -1125,11 +1142,11 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), args.as_ptr(), ptr::null(), @@ -1139,28 +1156,28 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_tool_call_end(ptr::null(), args.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_tool_call_end(ptr::null(), args.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_tool_call_end(handle, invalid_json.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::InvalidJson + nemo_relay_tool_call_end(handle, invalid_json.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call_end(handle, args.as_ptr(), invalid_json.as_ptr(), ptr::null(),), - NemoFlowStatus::InvalidJson + nemo_relay_tool_call_end(handle, args.as_ptr(), invalid_json.as_ptr(), ptr::null(),), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call_end(handle, args.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_tool_call_end(handle, args.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(handle); + nemo_relay_tool_handle_free(handle); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( name.as_ptr(), args.as_ptr(), tool_exec_cb, @@ -1172,10 +1189,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( name.as_ptr(), invalid_json.as_ptr(), tool_exec_cb, @@ -1187,11 +1204,11 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), ptr::null(), @@ -1201,10 +1218,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), invalid_json.as_ptr(), ptr::null(), @@ -1214,10 +1231,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), invalid_request_shape.as_ptr(), ptr::null(), @@ -1227,7 +1244,7 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -1236,7 +1253,7 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), ptr::null(), @@ -1246,24 +1263,24 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_llm_call_end(ptr::null(), args.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_llm_call_end(ptr::null(), args.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_llm_call_end(llm_handle, invalid_json.as_ptr(), ptr::null(), ptr::null(),), - NemoFlowStatus::InvalidJson + nemo_relay_llm_call_end(llm_handle, invalid_json.as_ptr(), ptr::null(), ptr::null(),), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_end(llm_handle, args.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_llm_call_end(llm_handle, args.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_llm_handle_free(llm_handle); + nemo_relay_llm_handle_free(llm_handle); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1281,10 +1298,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), invalid_request_shape.as_ptr(), llm_exec_cb, @@ -1302,11 +1319,11 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1326,10 +1343,10 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), invalid_request_shape.as_ptr(), llm_exec_cb, @@ -1349,9 +1366,9 @@ fn test_ffi_additional_null_and_invalid_json_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/unit/api/coverage_sweeps_tests.rs b/crates/ffi/tests/unit/api/coverage_sweeps_tests.rs index f01d0dae6..2d9293b08 100644 --- a/crates/ffi/tests/unit/api/coverage_sweeps_tests.rs +++ b/crates/ffi/tests/unit/api/coverage_sweeps_tests.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for coverage sweeps in the NeMo Flow FFI crate. +//! Unit tests for coverage sweeps in the NeMo Relay FFI crate. use super::*; -const RUNTIME_OWNER_ENV: &str = "NEMO_FLOW_RUNTIME_OWNER"; -const BINDING_KIND_ENV: &str = "NEMO_FLOW_BINDING_KIND"; +const RUNTIME_OWNER_ENV: &str = "NEMO_RELAY_RUNTIME_OWNER"; +const BINDING_KIND_ENV: &str = "NEMO_RELAY_BINDING_KIND"; struct EnvGuard { key: &'static str, @@ -43,23 +43,23 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers macro_rules! assert_already_exists { ($expr:expr) => { - assert_eq!($expr, NemoFlowStatus::AlreadyExists); + assert_eq!($expr, NemoRelayStatus::AlreadyExists); }; } unsafe { let tool_san_req = cstring(&unique_name("dup_tool_san_req_extra")); assert_eq!( - nemo_flow_register_tool_sanitize_request_guardrail( + nemo_relay_register_tool_sanitize_request_guardrail( tool_san_req.as_ptr(), 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_tool_sanitize_request_guardrail( + assert_already_exists!(nemo_relay_register_tool_sanitize_request_guardrail( tool_san_req.as_ptr(), 1, tool_request_cb, @@ -67,22 +67,22 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(tool_san_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_sanitize_request_guardrail(tool_san_req.as_ptr()), + NemoRelayStatus::Ok ); let tool_san_resp = cstring(&unique_name("dup_tool_san_resp_extra")); assert_eq!( - nemo_flow_register_tool_sanitize_response_guardrail( + nemo_relay_register_tool_sanitize_response_guardrail( tool_san_resp.as_ptr(), 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_tool_sanitize_response_guardrail( + assert_already_exists!(nemo_relay_register_tool_sanitize_response_guardrail( tool_san_resp.as_ptr(), 1, tool_request_cb, @@ -90,22 +90,22 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_tool_sanitize_response_guardrail(tool_san_resp.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_sanitize_response_guardrail(tool_san_resp.as_ptr()), + NemoRelayStatus::Ok ); let tool_exec = cstring(&unique_name("dup_tool_exec_extra")); assert_eq!( - nemo_flow_register_tool_execution_intercept( + nemo_relay_register_tool_execution_intercept( tool_exec.as_ptr(), 1, tool_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_tool_execution_intercept( + assert_already_exists!(nemo_relay_register_tool_execution_intercept( tool_exec.as_ptr(), 1, tool_exec_intercept_cb, @@ -113,22 +113,22 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_tool_execution_intercept(tool_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_execution_intercept(tool_exec.as_ptr()), + NemoRelayStatus::Ok ); let llm_san_req = cstring(&unique_name("dup_llm_san_req_extra")); assert_eq!( - nemo_flow_register_llm_sanitize_request_guardrail( + nemo_relay_register_llm_sanitize_request_guardrail( llm_san_req.as_ptr(), 1, llm_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_sanitize_request_guardrail( + assert_already_exists!(nemo_relay_register_llm_sanitize_request_guardrail( llm_san_req.as_ptr(), 1, llm_request_cb, @@ -136,22 +136,22 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_llm_sanitize_request_guardrail(llm_san_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_sanitize_request_guardrail(llm_san_req.as_ptr()), + NemoRelayStatus::Ok ); let llm_exec = cstring(&unique_name("dup_llm_exec_extra")); assert_eq!( - nemo_flow_register_llm_execution_intercept( + nemo_relay_register_llm_execution_intercept( llm_exec.as_ptr(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_execution_intercept( + assert_already_exists!(nemo_relay_register_llm_execution_intercept( llm_exec.as_ptr(), 1, llm_exec_intercept_cb, @@ -159,22 +159,22 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_llm_execution_intercept(llm_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_execution_intercept(llm_exec.as_ptr()), + NemoRelayStatus::Ok ); let llm_stream_exec = cstring(&unique_name("dup_llm_stream_exec_extra")); assert_eq!( - nemo_flow_register_llm_stream_execution_intercept( + nemo_relay_register_llm_stream_execution_intercept( llm_stream_exec.as_ptr(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_stream_execution_intercept( + assert_already_exists!(nemo_relay_register_llm_stream_execution_intercept( llm_stream_exec.as_ptr(), 1, llm_exec_intercept_cb, @@ -182,8 +182,8 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_global_wrappers None, )); assert_eq!( - nemo_flow_deregister_llm_stream_execution_intercept(llm_stream_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_stream_execution_intercept(llm_stream_exec.as_ptr()), + NemoRelayStatus::Ok ); } } @@ -196,9 +196,9 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let scope_uuid = cstring( - &take_string(nemo_flow_scope_handle_uuid(parent)).expect("scope uuid should exist"), + &take_string(nemo_relay_scope_handle_uuid(parent)).expect("scope uuid should exist"), ); let tool_name = cstring("ffi_runtime_owner_tool"); @@ -211,7 +211,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { let mut tool_handle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), parent, @@ -221,12 +221,12 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ptr::null(), &mut tool_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut llm_handle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), llm_request.as_ptr(), parent, @@ -236,18 +236,18 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let malformed_request = cstring(r#"{"headers":[],"content":"bad"}"#); let mut transformed_out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_request_intercepts( + nemo_relay_llm_request_intercepts( llm_name.as_ptr(), malformed_request.as_ptr(), &mut transformed_out, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -255,8 +255,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { .contains("failed to parse native_json as LlmRequest") ); assert_eq!( - nemo_flow_llm_conditional_execution(malformed_request.as_ptr()), - NemoFlowStatus::InvalidJson + nemo_relay_llm_conditional_execution(malformed_request.as_ptr()), + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -276,12 +276,12 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { let mut out_json = ptr::null_mut(); assert_eq!( - nemo_flow_tool_request_intercepts( + nemo_relay_tool_request_intercepts( tool_name.as_ptr(), tool_args.as_ptr(), &mut out_json ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -290,12 +290,12 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ); assert_eq!( - nemo_flow_llm_request_intercepts( + nemo_relay_llm_request_intercepts( llm_name.as_ptr(), llm_request.as_ptr(), &mut out_json ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -304,8 +304,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ); assert_eq!( - nemo_flow_llm_conditional_execution(llm_request.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_llm_conditional_execution(llm_request.as_ptr()), + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -315,8 +315,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { let mut conflict_scope = ptr::null_mut(); assert_eq!( - nemo_flow_get_handle(&mut conflict_scope), - NemoFlowStatus::InvalidArg + nemo_relay_get_handle(&mut conflict_scope), + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -324,9 +324,9 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { .contains(conflict_fragment) ); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( tool_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, ptr::null(), @@ -334,7 +334,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ptr::null(), &mut conflict_scope, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -342,8 +342,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { .contains(conflict_fragment) ); assert_eq!( - nemo_flow_event(tool_name.as_ptr(), parent, ptr::null(), ptr::null()), - NemoFlowStatus::InvalidArg + nemo_relay_event(tool_name.as_ptr(), parent, ptr::null(), ptr::null()), + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -353,7 +353,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { let mut conflict_tool_handle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), parent, @@ -363,7 +363,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ptr::null(), &mut conflict_tool_handle, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -371,8 +371,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { .contains(conflict_fragment) ); assert_eq!( - nemo_flow_tool_call_end(tool_handle, tool_result.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::InvalidArg + nemo_relay_tool_call_end(tool_handle, tool_result.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -381,7 +381,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), llm_request.as_ptr(), parent, @@ -391,7 +391,7 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -399,8 +399,8 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { .contains(conflict_fragment) ); assert_eq!( - nemo_flow_llm_call_end(llm_handle, llm_response.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::InvalidArg + nemo_relay_llm_call_end(llm_handle, llm_response.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::InvalidArg ); assert!( read_last_error() @@ -410,130 +410,130 @@ fn test_ffi_runtime_owner_conflict_and_llm_shape_error_sweeps() { let global_name = cstring("conflict-global"); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_tool_sanitize_request_guardrail(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_tool_conditional_execution_guardrail(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_tool_request_intercept(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_tool_request_intercept(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_tool_execution_intercept(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_tool_execution_intercept(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_sanitize_request_guardrail(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_sanitize_request_guardrail(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_sanitize_response_guardrail(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_sanitize_response_guardrail(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_conditional_execution_guardrail(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_request_intercept(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_execution_intercept(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_execution_intercept(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_llm_stream_execution_intercept(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_llm_stream_execution_intercept(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_deregister_subscriber(global_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_deregister_subscriber(global_name.as_ptr()), + NemoRelayStatus::InvalidArg ); let scope_name = cstring("conflict-scope"); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_tool_request_intercept( + nemo_relay_scope_deregister_tool_request_intercept( scope_uuid.as_ptr(), scope_name.as_ptr() ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept( + nemo_relay_scope_deregister_tool_execution_intercept( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + nemo_relay_scope_deregister_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_request_intercept( + nemo_relay_scope_deregister_llm_request_intercept( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept( + nemo_relay_scope_deregister_llm_execution_intercept( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept( + nemo_relay_scope_deregister_llm_stream_execution_intercept( scope_uuid.as_ptr(), scope_name.as_ptr(), ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_name.as_ptr()), - NemoFlowStatus::InvalidArg + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_name.as_ptr()), + NemoRelayStatus::InvalidArg ); - nemo_flow_tool_handle_free(tool_handle); - nemo_flow_llm_handle_free(llm_handle); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_tool_handle_free(tool_handle); + nemo_relay_llm_handle_free(llm_handle); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -544,7 +544,7 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( macro_rules! assert_already_exists { ($expr:expr) => { - assert_eq!($expr, NemoFlowStatus::AlreadyExists); + assert_eq!($expr, NemoRelayStatus::AlreadyExists); }; } @@ -553,9 +553,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( let scope_name = cstring("dup_scope_extra"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -563,13 +563,13 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let tool_san_req = cstring(&unique_name("dup_scope_tool_san_req_extra")); assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), tool_san_req.as_ptr(), 1, @@ -577,9 +577,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_tool_sanitize_request_guardrail( + assert_already_exists!(nemo_relay_scope_register_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), tool_san_req.as_ptr(), 1, @@ -588,16 +588,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), tool_san_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_san_resp = cstring(&unique_name("dup_scope_tool_san_resp_extra")); assert_eq!( - nemo_flow_scope_register_tool_sanitize_response_guardrail( + nemo_relay_scope_register_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), tool_san_resp.as_ptr(), 1, @@ -605,9 +605,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_tool_sanitize_response_guardrail( + assert_already_exists!(nemo_relay_scope_register_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), tool_san_resp.as_ptr(), 1, @@ -616,16 +616,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_response_guardrail( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), tool_san_resp.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_exec = cstring(&unique_name("dup_scope_tool_exec_extra")); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( scope_uuid.as_ptr(), tool_exec.as_ptr(), 1, @@ -633,9 +633,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_tool_execution_intercept( + assert_already_exists!(nemo_relay_scope_register_tool_execution_intercept( scope_uuid.as_ptr(), tool_exec.as_ptr(), 1, @@ -644,16 +644,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept( + nemo_relay_scope_deregister_tool_execution_intercept( scope_uuid.as_ptr(), tool_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_san_req = cstring(&unique_name("dup_scope_llm_san_req_extra")); assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), llm_san_req.as_ptr(), 1, @@ -661,9 +661,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_llm_sanitize_request_guardrail( + assert_already_exists!(nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), llm_san_req.as_ptr(), 1, @@ -672,16 +672,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), llm_san_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_san_resp = cstring(&unique_name("dup_scope_llm_san_resp_extra")); assert_eq!( - nemo_flow_scope_register_llm_sanitize_response_guardrail( + nemo_relay_scope_register_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), llm_san_resp.as_ptr(), 1, @@ -689,9 +689,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_llm_sanitize_response_guardrail( + assert_already_exists!(nemo_relay_scope_register_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), llm_san_resp.as_ptr(), 1, @@ -700,16 +700,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + nemo_relay_scope_deregister_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), llm_san_resp.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_exec = cstring(&unique_name("dup_scope_llm_exec_extra")); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( scope_uuid.as_ptr(), llm_exec.as_ptr(), 1, @@ -717,9 +717,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_llm_execution_intercept( + assert_already_exists!(nemo_relay_scope_register_llm_execution_intercept( scope_uuid.as_ptr(), llm_exec.as_ptr(), 1, @@ -728,16 +728,16 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept( + nemo_relay_scope_deregister_llm_execution_intercept( scope_uuid.as_ptr(), llm_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let llm_stream_exec = cstring(&unique_name("dup_scope_llm_stream_exec_extra")); assert_eq!( - nemo_flow_scope_register_llm_stream_execution_intercept( + nemo_relay_scope_register_llm_stream_execution_intercept( scope_uuid.as_ptr(), llm_stream_exec.as_ptr(), 1, @@ -745,9 +745,9 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_llm_stream_execution_intercept( + assert_already_exists!(nemo_relay_scope_register_llm_stream_execution_intercept( scope_uuid.as_ptr(), llm_stream_exec.as_ptr(), 1, @@ -756,16 +756,19 @@ fn test_ffi_additional_duplicate_registration_sweeps_for_missing_scope_wrappers( None, )); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept( + nemo_relay_scope_deregister_llm_stream_execution_intercept( scope_uuid.as_ptr(), llm_stream_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -779,49 +782,49 @@ fn test_ffi_global_tool_registration_invalid_utf8_name_sweep() { unsafe { assert_eq!( - nemo_flow_register_tool_sanitize_request_guardrail( + nemo_relay_register_tool_sanitize_request_guardrail( invalid, 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_sanitize_request_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_sanitize_response_guardrail( + nemo_relay_register_tool_sanitize_response_guardrail( invalid, 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_sanitize_response_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_sanitize_response_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_conditional_execution_guardrail( + nemo_relay_register_tool_conditional_execution_guardrail( invalid, 1, tool_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_conditional_execution_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_request_intercept( + nemo_relay_register_tool_request_intercept( invalid, 1, false, @@ -829,25 +832,25 @@ fn test_ffi_global_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_request_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_request_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_tool_execution_intercept( + nemo_relay_register_tool_execution_intercept( invalid, 1, tool_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_tool_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_tool_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); } } @@ -862,49 +865,49 @@ fn test_ffi_global_llm_and_subscriber_registration_invalid_utf8_name_sweep() { unsafe { assert_eq!( - nemo_flow_register_llm_sanitize_request_guardrail( + nemo_relay_register_llm_sanitize_request_guardrail( invalid, 1, llm_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_sanitize_request_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_sanitize_request_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_sanitize_response_guardrail( + nemo_relay_register_llm_sanitize_response_guardrail( invalid, 1, llm_response_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_sanitize_response_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_sanitize_response_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_conditional_execution_guardrail( + nemo_relay_register_llm_conditional_execution_guardrail( invalid, 1, llm_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_conditional_execution_guardrail(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( invalid, 1, false, @@ -912,47 +915,47 @@ fn test_ffi_global_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_request_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_execution_intercept( + nemo_relay_register_llm_execution_intercept( invalid, 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_llm_stream_execution_intercept( + nemo_relay_register_llm_stream_execution_intercept( invalid, 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_llm_stream_execution_intercept(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_llm_stream_execution_intercept(invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_register_subscriber(invalid, subscriber_cb, ptr::null_mut(), None), - NemoFlowStatus::InvalidUtf8 + nemo_relay_register_subscriber(invalid, subscriber_cb, ptr::null_mut(), None), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_subscriber(invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_subscriber(invalid), + NemoRelayStatus::InvalidUtf8 ); } } @@ -968,7 +971,7 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { unsafe { assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( invalid_scope, name.as_ptr(), 1, @@ -976,17 +979,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( invalid_scope, name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_sanitize_response_guardrail( + nemo_relay_scope_register_tool_sanitize_response_guardrail( invalid_scope, name.as_ptr(), 1, @@ -994,17 +997,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_response_guardrail( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( invalid_scope, name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( invalid_scope, name.as_ptr(), 1, @@ -1012,17 +1015,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( invalid_scope, name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_request_intercept( + nemo_relay_scope_register_tool_request_intercept( invalid_scope, name.as_ptr(), 1, @@ -1031,14 +1034,14 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_request_intercept(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_request_intercept(invalid_scope, name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( invalid_scope, name.as_ptr(), 1, @@ -1046,11 +1049,11 @@ fn test_ffi_scope_tool_registration_invalid_utf8_scope_uuid_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_execution_intercept(invalid_scope, name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); } } @@ -1066,7 +1069,7 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( unsafe { assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( invalid_scope, name.as_ptr(), 1, @@ -1074,14 +1077,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail(invalid_scope, name.as_ptr(),), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( + invalid_scope, + name.as_ptr(), + ), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_sanitize_response_guardrail( + nemo_relay_scope_register_llm_sanitize_response_guardrail( invalid_scope, name.as_ptr(), 1, @@ -1089,17 +1095,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + nemo_relay_scope_deregister_llm_sanitize_response_guardrail( invalid_scope, name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( invalid_scope, name.as_ptr(), 1, @@ -1107,17 +1113,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( invalid_scope, name.as_ptr(), ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_request_intercept( + nemo_relay_scope_register_llm_request_intercept( invalid_scope, name.as_ptr(), 1, @@ -1126,14 +1132,14 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_request_intercept(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_request_intercept(invalid_scope, name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( invalid_scope, name.as_ptr(), 1, @@ -1141,14 +1147,14 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_execution_intercept(invalid_scope, name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_stream_execution_intercept( + nemo_relay_scope_register_llm_stream_execution_intercept( invalid_scope, name.as_ptr(), 1, @@ -1156,25 +1162,28 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_scope_uuid_sweep( ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_stream_execution_intercept( + invalid_scope, + name.as_ptr() + ), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( invalid_scope, name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_subscriber(invalid_scope, name.as_ptr()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_subscriber(invalid_scope, name.as_ptr()), + NemoRelayStatus::InvalidUtf8 ); } } @@ -1189,9 +1198,9 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { let scope_name = cstring("scope-tool-invalid-name"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -1199,14 +1208,14 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let invalid_utf8 = [0xffu8, 0]; let invalid = invalid_utf8.as_ptr() as *const c_char; assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1214,17 +1223,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_sanitize_response_guardrail( + nemo_relay_scope_register_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1232,17 +1241,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_response_guardrail( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), invalid ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1250,17 +1259,17 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), invalid, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_request_intercept( + nemo_relay_scope_register_tool_request_intercept( scope_uuid.as_ptr(), invalid, 1, @@ -1269,14 +1278,14 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_request_intercept(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_request_intercept(scope_uuid.as_ptr(), invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( scope_uuid.as_ptr(), invalid, 1, @@ -1284,16 +1293,19 @@ fn test_ffi_scope_tool_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_tool_execution_intercept(scope_uuid.as_ptr(), invalid), + NemoRelayStatus::InvalidUtf8 ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -1307,9 +1319,9 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { let scope_name = cstring("scope-llm-invalid-name"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -1317,14 +1329,14 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let invalid_utf8 = [0xffu8, 0]; let invalid = invalid_utf8.as_ptr() as *const c_char; assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1332,14 +1344,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( + scope_uuid.as_ptr(), + invalid + ), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_sanitize_response_guardrail( + nemo_relay_scope_register_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1347,17 +1362,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + nemo_relay_scope_deregister_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), invalid ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), invalid, 1, @@ -1365,17 +1380,17 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), invalid, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_request_intercept( + nemo_relay_scope_register_llm_request_intercept( scope_uuid.as_ptr(), invalid, 1, @@ -1384,14 +1399,14 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_request_intercept(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_request_intercept(scope_uuid.as_ptr(), invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( scope_uuid.as_ptr(), invalid, 1, @@ -1399,14 +1414,14 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_execution_intercept(scope_uuid.as_ptr(), invalid), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_llm_stream_execution_intercept( + nemo_relay_scope_register_llm_stream_execution_intercept( scope_uuid.as_ptr(), invalid, 1, @@ -1414,30 +1429,36 @@ fn test_ffi_scope_llm_and_subscriber_registration_invalid_utf8_name_sweep() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_llm_stream_execution_intercept( + scope_uuid.as_ptr(), + invalid + ), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( scope_uuid.as_ptr(), invalid, subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid), + NemoRelayStatus::InvalidUtf8 ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -1449,7 +1470,7 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let scope_name = cstring("ffi_child_scope_with_parent"); let data = cstring(r#"{"scope":"child"}"#); @@ -1460,9 +1481,9 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { let mut child = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 3, data.as_ptr(), @@ -1470,13 +1491,13 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_scope_handle_parent_uuid(child)).is_some()); + assert!(take_string(nemo_relay_scope_handle_parent_uuid(child)).is_some()); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( invalid, - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, ptr::null(), @@ -1484,12 +1505,12 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, invalid_json.as_ptr(), @@ -1497,12 +1518,12 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, parent, 0, ptr::null(), @@ -1510,46 +1531,49 @@ fn test_ffi_scope_and_event_parent_and_utf8_paths() { ptr::null(), &mut child, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); let event_name = cstring("ffi_event_with_parent"); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, data.as_ptr(), metadata.as_ptr() ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_event(invalid, parent, ptr::null(), ptr::null()), - NemoFlowStatus::InvalidUtf8 + nemo_relay_event(invalid, parent, ptr::null(), ptr::null()), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, invalid_json.as_ptr(), ptr::null() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_event( + nemo_relay_event( event_name.as_ptr(), parent, ptr::null(), invalid_json.as_ptr() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); - assert_eq!(nemo_flow_pop_scope(child, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(child); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(child, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(child); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -1561,7 +1585,7 @@ fn test_ffi_tool_call_parent_tool_call_id_and_utf8_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_tool_call_utf8"); let args = cstring(r#"{"value":1}"#); @@ -1575,7 +1599,7 @@ fn test_ffi_tool_call_parent_tool_call_id_and_utf8_paths() { let mut handle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), args.as_ptr(), parent, @@ -1585,11 +1609,11 @@ fn test_ffi_tool_call_parent_tool_call_id_and_utf8_paths() { tool_call_id.as_ptr(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_tool_handle_parent_uuid(handle)).is_some()); + assert!(take_string(nemo_relay_tool_handle_parent_uuid(handle)).is_some()); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( invalid, args.as_ptr(), parent, @@ -1599,10 +1623,10 @@ fn test_ffi_tool_call_parent_tool_call_id_and_utf8_paths() { ptr::null(), &mut handle ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( name.as_ptr(), args.as_ptr(), parent, @@ -1612,20 +1636,20 @@ fn test_ffi_tool_call_parent_tool_call_id_and_utf8_paths() { invalid, &mut handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_tool_call_end(handle, result.as_ptr(), ptr::null(), invalid_json.as_ptr()), - NemoFlowStatus::InvalidJson + nemo_relay_tool_call_end(handle, result.as_ptr(), ptr::null(), invalid_json.as_ptr()), + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call_end(handle, result.as_ptr(), data.as_ptr(), metadata.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_tool_call_end(handle, result.as_ptr(), data.as_ptr(), metadata.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(handle); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_tool_handle_free(handle); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -1637,7 +1661,7 @@ fn test_ffi_llm_call_parent_model_and_utf8_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_llm_call_utf8"); let request = cstring( @@ -1653,7 +1677,7 @@ fn test_ffi_llm_call_parent_model_and_utf8_paths() { let mut handle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), parent, @@ -1663,11 +1687,11 @@ fn test_ffi_llm_call_parent_model_and_utf8_paths() { model_name.as_ptr(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_llm_handle_parent_uuid(handle)).is_some()); + assert!(take_string(nemo_relay_llm_handle_parent_uuid(handle)).is_some()); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( invalid, request.as_ptr(), parent, @@ -1677,10 +1701,10 @@ fn test_ffi_llm_call_parent_model_and_utf8_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), parent, @@ -1690,25 +1714,25 @@ fn test_ffi_llm_call_parent_model_and_utf8_paths() { invalid, &mut handle, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call_end( + nemo_relay_llm_call_end( handle, response.as_ptr(), ptr::null(), invalid_json.as_ptr() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_end(handle, response.as_ptr(), data.as_ptr(), metadata.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_llm_call_end(handle, response.as_ptr(), data.as_ptr(), metadata.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_llm_handle_free(handle); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_llm_handle_free(handle); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -1725,7 +1749,7 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1743,11 +1767,11 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); let mut out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), invalid_shape.as_ptr(), llm_exec_cb, @@ -1765,7 +1789,7 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ptr::null(), &mut out, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -1774,7 +1798,7 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1794,11 +1818,11 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); let mut stream = ptr::null_mut(); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), invalid_shape.as_ptr(), llm_exec_cb, @@ -1818,7 +1842,7 @@ fn test_ffi_llm_execute_and_stream_shape_and_out_error_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -1834,7 +1858,7 @@ fn test_ffi_stream_next_reports_error_items() { reset_globals(); let (tx, rx) = tokio::sync::mpsc::channel(1); - tx.blocking_send(Err(nemo_flow::error::FlowError::Internal( + tx.blocking_send(Err(nemo_relay::error::FlowError::Internal( "ffi stream failed".to_string(), ))) .expect("expected error payload to be queued"); @@ -1846,14 +1870,14 @@ fn test_ffi_stream_next_reports_error_items() { unsafe { let mut chunk = ptr::null_mut(); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), -1); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), -1); assert!(chunk.is_null()); assert!( read_last_error() .unwrap_or_default() .contains("ffi stream failed") ); - nemo_flow_stream_free(stream); + nemo_relay_stream_free(stream); } } @@ -1871,8 +1895,8 @@ fn test_ffi_llm_helper_invalid_shape_and_intercept_failure_paths() { let mut out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_request_intercepts(name.as_ptr(), invalid_shape.as_ptr(), &mut out), - NemoFlowStatus::InvalidJson + nemo_relay_llm_request_intercepts(name.as_ptr(), invalid_shape.as_ptr(), &mut out), + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -1881,8 +1905,8 @@ fn test_ffi_llm_helper_invalid_shape_and_intercept_failure_paths() { ); assert_eq!( - nemo_flow_llm_conditional_execution(invalid_shape.as_ptr()), - NemoFlowStatus::InvalidJson + nemo_relay_llm_conditional_execution(invalid_shape.as_ptr()), + NemoRelayStatus::InvalidJson ); assert!( read_last_error() @@ -1892,7 +1916,7 @@ fn test_ffi_llm_helper_invalid_shape_and_intercept_failure_paths() { let intercept_name = cstring(&unique_name("ffi_llm_request_intercept_fail")); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( intercept_name.as_ptr(), 1, false, @@ -1900,11 +1924,11 @@ fn test_ffi_llm_helper_invalid_shape_and_intercept_failure_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_llm_request_intercepts(name.as_ptr(), valid_request.as_ptr(), &mut out), - NemoFlowStatus::Internal + nemo_relay_llm_request_intercepts(name.as_ptr(), valid_request.as_ptr(), &mut out), + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -1912,11 +1936,11 @@ fn test_ffi_llm_helper_invalid_shape_and_intercept_failure_paths() { .contains("llm request intercept callback failed") ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(intercept_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_request_intercept(intercept_name.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } @@ -1928,7 +1952,7 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let tool_name = cstring("ffi_tool_failure_sweep"); let tool_args = cstring(r#"{"value":9}"#); @@ -1939,7 +1963,7 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { let tool_intercept = cstring(&unique_name("ffi_tool_helper_fail")); assert_eq!( - nemo_flow_register_tool_request_intercept( + nemo_relay_register_tool_request_intercept( tool_intercept.as_ptr(), 1, false, @@ -1947,16 +1971,16 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut tool_out = ptr::null_mut(); assert_eq!( - nemo_flow_tool_request_intercepts( + nemo_relay_tool_request_intercepts( tool_name.as_ptr(), tool_args.as_ptr(), &mut tool_out ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -1964,13 +1988,13 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { .contains("tool sanitize callback failed") ); assert_eq!( - nemo_flow_deregister_tool_request_intercept(tool_intercept.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_request_intercept(tool_intercept.as_ptr()), + NemoRelayStatus::Ok ); let llm_intercept = cstring(&unique_name("ffi_llm_helper_fail")); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( llm_intercept.as_ptr(), 1, false, @@ -1978,12 +2002,16 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut llm_out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_request_intercepts(llm_name.as_ptr(), llm_request.as_ptr(), &mut llm_out), - NemoFlowStatus::Internal + nemo_relay_llm_request_intercepts( + llm_name.as_ptr(), + llm_request.as_ptr(), + &mut llm_out + ), + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -1991,13 +2019,13 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { .contains("llm request intercept callback failed") ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(llm_intercept.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_request_intercept(llm_intercept.as_ptr()), + NemoRelayStatus::Ok ); let mut llm_handle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), llm_request.as_ptr(), parent, @@ -2007,17 +2035,17 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null(), &mut llm_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_llm_call_end(llm_handle, llm_response.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_llm_call_end(llm_handle, llm_response.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_llm_handle_free(llm_handle); + nemo_relay_llm_handle_free(llm_handle); let mut tool_handle = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call( + nemo_relay_tool_call( tool_name.as_ptr(), tool_args.as_ptr(), parent, @@ -2027,22 +2055,22 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null(), &mut tool_handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let tool_result = cstring(r#"{"done":true}"#); assert_eq!( - nemo_flow_tool_call_end(tool_handle, tool_result.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_tool_call_end(tool_handle, tool_result.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_tool_handle_free(tool_handle); + nemo_relay_tool_handle_free(tool_handle); let invalid_utf8 = [0xffu8, 0]; let invalid_name = invalid_utf8.as_ptr() as *const c_char; let invalid_json = cstring("{"); let mut exec_out = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( invalid_name, tool_args.as_ptr(), tool_exec_cb, @@ -2054,10 +2082,10 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null(), &mut exec_out, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( tool_name.as_ptr(), tool_args.as_ptr(), tool_exec_cb, @@ -2069,11 +2097,11 @@ fn test_ffi_helper_and_lifecycle_callback_failure_paths() { ptr::null(), &mut exec_out, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -2091,9 +2119,9 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { let invalid_name = invalid_utf8.as_ptr() as *const c_char; assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -2101,7 +2129,7 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert!( read_last_error() @@ -2111,11 +2139,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { macro_rules! assert_missing_scope { ($expr:expr) => { - assert_eq!($expr, NemoFlowStatus::NotFound); + assert_eq!($expr, NemoRelayStatus::NotFound); }; } - assert_missing_scope!(nemo_flow_scope_register_tool_sanitize_request_guardrail( + assert_missing_scope!(nemo_relay_scope_register_tool_sanitize_request_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2123,11 +2151,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + assert_missing_scope!(nemo_relay_scope_deregister_tool_sanitize_request_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_tool_sanitize_response_guardrail( + assert_missing_scope!(nemo_relay_scope_register_tool_sanitize_response_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2135,12 +2163,14 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_tool_sanitize_response_guardrail( - missing_scope_uuid.as_ptr(), - valid_name.as_ptr(), - )); assert_missing_scope!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( + missing_scope_uuid.as_ptr(), + valid_name.as_ptr(), + ) + ); + assert_missing_scope!( + nemo_relay_scope_register_tool_conditional_execution_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2150,12 +2180,12 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ) ); assert_missing_scope!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), ) ); - assert_missing_scope!(nemo_flow_scope_register_tool_request_intercept( + assert_missing_scope!(nemo_relay_scope_register_tool_request_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2164,11 +2194,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_tool_request_intercept( + assert_missing_scope!(nemo_relay_scope_deregister_tool_request_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_tool_execution_intercept( + assert_missing_scope!(nemo_relay_scope_register_tool_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2176,12 +2206,12 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_tool_execution_intercept( + assert_missing_scope!(nemo_relay_scope_deregister_tool_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_llm_sanitize_request_guardrail( + assert_missing_scope!(nemo_relay_scope_register_llm_sanitize_request_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2189,11 +2219,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + assert_missing_scope!(nemo_relay_scope_deregister_llm_sanitize_request_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_llm_sanitize_response_guardrail( + assert_missing_scope!(nemo_relay_scope_register_llm_sanitize_response_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2201,12 +2231,12 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + assert_missing_scope!(nemo_relay_scope_deregister_llm_sanitize_response_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); assert_missing_scope!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2216,12 +2246,12 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ) ); assert_missing_scope!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), ) ); - assert_missing_scope!(nemo_flow_scope_register_llm_request_intercept( + assert_missing_scope!(nemo_relay_scope_register_llm_request_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2230,11 +2260,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_llm_request_intercept( + assert_missing_scope!(nemo_relay_scope_deregister_llm_request_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_llm_execution_intercept( + assert_missing_scope!(nemo_relay_scope_register_llm_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2242,11 +2272,11 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_llm_execution_intercept( + assert_missing_scope!(nemo_relay_scope_deregister_llm_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_llm_stream_execution_intercept( + assert_missing_scope!(nemo_relay_scope_register_llm_stream_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), 1, @@ -2254,27 +2284,27 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_llm_stream_execution_intercept( + assert_missing_scope!(nemo_relay_scope_deregister_llm_stream_execution_intercept( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); - assert_missing_scope!(nemo_flow_scope_register_subscriber( + assert_missing_scope!(nemo_relay_scope_register_subscriber( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), subscriber_cb, ptr::null_mut(), None, )); - assert_missing_scope!(nemo_flow_scope_deregister_subscriber( + assert_missing_scope!(nemo_relay_scope_deregister_subscriber( missing_scope_uuid.as_ptr(), valid_name.as_ptr(), )); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -2282,25 +2312,28 @@ fn test_ffi_scope_registry_missing_scope_and_null_out_sweeps() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept( + nemo_relay_scope_deregister_llm_stream_execution_intercept( scope_uuid.as_ptr(), invalid_name, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), invalid_name), + NemoRelayStatus::InvalidUtf8 ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -2312,7 +2345,7 @@ fn test_ffi_llm_lifecycle_additional_error_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_llm_lifecycle_extra"); let request = cstring( @@ -2323,7 +2356,7 @@ fn test_ffi_llm_lifecycle_additional_error_paths() { let mut handle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), parent, @@ -2333,10 +2366,10 @@ fn test_ffi_llm_lifecycle_additional_error_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), parent, @@ -2346,11 +2379,11 @@ fn test_ffi_llm_lifecycle_additional_error_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( name.as_ptr(), request.as_ptr(), parent, @@ -2360,25 +2393,25 @@ fn test_ffi_llm_lifecycle_additional_error_paths() { ptr::null(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_llm_call_end( + nemo_relay_llm_call_end( handle, response.as_ptr(), invalid_json.as_ptr(), ptr::null() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_end(handle, response.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_llm_call_end(handle, response.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_llm_handle_free(handle); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_llm_handle_free(handle); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -2390,7 +2423,7 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_llm_execute_extra"); let request = cstring( @@ -2402,13 +2435,13 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { let invalid_utf8 = [0xffu8, 0]; let invalid_name = invalid_utf8.as_ptr() as *const c_char; let invalid_model_name = invalid_utf8.as_ptr() as *const c_char; - let response_codec = api::nemo_flow_openai_chat_codec_new(); + let response_codec = api::nemo_relay_openai_chat_codec_new(); let mut out_json = ptr::null_mut(); let mut stream = ptr::null_mut(); let mut chunk = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( invalid_name, request.as_ptr(), llm_exec_cb, @@ -2426,10 +2459,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), invalid_json.as_ptr(), llm_exec_cb, @@ -2447,10 +2480,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -2468,10 +2501,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_openai_chat_cb, @@ -2489,14 +2522,14 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { response_codec, &mut out_json, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let decoded = returned_json(out_json); assert_eq!(decoded["id"], json!("chatcmpl-ffi")); assert_eq!(decoded["model"], json!("codec-model")); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( invalid_name, request.as_ptr(), llm_exec_cb, @@ -2516,10 +2549,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), invalid_json.as_ptr(), llm_exec_cb, @@ -2539,10 +2572,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -2562,10 +2595,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -2585,10 +2618,10 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -2608,15 +2641,15 @@ fn test_ffi_llm_execute_and_stream_additional_input_paths() { ptr::null(), &mut stream, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 1); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 1); assert_eq!(returned_json(chunk)["content"], json!("hello from ffi")); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 0); - nemo_flow_stream_free(stream); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 0); + nemo_relay_stream_free(stream); - types::nemo_flow_codec_free(response_codec); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + types::nemo_relay_codec_free(response_codec); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/unit/api/execution_tests.rs b/crates/ffi/tests/unit/api/execution_tests.rs index 9f6f82d2d..066b871c2 100644 --- a/crates/ffi/tests/unit/api/execution_tests.rs +++ b/crates/ffi/tests/unit/api/execution_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for execution in the NeMo Flow FFI crate. +//! Unit tests for execution in the NeMo Relay FFI crate. use super::*; @@ -13,7 +13,7 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_tool_execute_parent"); let args = cstring(r#"{"value":2}"#); @@ -23,7 +23,7 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { let mut out_json = ptr::null_mut(); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( name.as_ptr(), args.as_ptr(), tool_exec_cb, @@ -35,13 +35,13 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { metadata.as_ptr(), &mut out_json, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let executed = returned_json(out_json); assert_eq!(executed["executed"], json!(true)); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( name.as_ptr(), args.as_ptr(), tool_exec_cb, @@ -53,11 +53,11 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { invalid_json.as_ptr(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_call_execute( + nemo_relay_tool_call_execute( name.as_ptr(), args.as_ptr(), tool_exec_fail_cb, @@ -69,7 +69,7 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -77,8 +77,8 @@ fn test_ffi_tool_execute_parent_data_and_error_paths() { .contains("tool execution callback failed") ); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -90,7 +90,7 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_llm_execute_codec"); let request = cstring( @@ -104,7 +104,7 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { let mut out_json = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -122,14 +122,14 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let executed = returned_json(out_json); assert_eq!(executed["model_seen"], json!("codec-model")); assert_eq!(executed["content"], json!("hello from ffi")); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -147,10 +147,10 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -168,10 +168,10 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_fail_cb, @@ -189,7 +189,7 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { ptr::null(), &mut out_json, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -197,8 +197,8 @@ fn test_ffi_llm_execute_codec_parent_and_error_paths() { .contains("llm execution callback failed") ); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -210,7 +210,7 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { unsafe { let stack = fresh_scope_stack(); let mut parent = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut parent), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_get_handle(&mut parent), NemoRelayStatus::Ok); let name = cstring("ffi_llm_stream_defaults"); let request = cstring( @@ -220,12 +220,12 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { let metadata = cstring(r#"{"trace":"stream"}"#); let model_name = cstring("stream-model"); let invalid_json = cstring("{"); - let response_codec = api::nemo_flow_openai_chat_codec_new(); + let response_codec = api::nemo_relay_openai_chat_codec_new(); let mut stream = ptr::null_mut(); let mut chunk = ptr::null_mut(); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_openai_chat_cb, @@ -245,18 +245,18 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { response_codec, &mut stream, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 1); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 1); let stream_chunk = returned_json(chunk); assert_eq!(stream_chunk["id"], json!("chatcmpl-ffi")); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 0); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 0); assert!(lock_unpoisoned(collected_chunks()).is_empty()); assert_eq!(*lock_unpoisoned(finalizer_calls()), 0); - nemo_flow_stream_free(stream); + nemo_relay_stream_free(stream); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_openai_chat_cb, @@ -276,10 +276,10 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { response_codec, &mut stream, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( name.as_ptr(), request.as_ptr(), llm_exec_fail_cb, @@ -299,7 +299,7 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { response_codec, &mut stream, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -307,9 +307,9 @@ fn test_ffi_llm_stream_execute_response_codec_defaults_and_error_paths() { .contains("llm execution callback failed") ); - types::nemo_flow_codec_free(response_codec); - nemo_flow_scope_handle_free(parent); - nemo_flow_scope_stack_free(stack); + types::nemo_relay_codec_free(response_codec); + nemo_relay_scope_handle_free(parent); + nemo_relay_scope_stack_free(stack); } } @@ -320,21 +320,21 @@ fn test_ffi_registration_and_exporter_error_paths() { unsafe { assert_eq!( - nemo_flow_scope_stack_create(ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_scope_stack_create(ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_scope_stack_set_thread(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_scope_stack_set_thread(ptr::null()), + NemoRelayStatus::NullPointer ); let stack = fresh_scope_stack(); let scope_name = cstring("ffi_scope_local"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -342,124 +342,124 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let invalid_uuid = cstring("not-a-uuid"); let global_tool_san_req = cstring(&unique_name("ffi_tool_san_req")); assert_eq!( - nemo_flow_register_tool_sanitize_request_guardrail( + nemo_relay_register_tool_sanitize_request_guardrail( global_tool_san_req.as_ptr(), 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_register_tool_sanitize_request_guardrail( + nemo_relay_register_tool_sanitize_request_guardrail( global_tool_san_req.as_ptr(), 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::AlreadyExists + NemoRelayStatus::AlreadyExists ); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(global_tool_san_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_sanitize_request_guardrail(global_tool_san_req.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_tool_sanitize_request_guardrail(global_tool_san_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_sanitize_request_guardrail(global_tool_san_req.as_ptr()), + NemoRelayStatus::Ok ); let global_tool_san_resp = cstring(&unique_name("ffi_tool_san_resp")); assert_eq!( - nemo_flow_register_tool_sanitize_response_guardrail( + nemo_relay_register_tool_sanitize_response_guardrail( global_tool_san_resp.as_ptr(), 1, tool_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_tool_sanitize_response_guardrail(global_tool_san_resp.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_sanitize_response_guardrail(global_tool_san_resp.as_ptr()), + NemoRelayStatus::Ok ); let global_tool_exec = cstring(&unique_name("ffi_tool_exec")); assert_eq!( - nemo_flow_register_tool_execution_intercept( + nemo_relay_register_tool_execution_intercept( global_tool_exec.as_ptr(), 1, tool_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_tool_execution_intercept(global_tool_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_execution_intercept(global_tool_exec.as_ptr()), + NemoRelayStatus::Ok ); let global_llm_san_req = cstring(&unique_name("ffi_llm_san_req")); assert_eq!( - nemo_flow_register_llm_sanitize_request_guardrail( + nemo_relay_register_llm_sanitize_request_guardrail( global_llm_san_req.as_ptr(), 1, llm_request_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_sanitize_request_guardrail(global_llm_san_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_sanitize_request_guardrail(global_llm_san_req.as_ptr()), + NemoRelayStatus::Ok ); let global_llm_exec = cstring(&unique_name("ffi_llm_exec")); assert_eq!( - nemo_flow_register_llm_execution_intercept( + nemo_relay_register_llm_execution_intercept( global_llm_exec.as_ptr(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_execution_intercept(global_llm_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_execution_intercept(global_llm_exec.as_ptr()), + NemoRelayStatus::Ok ); let global_llm_stream_exec = cstring(&unique_name("ffi_llm_stream_exec")); assert_eq!( - nemo_flow_register_llm_stream_execution_intercept( + nemo_relay_register_llm_stream_execution_intercept( global_llm_stream_exec.as_ptr(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_stream_execution_intercept(global_llm_stream_exec.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_stream_execution_intercept(global_llm_stream_exec.as_ptr()), + NemoRelayStatus::Ok ); let scope_tool_san_req = cstring(&unique_name("scope_tool_san_req")); assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( invalid_uuid.as_ptr(), scope_tool_san_req.as_ptr(), 1, @@ -467,10 +467,10 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_scope_register_tool_sanitize_request_guardrail( + nemo_relay_scope_register_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_tool_san_req.as_ptr(), 1, @@ -478,19 +478,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + nemo_relay_scope_deregister_tool_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_tool_san_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_tool_san_resp = cstring(&unique_name("scope_tool_san_resp")); assert_eq!( - nemo_flow_scope_register_tool_sanitize_response_guardrail( + nemo_relay_scope_register_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), scope_tool_san_resp.as_ptr(), 1, @@ -498,19 +498,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_tool_sanitize_response_guardrail( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( scope_uuid.as_ptr(), scope_tool_san_resp.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_tool_cond = cstring(&unique_name("scope_tool_cond")); assert_eq!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_tool_cond.as_ptr(), 1, @@ -518,19 +518,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_tool_cond.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_tool_req = cstring(&unique_name("scope_tool_req")); assert_eq!( - nemo_flow_scope_register_tool_request_intercept( + nemo_relay_scope_register_tool_request_intercept( scope_uuid.as_ptr(), scope_tool_req.as_ptr(), 1, @@ -539,19 +539,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_tool_request_intercept( + nemo_relay_scope_deregister_tool_request_intercept( scope_uuid.as_ptr(), scope_tool_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_tool_exec = cstring(&unique_name("scope_tool_exec")); assert_eq!( - nemo_flow_scope_register_tool_execution_intercept( + nemo_relay_scope_register_tool_execution_intercept( scope_uuid.as_ptr(), scope_tool_exec.as_ptr(), 1, @@ -559,19 +559,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_tool_execution_intercept( + nemo_relay_scope_deregister_tool_execution_intercept( scope_uuid.as_ptr(), scope_tool_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_san_req = cstring(&unique_name("scope_llm_san_req")); assert_eq!( - nemo_flow_scope_register_llm_sanitize_request_guardrail( + nemo_relay_scope_register_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_llm_san_req.as_ptr(), 1, @@ -579,19 +579,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + nemo_relay_scope_deregister_llm_sanitize_request_guardrail( scope_uuid.as_ptr(), scope_llm_san_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_san_resp = cstring(&unique_name("scope_llm_san_resp")); assert_eq!( - nemo_flow_scope_register_llm_sanitize_response_guardrail( + nemo_relay_scope_register_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), scope_llm_san_resp.as_ptr(), 1, @@ -599,19 +599,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + nemo_relay_scope_deregister_llm_sanitize_response_guardrail( scope_uuid.as_ptr(), scope_llm_san_resp.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_cond = cstring(&unique_name("scope_llm_cond")); assert_eq!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_llm_cond.as_ptr(), 1, @@ -619,19 +619,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_llm_cond.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_req = cstring(&unique_name("scope_llm_req")); assert_eq!( - nemo_flow_scope_register_llm_request_intercept( + nemo_relay_scope_register_llm_request_intercept( scope_uuid.as_ptr(), scope_llm_req.as_ptr(), 1, @@ -640,19 +640,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_request_intercept( + nemo_relay_scope_deregister_llm_request_intercept( scope_uuid.as_ptr(), scope_llm_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_exec = cstring(&unique_name("scope_llm_exec")); assert_eq!( - nemo_flow_scope_register_llm_execution_intercept( + nemo_relay_scope_register_llm_execution_intercept( scope_uuid.as_ptr(), scope_llm_exec.as_ptr(), 1, @@ -660,19 +660,19 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_execution_intercept( + nemo_relay_scope_deregister_llm_execution_intercept( scope_uuid.as_ptr(), scope_llm_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_stream_exec = cstring(&unique_name("scope_llm_stream_exec")); assert_eq!( - nemo_flow_scope_register_llm_stream_execution_intercept( + nemo_relay_scope_register_llm_stream_execution_intercept( scope_uuid.as_ptr(), scope_llm_stream_exec.as_ptr(), 1, @@ -680,34 +680,34 @@ fn test_ffi_registration_and_exporter_error_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_llm_stream_execution_intercept( + nemo_relay_scope_deregister_llm_stream_execution_intercept( scope_uuid.as_ptr(), scope_llm_stream_exec.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_subscriber = cstring(&unique_name("scope_subscriber")); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( scope_uuid.as_ptr(), scope_subscriber.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), - NemoFlowStatus::Ok + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), - NemoFlowStatus::Ok + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), + NemoRelayStatus::Ok ); let mut exporter: *mut FfiAtifExporter = ptr::null_mut(); @@ -715,68 +715,71 @@ fn test_ffi_registration_and_exporter_error_paths() { let agent = cstring("ffi-agent"); let version = cstring("1.0.0"); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), ptr::null(), ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_register(ptr::null(), scope_subscriber.as_ptr()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_register(ptr::null(), scope_subscriber.as_ptr()), + NemoRelayStatus::NullPointer ); let mut null_export = ptr::null_mut(); assert_eq!( - nemo_flow_atif_exporter_export(ptr::null(), &mut null_export), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_export(ptr::null(), &mut null_export), + NemoRelayStatus::NullPointer ); let exporter_name = cstring(&unique_name("ffi_exporter_sub")); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::AlreadyExists + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::AlreadyExists ); assert_eq!( - nemo_flow_atif_exporter_export(exporter, ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_export(exporter, ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_clear(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_clear(ptr::null()), + NemoRelayStatus::NullPointer ); let missing_exporter = cstring("missing_exporter"); assert_eq!( - nemo_flow_atif_exporter_deregister(missing_exporter.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(missing_exporter.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_name.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_atif_exporter_free(exporter); + nemo_relay_atif_exporter_free(exporter); let mut chunk = ptr::null_mut(); - assert_eq!(nemo_flow_stream_next(ptr::null_mut(), &mut chunk), -1); - assert_eq!(nemo_flow_stream_next(ptr::null_mut(), ptr::null_mut()), -1); + assert_eq!(nemo_relay_stream_next(ptr::null_mut(), &mut chunk), -1); + assert_eq!(nemo_relay_stream_next(ptr::null_mut(), ptr::null_mut()), -1); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/unit/api/plugin_tests.rs b/crates/ffi/tests/unit/api/plugin_tests.rs index 2e22e7f52..2d37db847 100644 --- a/crates/ffi/tests/unit/api/plugin_tests.rs +++ b/crates/ffi/tests/unit/api/plugin_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for plugin in the NeMo Flow FFI crate. +//! Unit tests for plugin in the NeMo Relay FFI crate. use super::*; @@ -9,7 +9,7 @@ use super::*; fn test_ffi_plugin_registration_validation_and_cleanup() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let plugin_kind = unique_name("ffi_plugin"); let plugin_kind_c = cstring(&plugin_kind); @@ -28,20 +28,20 @@ fn test_ffi_plugin_registration_validation_and_cleanup() { unsafe { assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( plugin_kind_c.as_ptr(), Some(plugin_validate_warn), plugin_register_subscriber, user_data, Some(plugin_free), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut report_json = ptr::null_mut(); assert_eq!( - nemo_flow_validate_plugin_config(config.as_ptr(), &mut report_json), - NemoFlowStatus::Ok + nemo_relay_validate_plugin_config(config.as_ptr(), &mut report_json), + NemoRelayStatus::Ok ); let report = returned_json(report_json); assert!( @@ -54,8 +54,8 @@ fn test_ffi_plugin_registration_validation_and_cleanup() { let mut init_json = ptr::null_mut(); assert_eq!( - nemo_flow_initialize_plugins(config.as_ptr(), &mut init_json), - NemoFlowStatus::Ok + nemo_relay_initialize_plugins(config.as_ptr(), &mut init_json), + NemoRelayStatus::Ok ); let initialized = returned_json(init_json); assert!( @@ -68,20 +68,20 @@ fn test_ffi_plugin_registration_validation_and_cleanup() { let mut active_json = ptr::null_mut(); assert_eq!( - nemo_flow_active_plugin_report_json(&mut active_json), - NemoFlowStatus::Ok + nemo_relay_active_plugin_report_json(&mut active_json), + NemoRelayStatus::Ok ); let active = returned_json(active_json); assert_eq!(active["diagnostics"], initialized["diagnostics"]); - assert_eq!(nemo_flow_clear_plugin_configuration(), NemoFlowStatus::Ok); + assert_eq!(nemo_relay_clear_plugin_configuration(), NemoRelayStatus::Ok); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_plugin(plugin_kind_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind_c.as_ptr()), - NemoFlowStatus::NotFound + nemo_relay_deregister_plugin(plugin_kind_c.as_ptr()), + NemoRelayStatus::NotFound ); } @@ -92,17 +92,17 @@ fn test_ffi_plugin_registration_validation_and_cleanup() { fn test_ffi_plugin_validation_failure_modes_are_reported() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); for (suffix, validate_cb, expected_fragment) in [ ( "invalid", - Some(plugin_validate_invalid as callable::NemoFlowPluginValidateCb), + Some(plugin_validate_invalid as callable::NemoRelayPluginValidateCb), "invalid diagnostics JSON", ), ( "null", - Some(plugin_validate_null as callable::NemoFlowPluginValidateCb), + Some(plugin_validate_null as callable::NemoRelayPluginValidateCb), "returned null", ), ] { @@ -123,20 +123,20 @@ fn test_ffi_plugin_validation_failure_modes_are_reported() { unsafe { assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( plugin_kind_c.as_ptr(), validate_cb, plugin_register_fail, user_data, Some(plugin_free), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut report_json = ptr::null_mut(); assert_eq!( - nemo_flow_validate_plugin_config(config.as_ptr(), &mut report_json), - NemoFlowStatus::Ok + nemo_relay_validate_plugin_config(config.as_ptr(), &mut report_json), + NemoRelayStatus::Ok ); let report = returned_json(report_json); let diag = report["diagnostics"].as_array().unwrap(); @@ -151,8 +151,8 @@ fn test_ffi_plugin_validation_failure_modes_are_reported() { ); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_plugin(plugin_kind_c.as_ptr()), + NemoRelayStatus::Ok ); } } @@ -164,7 +164,7 @@ fn test_ffi_plugin_validation_failure_modes_are_reported() { fn test_ffi_plugin_without_validate_callback_uses_registration_fallback_error() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let plugin_kind = unique_name("ffi_plugin_no_validate"); let plugin_kind_c = cstring(&plugin_kind); @@ -183,42 +183,42 @@ fn test_ffi_plugin_without_validate_callback_uses_registration_fallback_error() unsafe { assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( plugin_kind_c.as_ptr(), None, plugin_register_fail, user_data, Some(plugin_free), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut report_json = ptr::null_mut(); assert_eq!( - nemo_flow_validate_plugin_config(config.as_ptr(), &mut report_json), - NemoFlowStatus::Ok + nemo_relay_validate_plugin_config(config.as_ptr(), &mut report_json), + NemoRelayStatus::Ok ); let report = returned_json(report_json); assert_eq!(report["diagnostics"], json!([])); let mut init_json = ptr::null_mut(); assert_eq!( - nemo_flow_initialize_plugins(config.as_ptr(), &mut init_json), - NemoFlowStatus::Internal + nemo_relay_initialize_plugins(config.as_ptr(), &mut init_json), + NemoRelayStatus::Internal ); let err = read_last_error().expect("expected plugin registration failure message"); assert!(err.contains("register callback failed with status Internal")); let mut active_json = ptr::null_mut(); assert_eq!( - nemo_flow_active_plugin_report_json(&mut active_json), - NemoFlowStatus::Ok + nemo_relay_active_plugin_report_json(&mut active_json), + NemoRelayStatus::Ok ); assert_eq!(returned_json(active_json), Json::Null); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_plugin(plugin_kind_c.as_ptr()), + NemoRelayStatus::Ok ); } @@ -229,7 +229,7 @@ fn test_ffi_plugin_without_validate_callback_uses_registration_fallback_error() fn test_ffi_plugin_registration_failure_prefers_last_error_message() { let _guard = TEST_MUTEX.lock().unwrap(); reset_globals(); - let _ = nemo_flow_clear_plugin_configuration(); + let _ = nemo_relay_clear_plugin_configuration(); let plugin_kind = unique_name("ffi_plugin_last_error"); let plugin_kind_c = cstring(&plugin_kind); @@ -248,20 +248,20 @@ fn test_ffi_plugin_registration_failure_prefers_last_error_message() { unsafe { assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( plugin_kind_c.as_ptr(), None, plugin_register_fail_with_last_error, user_data, Some(plugin_free), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut init_json = ptr::null_mut(); assert_eq!( - nemo_flow_initialize_plugins(config.as_ptr(), &mut init_json), - NemoFlowStatus::Internal + nemo_relay_initialize_plugins(config.as_ptr(), &mut init_json), + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -270,8 +270,8 @@ fn test_ffi_plugin_registration_failure_prefers_last_error_message() { ); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_plugin(plugin_kind_c.as_ptr()), + NemoRelayStatus::Ok ); } @@ -289,17 +289,17 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { unsafe { assert_eq!( - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( ptr::null_mut(), name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( ptr::null_mut(), tool_name.as_ptr(), 1, @@ -307,10 +307,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( ptr::null_mut(), tool_name.as_ptr(), 1, @@ -318,10 +318,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( ptr::null_mut(), tool_name.as_ptr(), 1, @@ -329,10 +329,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -340,10 +340,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -351,10 +351,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -362,10 +362,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_request_intercept( + nemo_relay_plugin_context_register_llm_request_intercept( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -374,10 +374,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_tool_request_intercept( + nemo_relay_plugin_context_register_tool_request_intercept( ptr::null_mut(), tool_name.as_ptr(), 1, @@ -386,10 +386,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_execution_intercept( + nemo_relay_plugin_context_register_llm_execution_intercept( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -397,10 +397,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_llm_stream_execution_intercept( + nemo_relay_plugin_context_register_llm_stream_execution_intercept( ptr::null_mut(), llm_name.as_ptr(), 1, @@ -408,10 +408,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_plugin_context_register_tool_execution_intercept( + nemo_relay_plugin_context_register_tool_execution_intercept( ptr::null_mut(), tool_name.as_ptr(), 1, @@ -419,7 +419,7 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); } @@ -428,17 +428,17 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { unsafe { assert_eq!( - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( &mut ctx, name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, tool_name.as_ptr(), 1, @@ -446,10 +446,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( &mut ctx, tool_name.as_ptr(), 1, @@ -457,10 +457,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( &mut ctx, tool_name.as_ptr(), 1, @@ -468,10 +468,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( &mut ctx, llm_name.as_ptr(), 1, @@ -479,10 +479,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( &mut ctx, llm_name.as_ptr(), 1, @@ -490,10 +490,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( &mut ctx, llm_name.as_ptr(), 1, @@ -501,10 +501,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_request_intercept( + nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, llm_name.as_ptr(), 1, @@ -513,10 +513,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_request_intercept( + nemo_relay_plugin_context_register_tool_request_intercept( &mut ctx, tool_name.as_ptr(), 1, @@ -525,10 +525,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_execution_intercept( + nemo_relay_plugin_context_register_llm_execution_intercept( &mut ctx, llm_name.as_ptr(), 1, @@ -536,10 +536,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_stream_execution_intercept( + nemo_relay_plugin_context_register_llm_stream_execution_intercept( &mut ctx, llm_name.as_ptr(), 1, @@ -547,10 +547,10 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_execution_intercept( + nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, tool_name.as_ptr(), 1, @@ -558,7 +558,7 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); } @@ -584,7 +584,7 @@ fn test_ffi_plugin_context_helpers_cover_null_and_success_paths() { "ffi::tool", ] ); - nemo_flow::plugin::rollback_registrations(&mut registrations); + nemo_relay::plugin::rollback_registrations(&mut registrations); assert!(registrations.is_empty()); } @@ -602,24 +602,24 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { unsafe { assert_eq!( - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( &mut ctx, subscriber_name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( &mut ctx, subscriber_name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -628,7 +628,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, tool_name.as_ptr(), 1, @@ -636,10 +636,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, tool_name.as_ptr(), 2, @@ -647,7 +647,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -656,7 +656,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ); assert_eq!( - nemo_flow_plugin_context_register_llm_request_intercept( + nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, llm_name.as_ptr(), 1, @@ -665,10 +665,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_llm_request_intercept( + nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, llm_name.as_ptr(), 2, @@ -677,7 +677,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -686,7 +686,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ); assert_eq!( - nemo_flow_plugin_context_register_tool_execution_intercept( + nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, tool_name.as_ptr(), 1, @@ -694,10 +694,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_plugin_context_register_tool_execution_intercept( + nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, tool_name.as_ptr(), 2, @@ -705,7 +705,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names() { ptr::null_mut(), None, ), - NemoFlowStatus::Internal + NemoRelayStatus::Internal ); assert!( read_last_error() @@ -728,13 +728,13 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { macro_rules! assert_invalid_name_status { ($call:expr) => {{ - assert_eq!($call, NemoFlowStatus::InvalidUtf8); + assert_eq!($call, NemoRelayStatus::InvalidUtf8); assert!(read_last_error().unwrap_or_default().contains("utf-8")); }}; } unsafe { - assert_invalid_name_status!(nemo_flow_plugin_context_register_subscriber( + assert_invalid_name_status!(nemo_relay_plugin_context_register_subscriber( &mut ctx, invalid_name, subscriber_cb, @@ -742,7 +742,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { None, )); assert_invalid_name_status!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, invalid_name, 1, @@ -752,7 +752,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ) ); assert_invalid_name_status!( - nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( &mut ctx, invalid_name, 1, @@ -762,7 +762,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ) ); assert_invalid_name_status!( - nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( &mut ctx, invalid_name, 1, @@ -772,7 +772,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ) ); assert_invalid_name_status!( - nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( &mut ctx, invalid_name, 1, @@ -782,7 +782,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ) ); assert_invalid_name_status!( - nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( &mut ctx, invalid_name, 1, @@ -792,7 +792,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ) ); assert_invalid_name_status!( - nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( &mut ctx, invalid_name, 1, @@ -801,7 +801,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { None, ) ); - assert_invalid_name_status!(nemo_flow_plugin_context_register_llm_request_intercept( + assert_invalid_name_status!(nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, invalid_name, 1, @@ -810,7 +810,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ptr::null_mut(), None, )); - assert_invalid_name_status!(nemo_flow_plugin_context_register_tool_request_intercept( + assert_invalid_name_status!(nemo_relay_plugin_context_register_tool_request_intercept( &mut ctx, invalid_name, 1, @@ -819,7 +819,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { ptr::null_mut(), None, )); - assert_invalid_name_status!(nemo_flow_plugin_context_register_llm_execution_intercept( + assert_invalid_name_status!(nemo_relay_plugin_context_register_llm_execution_intercept( &mut ctx, invalid_name, 1, @@ -828,7 +828,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { None, )); assert_invalid_name_status!( - nemo_flow_plugin_context_register_llm_stream_execution_intercept( + nemo_relay_plugin_context_register_llm_stream_execution_intercept( &mut ctx, invalid_name, 1, @@ -837,7 +837,7 @@ fn test_ffi_plugin_context_helpers_reject_invalid_utf8_names_in_bulk() { None, ) ); - assert_invalid_name_status!(nemo_flow_plugin_context_register_tool_execution_intercept( + assert_invalid_name_status!(nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, invalid_name, 1, @@ -861,7 +861,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { macro_rules! assert_duplicate { ($call:expr) => {{ - assert_eq!($call, NemoFlowStatus::Internal); + assert_eq!($call, NemoRelayStatus::Internal); assert!( read_last_error() .unwrap_or_default() @@ -873,16 +873,16 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { unsafe { let subscriber_name = cstring("duplicate-subscriber-bulk"); assert_eq!( - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( &mut ctx, subscriber_name.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_duplicate!(nemo_flow_plugin_context_register_subscriber( + assert_duplicate!(nemo_relay_plugin_context_register_subscriber( &mut ctx, subscriber_name.as_ptr(), subscriber_cb, @@ -892,7 +892,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let tool_sanitize_req = cstring("duplicate-tool-sanitize-req-bulk"); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, tool_sanitize_req.as_ptr(), 1, @@ -900,10 +900,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( &mut ctx, tool_sanitize_req.as_ptr(), 2, @@ -915,7 +915,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let tool_sanitize_resp = cstring("duplicate-tool-sanitize-resp-bulk"); assert_eq!( - nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( &mut ctx, tool_sanitize_resp.as_ptr(), 1, @@ -923,10 +923,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( &mut ctx, tool_sanitize_resp.as_ptr(), 2, @@ -938,7 +938,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let tool_conditional = cstring("duplicate-tool-conditional-bulk"); assert_eq!( - nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( &mut ctx, tool_conditional.as_ptr(), 1, @@ -946,10 +946,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( &mut ctx, tool_conditional.as_ptr(), 2, @@ -961,7 +961,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_sanitize_req = cstring("duplicate-llm-sanitize-req-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( &mut ctx, llm_sanitize_req.as_ptr(), 1, @@ -969,10 +969,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( &mut ctx, llm_sanitize_req.as_ptr(), 2, @@ -984,7 +984,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_sanitize_resp = cstring("duplicate-llm-sanitize-resp-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( &mut ctx, llm_sanitize_resp.as_ptr(), 1, @@ -992,10 +992,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( &mut ctx, llm_sanitize_resp.as_ptr(), 2, @@ -1007,7 +1007,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_conditional = cstring("duplicate-llm-conditional-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( &mut ctx, llm_conditional.as_ptr(), 1, @@ -1015,10 +1015,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( &mut ctx, llm_conditional.as_ptr(), 2, @@ -1030,7 +1030,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_request = cstring("duplicate-llm-request-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_request_intercept( + nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, llm_request.as_ptr(), 1, @@ -1039,9 +1039,9 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_duplicate!(nemo_flow_plugin_context_register_llm_request_intercept( + assert_duplicate!(nemo_relay_plugin_context_register_llm_request_intercept( &mut ctx, llm_request.as_ptr(), 2, @@ -1053,7 +1053,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let tool_request = cstring("duplicate-tool-request-bulk"); assert_eq!( - nemo_flow_plugin_context_register_tool_request_intercept( + nemo_relay_plugin_context_register_tool_request_intercept( &mut ctx, tool_request.as_ptr(), 1, @@ -1062,9 +1062,9 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_duplicate!(nemo_flow_plugin_context_register_tool_request_intercept( + assert_duplicate!(nemo_relay_plugin_context_register_tool_request_intercept( &mut ctx, tool_request.as_ptr(), 2, @@ -1076,7 +1076,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_exec = cstring("duplicate-llm-exec-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_execution_intercept( + nemo_relay_plugin_context_register_llm_execution_intercept( &mut ctx, llm_exec.as_ptr(), 1, @@ -1084,9 +1084,9 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_duplicate!(nemo_flow_plugin_context_register_llm_execution_intercept( + assert_duplicate!(nemo_relay_plugin_context_register_llm_execution_intercept( &mut ctx, llm_exec.as_ptr(), 2, @@ -1097,7 +1097,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let llm_stream_exec = cstring("duplicate-llm-stream-exec-bulk"); assert_eq!( - nemo_flow_plugin_context_register_llm_stream_execution_intercept( + nemo_relay_plugin_context_register_llm_stream_execution_intercept( &mut ctx, llm_stream_exec.as_ptr(), 1, @@ -1105,10 +1105,10 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_duplicate!( - nemo_flow_plugin_context_register_llm_stream_execution_intercept( + nemo_relay_plugin_context_register_llm_stream_execution_intercept( &mut ctx, llm_stream_exec.as_ptr(), 2, @@ -1120,7 +1120,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { let tool_exec = cstring("duplicate-tool-exec-bulk"); assert_eq!( - nemo_flow_plugin_context_register_tool_execution_intercept( + nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, tool_exec.as_ptr(), 1, @@ -1128,9 +1128,9 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_duplicate!(nemo_flow_plugin_context_register_tool_execution_intercept( + assert_duplicate!(nemo_relay_plugin_context_register_tool_execution_intercept( &mut ctx, tool_exec.as_ptr(), 2, @@ -1141,7 +1141,7 @@ fn test_ffi_plugin_context_helpers_reject_duplicate_names_in_bulk() { } let mut registrations = inner.into_registrations(); - nemo_flow::plugin::rollback_registrations(&mut registrations); + nemo_relay::plugin::rollback_registrations(&mut registrations); assert!(registrations.is_empty()); } @@ -1156,7 +1156,7 @@ fn test_ffi_specialized_subscriber_and_exporter_default_and_invalid_name_paths() let mut otel_subscriber: *mut FfiOpenTelemetrySubscriber = ptr::null_mut(); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), ptr::null(), ptr::null(), @@ -1168,46 +1168,46 @@ fn test_ffi_specialized_subscriber_and_exporter_default_and_invalid_name_paths() 0, &mut otel_subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let otel_name = cstring(&unique_name("ffi_otel_defaults")); assert_eq!( - nemo_flow_otel_subscriber_register(otel_subscriber, invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_otel_subscriber_register(otel_subscriber, invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_otel_subscriber_register(otel_subscriber, otel_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_register(otel_subscriber, otel_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_register(otel_subscriber, otel_name.as_ptr()), - NemoFlowStatus::Internal + nemo_relay_otel_subscriber_register(otel_subscriber, otel_name.as_ptr()), + NemoRelayStatus::Internal ); assert_eq!( - nemo_flow_otel_subscriber_deregister(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_otel_subscriber_deregister(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_otel_subscriber_deregister(invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_otel_subscriber_deregister(invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_otel_subscriber_deregister(otel_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_deregister(otel_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_force_flush(otel_subscriber), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_force_flush(otel_subscriber), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_shutdown(otel_subscriber), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_shutdown(otel_subscriber), + NemoRelayStatus::Ok ); - nemo_flow_otel_subscriber_free(otel_subscriber); + nemo_relay_otel_subscriber_free(otel_subscriber); let mut oi_subscriber: *mut FfiOpenInferenceSubscriber = ptr::null_mut(); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), ptr::null(), ptr::null(), @@ -1219,83 +1219,83 @@ fn test_ffi_specialized_subscriber_and_exporter_default_and_invalid_name_paths() 0, &mut oi_subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let oi_name = cstring(&unique_name("ffi_oi_defaults")); assert_eq!( - nemo_flow_openinference_subscriber_register(oi_subscriber, invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_openinference_subscriber_register(oi_subscriber, invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_openinference_subscriber_register(oi_subscriber, oi_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_register(oi_subscriber, oi_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_register(oi_subscriber, oi_name.as_ptr()), - NemoFlowStatus::Internal + nemo_relay_openinference_subscriber_register(oi_subscriber, oi_name.as_ptr()), + NemoRelayStatus::Internal ); assert_eq!( - nemo_flow_openinference_subscriber_deregister(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_openinference_subscriber_deregister(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_openinference_subscriber_deregister(invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_openinference_subscriber_deregister(invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_openinference_subscriber_deregister(oi_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_deregister(oi_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_force_flush(oi_subscriber), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_force_flush(oi_subscriber), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_shutdown(oi_subscriber), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_shutdown(oi_subscriber), + NemoRelayStatus::Ok ); - nemo_flow_openinference_subscriber_free(oi_subscriber); + nemo_relay_openinference_subscriber_free(oi_subscriber); let session = cstring("specialized-session"); let agent = cstring("specialized-agent"); let version = cstring("1.0.0"); let mut exporter = ptr::null_mut(); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let exporter_name = cstring(&unique_name("ffi_exporter_defaults")); assert_eq!( - nemo_flow_atif_exporter_register(exporter, invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_atif_exporter_register(exporter, invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::AlreadyExists + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::AlreadyExists ); assert_eq!( - nemo_flow_atif_exporter_deregister(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_deregister(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_deregister(invalid_name), - NemoFlowStatus::InvalidUtf8 + nemo_relay_atif_exporter_deregister(invalid_name), + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_name.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_atif_exporter_free(exporter); + nemo_relay_atif_exporter_free(exporter); } } @@ -1319,7 +1319,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { let mut otel = ptr::null_mut(); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), malformed_json.as_ptr(), @@ -1331,10 +1331,10 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut otel, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), valid_headers.as_ptr(), @@ -1346,7 +1346,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut otel, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); for (transport, endpoint_ptr, service_ptr, namespace_ptr, version_ptr, scope_ptr) in [ ( @@ -1399,7 +1399,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { ), ] { assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( transport, endpoint_ptr, valid_headers.as_ptr(), @@ -1411,13 +1411,13 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut otel, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); } let mut openinference = ptr::null_mut(); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), malformed_json.as_ptr(), @@ -1429,10 +1429,10 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut openinference, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), valid_headers.as_ptr(), @@ -1444,7 +1444,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut openinference, ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); for (transport, endpoint_ptr, service_ptr, namespace_ptr, version_ptr, scope_ptr) in [ ( @@ -1497,7 +1497,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { ), ] { assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( transport, endpoint_ptr, valid_headers.as_ptr(), @@ -1509,7 +1509,7 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { 1, &mut openinference, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); } @@ -1534,31 +1534,31 @@ fn test_ffi_specialized_constructor_invalid_utf8_and_malformed_json_sweep() { ), ] { assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session_ptr, agent_ptr, version_ptr, model_ptr, &mut exporter, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); } let plugin_kind = invalid; assert_eq!( - nemo_flow_register_plugin( + nemo_relay_register_plugin( plugin_kind, None, plugin_register_fail, ptr::null_mut(), None, ), - NemoFlowStatus::InvalidUtf8 + NemoRelayStatus::InvalidUtf8 ); assert_eq!( - nemo_flow_deregister_plugin(plugin_kind), - NemoFlowStatus::InvalidUtf8 + nemo_relay_deregister_plugin(plugin_kind), + NemoRelayStatus::InvalidUtf8 ); } } diff --git a/crates/ffi/tests/unit/api/registry_tests.rs b/crates/ffi/tests/unit/api/registry_tests.rs index 5fcf3f341..a9ff0a924 100644 --- a/crates/ffi/tests/unit/api/registry_tests.rs +++ b/crates/ffi/tests/unit/api/registry_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for registry in the NeMo Flow FFI crate. +//! Unit tests for registry in the NeMo Relay FFI crate. use super::*; @@ -25,7 +25,7 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { let invalid_resource_attributes = cstring(r#"["not-an-object"]"#); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -37,10 +37,10 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( invalid_transport.as_ptr(), endpoint.as_ptr(), headers.as_ptr(), @@ -52,10 +52,10 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), invalid_headers.as_ptr(), @@ -67,10 +67,10 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -82,10 +82,10 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( grpc_transport.as_ptr(), endpoint.as_ptr(), headers.as_ptr(), @@ -97,13 +97,13 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert!(!subscriber.is_null()); - nemo_flow_otel_subscriber_free(subscriber); + nemo_relay_otel_subscriber_free(subscriber); subscriber = ptr::null_mut(); assert_eq!( - nemo_flow_otel_subscriber_create( + nemo_relay_otel_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -115,45 +115,45 @@ fn test_ffi_open_telemetry_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert!(!subscriber.is_null()); let name = cstring(&unique_name("ffi_otel")); assert_eq!( - nemo_flow_otel_subscriber_register(ptr::null(), name.as_ptr()), - NemoFlowStatus::NullPointer + nemo_relay_otel_subscriber_register(ptr::null(), name.as_ptr()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_otel_subscriber_force_flush(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_otel_subscriber_force_flush(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_otel_subscriber_shutdown(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_otel_subscriber_shutdown(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_otel_subscriber_register(subscriber, name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_register(subscriber, name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_deregister(name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_deregister(name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_deregister(name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_deregister(name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_force_flush(subscriber), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_force_flush(subscriber), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_otel_subscriber_shutdown(subscriber), - NemoFlowStatus::Ok + nemo_relay_otel_subscriber_shutdown(subscriber), + NemoRelayStatus::Ok ); - nemo_flow_otel_subscriber_free(subscriber); + nemo_relay_otel_subscriber_free(subscriber); } } @@ -177,7 +177,7 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { let invalid_resource_attributes = cstring(r#"["not-an-object"]"#); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -189,10 +189,10 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, ptr::null_mut(), ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( invalid_transport.as_ptr(), endpoint.as_ptr(), headers.as_ptr(), @@ -204,10 +204,10 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), invalid_headers.as_ptr(), @@ -219,10 +219,10 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -234,10 +234,10 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::InvalidArg + NemoRelayStatus::InvalidArg ); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( grpc_transport.as_ptr(), endpoint.as_ptr(), headers.as_ptr(), @@ -249,13 +249,13 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert!(!subscriber.is_null()); - nemo_flow_openinference_subscriber_free(subscriber); + nemo_relay_openinference_subscriber_free(subscriber); subscriber = ptr::null_mut(); assert_eq!( - nemo_flow_openinference_subscriber_create( + nemo_relay_openinference_subscriber_create( ptr::null(), endpoint.as_ptr(), headers.as_ptr(), @@ -267,45 +267,45 @@ fn test_ffi_open_inference_subscriber_lifecycle_and_errors() { 1250, &mut subscriber, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert!(!subscriber.is_null()); let name = cstring(&unique_name("ffi_openinference")); assert_eq!( - nemo_flow_openinference_subscriber_register(ptr::null(), name.as_ptr()), - NemoFlowStatus::NullPointer + nemo_relay_openinference_subscriber_register(ptr::null(), name.as_ptr()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_openinference_subscriber_force_flush(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_openinference_subscriber_force_flush(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_openinference_subscriber_shutdown(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_openinference_subscriber_shutdown(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_openinference_subscriber_register(subscriber, name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_register(subscriber, name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_deregister(name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_deregister(name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_deregister(name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_deregister(name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_force_flush(subscriber), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_force_flush(subscriber), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_openinference_subscriber_shutdown(subscriber), - NemoFlowStatus::Ok + nemo_relay_openinference_subscriber_shutdown(subscriber), + NemoRelayStatus::Ok ); - nemo_flow_openinference_subscriber_free(subscriber); + nemo_relay_openinference_subscriber_free(subscriber); } } @@ -324,88 +324,88 @@ fn test_ffi_helper_rejection_and_null_name_paths() { let mut null_llm_out = ptr::null_mut(); assert_eq!( - nemo_flow_tool_request_intercepts(ptr::null(), args.as_ptr(), ptr::null_mut()), - NemoFlowStatus::NullPointer + nemo_relay_tool_request_intercepts(ptr::null(), args.as_ptr(), ptr::null_mut()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_tool_request_intercepts( + nemo_relay_tool_request_intercepts( tool_name.as_ptr(), invalid_json.as_ptr(), ptr::null_mut() ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_tool_conditional_execution(ptr::null(), args.as_ptr()), - NemoFlowStatus::NullPointer + nemo_relay_tool_conditional_execution(ptr::null(), args.as_ptr()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_tool_conditional_execution(tool_name.as_ptr(), invalid_json.as_ptr()), - NemoFlowStatus::InvalidJson + nemo_relay_tool_conditional_execution(tool_name.as_ptr(), invalid_json.as_ptr()), + NemoRelayStatus::InvalidJson ); let tool_guard = cstring(&unique_name("ffi_tool_reject")); assert_eq!( - nemo_flow_register_tool_conditional_execution_guardrail( + nemo_relay_register_tool_conditional_execution_guardrail( tool_guard.as_ptr(), 1, tool_reject_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_tool_conditional_execution(tool_name.as_ptr(), args.as_ptr()), - NemoFlowStatus::GuardrailRejected + nemo_relay_tool_conditional_execution(tool_name.as_ptr(), args.as_ptr()), + NemoRelayStatus::GuardrailRejected ); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(tool_guard.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_conditional_execution_guardrail(tool_guard.as_ptr()), + NemoRelayStatus::Ok ); let mut llm_out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_request_intercepts(ptr::null(), request.as_ptr(), &mut llm_out), - NemoFlowStatus::Ok + nemo_relay_llm_request_intercepts(ptr::null(), request.as_ptr(), &mut llm_out), + NemoRelayStatus::Ok ); let llm_json = returned_json(llm_out); assert_eq!(llm_json["content"]["model"], json!("ffi-model")); assert_eq!( - nemo_flow_llm_request_intercepts( + nemo_relay_llm_request_intercepts( llm_name.as_ptr(), invalid_json.as_ptr(), &mut null_llm_out ), - NemoFlowStatus::InvalidJson + NemoRelayStatus::InvalidJson ); assert_eq!( - nemo_flow_llm_conditional_execution(invalid_json.as_ptr()), - NemoFlowStatus::InvalidJson + nemo_relay_llm_conditional_execution(invalid_json.as_ptr()), + NemoRelayStatus::InvalidJson ); let llm_guard = cstring(&unique_name("ffi_llm_reject")); assert_eq!( - nemo_flow_register_llm_conditional_execution_guardrail( + nemo_relay_register_llm_conditional_execution_guardrail( llm_guard.as_ptr(), 1, llm_reject_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_llm_conditional_execution(request.as_ptr()), - NemoFlowStatus::GuardrailRejected + nemo_relay_llm_conditional_execution(request.as_ptr()), + NemoRelayStatus::GuardrailRejected ); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(llm_guard.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_conditional_execution_guardrail(llm_guard.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } @@ -416,12 +416,12 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { macro_rules! assert_invalid_arg { ($expr:expr_2021) => { - assert_eq!($expr, NemoFlowStatus::InvalidArg); + assert_eq!($expr, NemoRelayStatus::InvalidArg); }; } macro_rules! assert_null_pointer { ($expr:expr_2021) => { - assert_eq!($expr, NemoFlowStatus::NullPointer); + assert_eq!($expr, NemoRelayStatus::NullPointer); }; } @@ -430,9 +430,9 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { let scope_name = cstring("ffi_error_sweep_scope"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -440,43 +440,43 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let valid_scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let valid_scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let invalid_scope_uuid = cstring("not-a-uuid"); - assert_null_pointer!(nemo_flow_register_tool_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_register_tool_sanitize_request_guardrail( ptr::null(), 1, tool_request_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_tool_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_deregister_tool_sanitize_request_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_tool_sanitize_response_guardrail( + assert_null_pointer!(nemo_relay_register_tool_sanitize_response_guardrail( ptr::null(), 1, tool_request_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_tool_sanitize_response_guardrail( + assert_null_pointer!(nemo_relay_deregister_tool_sanitize_response_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_tool_conditional_execution_guardrail( + assert_null_pointer!(nemo_relay_register_tool_conditional_execution_guardrail( ptr::null(), 1, tool_allow_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_tool_conditional_execution_guardrail( + assert_null_pointer!(nemo_relay_deregister_tool_conditional_execution_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_tool_request_intercept( + assert_null_pointer!(nemo_relay_register_tool_request_intercept( ptr::null(), 1, false, @@ -484,46 +484,46 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_tool_request_intercept(ptr::null())); - assert_null_pointer!(nemo_flow_register_tool_execution_intercept( + assert_null_pointer!(nemo_relay_deregister_tool_request_intercept(ptr::null())); + assert_null_pointer!(nemo_relay_register_tool_execution_intercept( ptr::null(), 1, tool_exec_intercept_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_tool_execution_intercept(ptr::null())); - assert_null_pointer!(nemo_flow_register_llm_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_deregister_tool_execution_intercept(ptr::null())); + assert_null_pointer!(nemo_relay_register_llm_sanitize_request_guardrail( ptr::null(), 1, llm_request_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_deregister_llm_sanitize_request_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_llm_sanitize_response_guardrail( + assert_null_pointer!(nemo_relay_register_llm_sanitize_response_guardrail( ptr::null(), 1, llm_response_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_sanitize_response_guardrail( + assert_null_pointer!(nemo_relay_deregister_llm_sanitize_response_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_llm_conditional_execution_guardrail( + assert_null_pointer!(nemo_relay_register_llm_conditional_execution_guardrail( ptr::null(), 1, llm_allow_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_conditional_execution_guardrail( + assert_null_pointer!(nemo_relay_deregister_llm_conditional_execution_guardrail( ptr::null() )); - assert_null_pointer!(nemo_flow_register_llm_request_intercept( + assert_null_pointer!(nemo_relay_register_llm_request_intercept( ptr::null(), 1, false, @@ -531,34 +531,34 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_request_intercept(ptr::null())); - assert_null_pointer!(nemo_flow_register_llm_execution_intercept( + assert_null_pointer!(nemo_relay_deregister_llm_request_intercept(ptr::null())); + assert_null_pointer!(nemo_relay_register_llm_execution_intercept( ptr::null(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_execution_intercept(ptr::null())); - assert_null_pointer!(nemo_flow_register_llm_stream_execution_intercept( + assert_null_pointer!(nemo_relay_deregister_llm_execution_intercept(ptr::null())); + assert_null_pointer!(nemo_relay_register_llm_stream_execution_intercept( ptr::null(), 1, llm_exec_intercept_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_llm_stream_execution_intercept( + assert_null_pointer!(nemo_relay_deregister_llm_stream_execution_intercept( ptr::null() )); - assert_null_pointer!(nemo_flow_register_subscriber( + assert_null_pointer!(nemo_relay_register_subscriber( ptr::null(), subscriber_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_deregister_subscriber(ptr::null())); + assert_null_pointer!(nemo_relay_deregister_subscriber(ptr::null())); - assert_invalid_arg!(nemo_flow_scope_register_tool_sanitize_request_guardrail( + assert_invalid_arg!(nemo_relay_scope_register_tool_sanitize_request_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -566,11 +566,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_invalid_arg!(nemo_flow_scope_deregister_tool_sanitize_request_guardrail( + assert_invalid_arg!(nemo_relay_scope_deregister_tool_sanitize_request_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), )); - assert_null_pointer!(nemo_flow_scope_register_tool_sanitize_response_guardrail( + assert_null_pointer!(nemo_relay_scope_register_tool_sanitize_response_guardrail( valid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -578,12 +578,14 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_scope_deregister_tool_sanitize_response_guardrail( - valid_scope_uuid.as_ptr(), - ptr::null(), - )); + assert_null_pointer!( + nemo_relay_scope_deregister_tool_sanitize_response_guardrail( + valid_scope_uuid.as_ptr(), + ptr::null(), + ) + ); assert_invalid_arg!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -593,12 +595,12 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ) ); assert_invalid_arg!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), ) ); - assert_null_pointer!(nemo_flow_scope_register_tool_request_intercept( + assert_null_pointer!(nemo_relay_scope_register_tool_request_intercept( valid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -607,11 +609,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_scope_deregister_tool_request_intercept( + assert_null_pointer!(nemo_relay_scope_deregister_tool_request_intercept( valid_scope_uuid.as_ptr(), ptr::null(), )); - assert_invalid_arg!(nemo_flow_scope_register_tool_execution_intercept( + assert_invalid_arg!(nemo_relay_scope_register_tool_execution_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -619,11 +621,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_invalid_arg!(nemo_flow_scope_deregister_tool_execution_intercept( + assert_invalid_arg!(nemo_relay_scope_deregister_tool_execution_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), )); - assert_null_pointer!(nemo_flow_scope_register_llm_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_scope_register_llm_sanitize_request_guardrail( valid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -631,11 +633,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_scope_deregister_llm_sanitize_request_guardrail( + assert_null_pointer!(nemo_relay_scope_deregister_llm_sanitize_request_guardrail( valid_scope_uuid.as_ptr(), ptr::null(), )); - assert_invalid_arg!(nemo_flow_scope_register_llm_sanitize_response_guardrail( + assert_invalid_arg!(nemo_relay_scope_register_llm_sanitize_response_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -643,12 +645,12 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_invalid_arg!(nemo_flow_scope_deregister_llm_sanitize_response_guardrail( + assert_invalid_arg!(nemo_relay_scope_deregister_llm_sanitize_response_guardrail( invalid_scope_uuid.as_ptr(), ptr::null(), )); assert_null_pointer!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( valid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -658,12 +660,12 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ) ); assert_null_pointer!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( valid_scope_uuid.as_ptr(), ptr::null(), ) ); - assert_invalid_arg!(nemo_flow_scope_register_llm_request_intercept( + assert_invalid_arg!(nemo_relay_scope_register_llm_request_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -672,11 +674,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_invalid_arg!(nemo_flow_scope_deregister_llm_request_intercept( + assert_invalid_arg!(nemo_relay_scope_deregister_llm_request_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), )); - assert_null_pointer!(nemo_flow_scope_register_llm_execution_intercept( + assert_null_pointer!(nemo_relay_scope_register_llm_execution_intercept( valid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -684,11 +686,11 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_scope_deregister_llm_execution_intercept( + assert_null_pointer!(nemo_relay_scope_deregister_llm_execution_intercept( valid_scope_uuid.as_ptr(), ptr::null(), )); - assert_invalid_arg!(nemo_flow_scope_register_llm_stream_execution_intercept( + assert_invalid_arg!(nemo_relay_scope_register_llm_stream_execution_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), 1, @@ -696,25 +698,28 @@ fn test_ffi_registration_name_and_uuid_error_sweep() { ptr::null_mut(), None, )); - assert_invalid_arg!(nemo_flow_scope_deregister_llm_stream_execution_intercept( + assert_invalid_arg!(nemo_relay_scope_deregister_llm_stream_execution_intercept( invalid_scope_uuid.as_ptr(), ptr::null(), )); - assert_null_pointer!(nemo_flow_scope_register_subscriber( + assert_null_pointer!(nemo_relay_scope_register_subscriber( valid_scope_uuid.as_ptr(), ptr::null(), subscriber_cb, ptr::null_mut(), None, )); - assert_null_pointer!(nemo_flow_scope_deregister_subscriber( + assert_null_pointer!(nemo_relay_scope_deregister_subscriber( valid_scope_uuid.as_ptr(), ptr::null(), )); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -725,7 +730,7 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { macro_rules! assert_already_exists { ($expr:expr_2021) => { - assert_eq!($expr, NemoFlowStatus::AlreadyExists); + assert_eq!($expr, NemoRelayStatus::AlreadyExists); }; } @@ -753,9 +758,9 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { let scope_name = cstring("ffi_duplicate_scope"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -763,22 +768,22 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); let tool_cond = cstring(&unique_name("dup_tool_cond")); assert_eq!( - nemo_flow_register_tool_conditional_execution_guardrail( + nemo_relay_register_tool_conditional_execution_guardrail( tool_cond.as_ptr(), 1, tool_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_tool_conditional_execution_guardrail( + assert_already_exists!(nemo_relay_register_tool_conditional_execution_guardrail( tool_cond.as_ptr(), 1, tool_allow_cb, @@ -786,13 +791,13 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_deregister_tool_conditional_execution_guardrail(tool_cond.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_conditional_execution_guardrail(tool_cond.as_ptr()), + NemoRelayStatus::Ok ); let tool_req = cstring(&unique_name("dup_tool_req")); assert_eq!( - nemo_flow_register_tool_request_intercept( + nemo_relay_register_tool_request_intercept( tool_req.as_ptr(), 1, false, @@ -800,9 +805,9 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_tool_request_intercept( + assert_already_exists!(nemo_relay_register_tool_request_intercept( tool_req.as_ptr(), 1, false, @@ -811,22 +816,22 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_deregister_tool_request_intercept(tool_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_tool_request_intercept(tool_req.as_ptr()), + NemoRelayStatus::Ok ); let llm_san_resp = cstring(&unique_name("dup_llm_san_resp")); assert_eq!( - nemo_flow_register_llm_sanitize_response_guardrail( + nemo_relay_register_llm_sanitize_response_guardrail( llm_san_resp.as_ptr(), 1, llm_response_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_sanitize_response_guardrail( + assert_already_exists!(nemo_relay_register_llm_sanitize_response_guardrail( llm_san_resp.as_ptr(), 1, llm_response_cb, @@ -834,22 +839,22 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_deregister_llm_sanitize_response_guardrail(llm_san_resp.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_sanitize_response_guardrail(llm_san_resp.as_ptr()), + NemoRelayStatus::Ok ); let llm_cond = cstring(&unique_name("dup_llm_cond")); assert_eq!( - nemo_flow_register_llm_conditional_execution_guardrail( + nemo_relay_register_llm_conditional_execution_guardrail( llm_cond.as_ptr(), 1, llm_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_conditional_execution_guardrail( + assert_already_exists!(nemo_relay_register_llm_conditional_execution_guardrail( llm_cond.as_ptr(), 1, llm_allow_cb, @@ -857,13 +862,13 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(llm_cond.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_conditional_execution_guardrail(llm_cond.as_ptr()), + NemoRelayStatus::Ok ); let llm_req = cstring(&unique_name("dup_llm_req")); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( llm_req.as_ptr(), 1, false, @@ -871,9 +876,9 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_llm_request_intercept( + assert_already_exists!(nemo_relay_register_llm_request_intercept( llm_req.as_ptr(), 1, false, @@ -882,34 +887,34 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_deregister_llm_request_intercept(llm_req.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_request_intercept(llm_req.as_ptr()), + NemoRelayStatus::Ok ); let subscriber = cstring(&unique_name("dup_subscriber")); assert_eq!( - nemo_flow_register_subscriber( + nemo_relay_register_subscriber( subscriber.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_register_subscriber( + assert_already_exists!(nemo_relay_register_subscriber( subscriber.as_ptr(), subscriber_cb, ptr::null_mut(), None, )); assert_eq!( - nemo_flow_deregister_subscriber(subscriber.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_subscriber(subscriber.as_ptr()), + NemoRelayStatus::Ok ); let scope_tool_cond = cstring(&unique_name("dup_scope_tool_cond")); assert_eq!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_tool_cond.as_ptr(), 1, @@ -917,10 +922,10 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_already_exists!( - nemo_flow_scope_register_tool_conditional_execution_guardrail( + nemo_relay_scope_register_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_tool_cond.as_ptr(), 1, @@ -930,16 +935,16 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ) ); assert_eq!( - nemo_flow_scope_deregister_tool_conditional_execution_guardrail( + nemo_relay_scope_deregister_tool_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_tool_cond.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_tool_req = cstring(&unique_name("dup_scope_tool_req")); assert_eq!( - nemo_flow_scope_register_tool_request_intercept( + nemo_relay_scope_register_tool_request_intercept( scope_uuid.as_ptr(), scope_tool_req.as_ptr(), 1, @@ -948,9 +953,9 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_tool_request_intercept( + assert_already_exists!(nemo_relay_scope_register_tool_request_intercept( scope_uuid.as_ptr(), scope_tool_req.as_ptr(), 1, @@ -960,16 +965,16 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_scope_deregister_tool_request_intercept( + nemo_relay_scope_deregister_tool_request_intercept( scope_uuid.as_ptr(), scope_tool_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_cond = cstring(&unique_name("dup_scope_llm_cond")); assert_eq!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_llm_cond.as_ptr(), 1, @@ -977,10 +982,10 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_already_exists!( - nemo_flow_scope_register_llm_conditional_execution_guardrail( + nemo_relay_scope_register_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_llm_cond.as_ptr(), 1, @@ -990,16 +995,16 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ) ); assert_eq!( - nemo_flow_scope_deregister_llm_conditional_execution_guardrail( + nemo_relay_scope_deregister_llm_conditional_execution_guardrail( scope_uuid.as_ptr(), scope_llm_cond.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_llm_req = cstring(&unique_name("dup_scope_llm_req")); assert_eq!( - nemo_flow_scope_register_llm_request_intercept( + nemo_relay_scope_register_llm_request_intercept( scope_uuid.as_ptr(), scope_llm_req.as_ptr(), 1, @@ -1008,9 +1013,9 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_llm_request_intercept( + assert_already_exists!(nemo_relay_scope_register_llm_request_intercept( scope_uuid.as_ptr(), scope_llm_req.as_ptr(), 1, @@ -1020,25 +1025,25 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_scope_deregister_llm_request_intercept( + nemo_relay_scope_deregister_llm_request_intercept( scope_uuid.as_ptr(), scope_llm_req.as_ptr(), ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let scope_subscriber = cstring(&unique_name("dup_scope_subscriber")); assert_eq!( - nemo_flow_scope_register_subscriber( + nemo_relay_scope_register_subscriber( scope_uuid.as_ptr(), scope_subscriber.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_scope_register_subscriber( + assert_already_exists!(nemo_relay_scope_register_subscriber( scope_uuid.as_ptr(), scope_subscriber.as_ptr(), subscriber_cb, @@ -1046,8 +1051,8 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { None, )); assert_eq!( - nemo_flow_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), - NemoFlowStatus::Ok + nemo_relay_scope_deregister_subscriber(scope_uuid.as_ptr(), scope_subscriber.as_ptr(),), + NemoRelayStatus::Ok ); let session = cstring("dup-session"); @@ -1055,67 +1060,67 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { let version = cstring("1.0.0"); let mut exporter = ptr::null_mut(); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( ptr::null(), agent.as_ptr(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), ptr::null(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), ptr::null(), ptr::null(), &mut exporter, ), - NemoFlowStatus::NullPointer + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_register(exporter, ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_register(exporter, ptr::null()), + NemoRelayStatus::NullPointer ); let exporter_name = cstring(&unique_name("dup_exporter_subscriber")); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::Ok ); - assert_already_exists!(nemo_flow_atif_exporter_register( + assert_already_exists!(nemo_relay_atif_exporter_register( exporter, exporter_name.as_ptr(), )); assert_eq!( - nemo_flow_atif_exporter_deregister(ptr::null()), - NemoFlowStatus::NullPointer + nemo_relay_atif_exporter_deregister(ptr::null()), + NemoRelayStatus::NullPointer ); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_name.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_atif_exporter_free(exporter); + nemo_relay_atif_exporter_free(exporter); let args = cstring(r#"{"value":1}"#); let tool_intercept_json = take_string(tool_exec_intercept_cb( @@ -1143,9 +1148,12 @@ fn test_ffi_duplicate_registration_sweep_and_helper_callbacks() { json!({"role":"assistant","content":"next","tool_calls":[]}) ); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -1159,14 +1167,14 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { let name = cstring(&unique_name($prefix)); assert_eq!( $register(name.as_ptr(), 1, $cb, ptr::null_mut(), None), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $register(name.as_ptr(), 1, $cb, ptr::null_mut(), None), - NemoFlowStatus::AlreadyExists + NemoRelayStatus::AlreadyExists ); - assert_eq!($deregister(name.as_ptr()), NemoFlowStatus::Ok); - assert_eq!($deregister(name.as_ptr()), NemoFlowStatus::Ok); + assert_eq!($deregister(name.as_ptr()), NemoRelayStatus::Ok); + assert_eq!($deregister(name.as_ptr()), NemoRelayStatus::Ok); }}; } @@ -1175,14 +1183,14 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { let name = cstring(&unique_name($prefix)); assert_eq!( $register(name.as_ptr(), 1, $cb, ptr::null_mut(), None), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $register(name.as_ptr(), 1, $cb, ptr::null_mut(), None), - NemoFlowStatus::AlreadyExists + NemoRelayStatus::AlreadyExists ); - assert_eq!($deregister(name.as_ptr()), NemoFlowStatus::Ok); - assert_eq!($deregister(name.as_ptr()), NemoFlowStatus::Ok); + assert_eq!($deregister(name.as_ptr()), NemoRelayStatus::Ok); + assert_eq!($deregister(name.as_ptr()), NemoRelayStatus::Ok); }}; } @@ -1198,7 +1206,7 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $register( @@ -1209,15 +1217,15 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { ptr::null_mut(), None, ), - NemoFlowStatus::AlreadyExists + NemoRelayStatus::AlreadyExists ); assert_eq!( $deregister($scope_uuid.as_ptr(), name.as_ptr()), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $deregister($scope_uuid.as_ptr(), name.as_ptr()), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); }}; } @@ -1234,7 +1242,7 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $register( @@ -1245,15 +1253,15 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { ptr::null_mut(), None, ), - NemoFlowStatus::AlreadyExists + NemoRelayStatus::AlreadyExists ); assert_eq!( $deregister($scope_uuid.as_ptr(), name.as_ptr()), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( $deregister($scope_uuid.as_ptr(), name.as_ptr()), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); }}; } @@ -1263,9 +1271,9 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { let scope_name = cstring("ffi_table_sweep_scope"); let mut scope = ptr::null_mut(); assert_eq!( - nemo_flow_push_scope( + nemo_relay_push_scope( scope_name.as_ptr(), - NemoFlowScopeType::Function, + NemoRelayScopeType::Function, ptr::null(), 0, ptr::null(), @@ -1273,81 +1281,81 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { ptr::null(), &mut scope, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - let scope_uuid = cstring(&take_string(nemo_flow_scope_handle_uuid(scope)).unwrap()); + let scope_uuid = cstring(&take_string(nemo_relay_scope_handle_uuid(scope)).unwrap()); assert_global_guardrail_sweep!( "table_tool_san_resp", - nemo_flow_register_tool_sanitize_response_guardrail, - nemo_flow_deregister_tool_sanitize_response_guardrail, + nemo_relay_register_tool_sanitize_response_guardrail, + nemo_relay_deregister_tool_sanitize_response_guardrail, tool_request_cb ); assert_global_execution_sweep!( "table_tool_exec", - nemo_flow_register_tool_execution_intercept, - nemo_flow_deregister_tool_execution_intercept, + nemo_relay_register_tool_execution_intercept, + nemo_relay_deregister_tool_execution_intercept, tool_exec_intercept_cb ); assert_global_guardrail_sweep!( "table_llm_san_req", - nemo_flow_register_llm_sanitize_request_guardrail, - nemo_flow_deregister_llm_sanitize_request_guardrail, + nemo_relay_register_llm_sanitize_request_guardrail, + nemo_relay_deregister_llm_sanitize_request_guardrail, llm_request_cb ); assert_global_execution_sweep!( "table_llm_exec", - nemo_flow_register_llm_execution_intercept, - nemo_flow_deregister_llm_execution_intercept, + nemo_relay_register_llm_execution_intercept, + nemo_relay_deregister_llm_execution_intercept, llm_exec_intercept_cb ); assert_global_execution_sweep!( "table_llm_stream_exec", - nemo_flow_register_llm_stream_execution_intercept, - nemo_flow_deregister_llm_stream_execution_intercept, + nemo_relay_register_llm_stream_execution_intercept, + nemo_relay_deregister_llm_stream_execution_intercept, llm_exec_intercept_cb ); assert_scope_guardrail_sweep!( scope_uuid, "table_scope_tool_san_resp", - nemo_flow_scope_register_tool_sanitize_response_guardrail, - nemo_flow_scope_deregister_tool_sanitize_response_guardrail, + nemo_relay_scope_register_tool_sanitize_response_guardrail, + nemo_relay_scope_deregister_tool_sanitize_response_guardrail, tool_request_cb ); assert_scope_execution_sweep!( scope_uuid, "table_scope_tool_exec", - nemo_flow_scope_register_tool_execution_intercept, - nemo_flow_scope_deregister_tool_execution_intercept, + nemo_relay_scope_register_tool_execution_intercept, + nemo_relay_scope_deregister_tool_execution_intercept, tool_exec_intercept_cb ); assert_scope_guardrail_sweep!( scope_uuid, "table_scope_llm_san_req", - nemo_flow_scope_register_llm_sanitize_request_guardrail, - nemo_flow_scope_deregister_llm_sanitize_request_guardrail, + nemo_relay_scope_register_llm_sanitize_request_guardrail, + nemo_relay_scope_deregister_llm_sanitize_request_guardrail, llm_request_cb ); assert_scope_guardrail_sweep!( scope_uuid, "table_scope_llm_san_resp", - nemo_flow_scope_register_llm_sanitize_response_guardrail, - nemo_flow_scope_deregister_llm_sanitize_response_guardrail, + nemo_relay_scope_register_llm_sanitize_response_guardrail, + nemo_relay_scope_deregister_llm_sanitize_response_guardrail, llm_response_cb ); assert_scope_execution_sweep!( scope_uuid, "table_scope_llm_exec", - nemo_flow_scope_register_llm_execution_intercept, - nemo_flow_scope_deregister_llm_execution_intercept, + nemo_relay_scope_register_llm_execution_intercept, + nemo_relay_scope_deregister_llm_execution_intercept, llm_exec_intercept_cb ); assert_scope_execution_sweep!( scope_uuid, "table_scope_llm_stream_exec", - nemo_flow_scope_register_llm_stream_execution_intercept, - nemo_flow_scope_deregister_llm_stream_execution_intercept, + nemo_relay_scope_register_llm_stream_execution_intercept, + nemo_relay_scope_deregister_llm_stream_execution_intercept, llm_exec_intercept_cb ); @@ -1357,32 +1365,35 @@ fn test_ffi_registration_table_sweep_for_remaining_wrappers() { let version = cstring("1.0.0"); let exporter_name = cstring(&unique_name("table_exporter_subscriber")); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), ptr::null(), &mut exporter, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_register(exporter, exporter_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_name.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_name.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_name.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_atif_exporter_free(exporter); + nemo_relay_atif_exporter_free(exporter); - assert_eq!(nemo_flow_pop_scope(scope, ptr::null()), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(scope); - nemo_flow_scope_stack_free(stack); + assert_eq!( + nemo_relay_pop_scope(scope, ptr::null()), + NemoRelayStatus::Ok + ); + nemo_relay_scope_handle_free(scope); + nemo_relay_scope_stack_free(stack); } } @@ -1397,23 +1408,23 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { let subscriber_name = unique_name("ffi_llm_subscriber"); let subscriber_name_c = cstring(&subscriber_name); assert_eq!( - nemo_flow_register_subscriber( + nemo_relay_register_subscriber( subscriber_name_c.as_ptr(), subscriber_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut root = ptr::null_mut(); - assert_eq!(nemo_flow_get_handle(&mut root), NemoFlowStatus::Ok); - nemo_flow_scope_handle_free(root); + assert_eq!(nemo_relay_get_handle(&mut root), NemoRelayStatus::Ok); + nemo_relay_scope_handle_free(root); let intercept_name = unique_name("ffi_llm_intercept"); let intercept_name_c = cstring(&intercept_name); assert_eq!( - nemo_flow_register_llm_request_intercept( + nemo_relay_register_llm_request_intercept( intercept_name_c.as_ptr(), 1, false, @@ -1421,33 +1432,33 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let conditional_name = unique_name("ffi_llm_conditional"); let conditional_name_c = cstring(&conditional_name); assert_eq!( - nemo_flow_register_llm_conditional_execution_guardrail( + nemo_relay_register_llm_conditional_execution_guardrail( conditional_name_c.as_ptr(), 1, llm_allow_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let sanitize_name = unique_name("ffi_llm_sanitize"); let sanitize_name_c = cstring(&sanitize_name); assert_eq!( - nemo_flow_register_llm_sanitize_response_guardrail( + nemo_relay_register_llm_sanitize_response_guardrail( sanitize_name_c.as_ptr(), 1, llm_response_cb, ptr::null_mut(), None, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut exporter: *mut FfiAtifExporter = ptr::null_mut(); @@ -1456,21 +1467,21 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { let version = cstring("1.0.0"); let model_name = cstring("ffi-model"); assert_eq!( - nemo_flow_atif_exporter_create( + nemo_relay_atif_exporter_create( session.as_ptr(), agent.as_ptr(), version.as_ptr(), model_name.as_ptr(), &mut exporter, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let exporter_sub = unique_name("ffi_exporter"); let exporter_sub_c = cstring(&exporter_sub); assert_eq!( - nemo_flow_atif_exporter_register(exporter, exporter_sub_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_register(exporter, exporter_sub_c.as_ptr()), + NemoRelayStatus::Ok ); let llm_name = cstring("ffi_llm"); @@ -1479,40 +1490,40 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { ); let headers = cstring(r#"{"Authorization":"Bearer token"}"#); let content = cstring(r#"{"messages":[],"model":"ffi-model"}"#); - let llm_request = nemo_flow_llm_request_new(headers.as_ptr(), content.as_ptr()); + let llm_request = nemo_relay_llm_request_new(headers.as_ptr(), content.as_ptr()); assert!(!llm_request.is_null()); assert_eq!( serde_json::from_str::( - &take_string(nemo_flow_llm_request_headers(llm_request)).unwrap() + &take_string(nemo_relay_llm_request_headers(llm_request)).unwrap() ) .unwrap(), json!({"Authorization": "Bearer token"}) ); assert_eq!( serde_json::from_str::( - &take_string(nemo_flow_llm_request_content(llm_request)).unwrap() + &take_string(nemo_relay_llm_request_content(llm_request)).unwrap() ) .unwrap(), json!({"messages": [], "model": "ffi-model"}) ); - nemo_flow_llm_request_free(llm_request); + nemo_relay_llm_request_free(llm_request); let mut helper_out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_request_intercepts(llm_name.as_ptr(), request.as_ptr(), &mut helper_out), - NemoFlowStatus::Ok + nemo_relay_llm_request_intercepts(llm_name.as_ptr(), request.as_ptr(), &mut helper_out), + NemoRelayStatus::Ok ); let helper_json = returned_json(helper_out); assert_eq!(helper_json["content"]["intercepted"], json!(true)); assert_eq!( - nemo_flow_llm_conditional_execution(request.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_llm_conditional_execution(request.as_ptr()), + NemoRelayStatus::Ok ); let mut handle: *mut FfiLLMHandle = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call( + nemo_relay_llm_call( llm_name.as_ptr(), request.as_ptr(), ptr::null(), @@ -1522,26 +1533,26 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { model_name.as_ptr(), &mut handle, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); - assert!(take_string(nemo_flow_llm_handle_uuid(handle)).is_some()); + assert!(take_string(nemo_relay_llm_handle_uuid(handle)).is_some()); assert_eq!( - take_string(nemo_flow_llm_handle_name(handle)).unwrap(), + take_string(nemo_relay_llm_handle_name(handle)).unwrap(), "ffi_llm" ); - assert_eq!(nemo_flow_llm_handle_attributes(handle), 2); - assert!(take_string(nemo_flow_llm_handle_parent_uuid(handle)).is_some()); + assert_eq!(nemo_relay_llm_handle_attributes(handle), 2); + assert!(take_string(nemo_relay_llm_handle_parent_uuid(handle)).is_some()); let response = cstring(r#"{"content":"manual end","role":"assistant","tool_calls":[]}"#); assert_eq!( - nemo_flow_llm_call_end(handle, response.as_ptr(), ptr::null(), ptr::null()), - NemoFlowStatus::Ok + nemo_relay_llm_call_end(handle, response.as_ptr(), ptr::null(), ptr::null()), + NemoRelayStatus::Ok ); - nemo_flow_llm_handle_free(handle); + nemo_relay_llm_handle_free(handle); let mut execute_out = ptr::null_mut(); assert_eq!( - nemo_flow_llm_call_execute( + nemo_relay_llm_call_execute( llm_name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1559,7 +1570,7 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { ptr::null(), &mut execute_out, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let execute_json = returned_json(execute_out); assert_eq!(execute_json["content"], json!("hello from ffi")); @@ -1578,7 +1589,7 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { let mut stream = ptr::null_mut(); assert_eq!( - nemo_flow_llm_stream_call_execute( + nemo_relay_llm_stream_call_execute( llm_name.as_ptr(), request.as_ptr(), llm_exec_cb, @@ -1598,58 +1609,61 @@ fn test_ffi_llm_execute_stream_and_atif_exporter() { ptr::null(), &mut stream, ), - NemoFlowStatus::Ok + NemoRelayStatus::Ok ); let mut chunk = ptr::null_mut(); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 1); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 1); let chunk_json = returned_json(chunk); assert_eq!(chunk_json["content"], json!("hello from ffi")); - assert_eq!(nemo_flow_stream_next(stream, &mut chunk), 0); - nemo_flow_stream_free(stream); + assert_eq!(nemo_relay_stream_next(stream, &mut chunk), 0); + nemo_relay_stream_free(stream); assert_eq!(lock_unpoisoned(collected_chunks()).len(), 1); assert_eq!(*lock_unpoisoned(finalizer_calls()), 1); let mut exported = ptr::null_mut(); assert_eq!( - nemo_flow_atif_exporter_export(exporter, &mut exported), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_export(exporter, &mut exported), + NemoRelayStatus::Ok ); let trajectory = returned_json(exported); assert_eq!(trajectory["schema_version"], json!("ATIF-v1.6")); assert!(trajectory["steps"].as_array().unwrap().len() >= 4); - assert_eq!(nemo_flow_atif_exporter_clear(exporter), NemoFlowStatus::Ok); + assert_eq!( + nemo_relay_atif_exporter_clear(exporter), + NemoRelayStatus::Ok + ); let mut cleared = ptr::null_mut(); assert_eq!( - nemo_flow_atif_exporter_export(exporter, &mut cleared), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_export(exporter, &mut cleared), + NemoRelayStatus::Ok ); let cleared_json = returned_json(cleared); assert_eq!(cleared_json["steps"].as_array().unwrap().len(), 0); assert_eq!( - nemo_flow_atif_exporter_deregister(exporter_sub_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_atif_exporter_deregister(exporter_sub_c.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_atif_exporter_free(exporter); + nemo_relay_atif_exporter_free(exporter); assert_eq!( - nemo_flow_deregister_subscriber(subscriber_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_subscriber(subscriber_name_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_request_intercept(intercept_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_request_intercept(intercept_name_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_conditional_execution_guardrail(conditional_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_conditional_execution_guardrail(conditional_name_c.as_ptr()), + NemoRelayStatus::Ok ); assert_eq!( - nemo_flow_deregister_llm_sanitize_response_guardrail(sanitize_name_c.as_ptr()), - NemoFlowStatus::Ok + nemo_relay_deregister_llm_sanitize_response_guardrail(sanitize_name_c.as_ptr()), + NemoRelayStatus::Ok ); - nemo_flow_scope_stack_free(stack); + nemo_relay_scope_stack_free(stack); } } diff --git a/crates/ffi/tests/unit/api_tests.rs b/crates/ffi/tests/unit/api_tests.rs index cbc498cfd..2f3af3b2d 100644 --- a/crates/ffi/tests/unit/api_tests.rs +++ b/crates/ffi/tests/unit/api_tests.rs @@ -1,35 +1,36 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for api in the NeMo Flow FFI crate. +//! Unit tests for api in the NeMo Relay FFI crate. use super::*; use std::ffi::{CStr, CString}; use std::ptr; use std::sync::{Mutex, OnceLock}; -use nemo_flow::plugin::PluginRegistrationContext; +use nemo_relay::plugin::PluginRegistrationContext; use serde_json::{Value as Json, json}; use uuid::Uuid; -use crate::callable::{NemoFlowLlmExecNextFn, NemoFlowToolExecNextFn}; -use crate::convert::nemo_flow_string_free; -use crate::error::{NemoFlowStatus, nemo_flow_last_error}; +use crate::callable::{NemoRelayLlmExecNextFn, NemoRelayToolExecNextFn}; +use crate::convert::nemo_relay_string_free; +use crate::error::{NemoRelayStatus, nemo_relay_last_error}; use crate::types::{ FfiAtifExporter, FfiEvent, FfiLLMHandle, FfiLLMRequest, FfiOpenTelemetrySubscriber, - FfiScopeStack, FfiToolHandle, nemo_flow_atif_exporter_free, nemo_flow_event_data, - nemo_flow_event_input, nemo_flow_event_metadata, nemo_flow_event_model_name, - nemo_flow_event_name, nemo_flow_event_output, nemo_flow_event_parent_uuid, - nemo_flow_event_scope_type, nemo_flow_event_timestamp, nemo_flow_event_tool_call_id, - nemo_flow_event_uuid, nemo_flow_llm_handle_attributes, nemo_flow_llm_handle_free, - nemo_flow_llm_handle_name, nemo_flow_llm_handle_parent_uuid, nemo_flow_llm_handle_uuid, - nemo_flow_llm_request_content, nemo_flow_llm_request_free, nemo_flow_llm_request_headers, - nemo_flow_llm_request_new, nemo_flow_otel_subscriber_free, nemo_flow_scope_handle_attributes, - nemo_flow_scope_handle_data, nemo_flow_scope_handle_free, nemo_flow_scope_handle_metadata, - nemo_flow_scope_handle_name, nemo_flow_scope_handle_parent_uuid, - nemo_flow_scope_handle_scope_type, nemo_flow_scope_handle_uuid, nemo_flow_scope_stack_free, - nemo_flow_tool_handle_attributes, nemo_flow_tool_handle_free, nemo_flow_tool_handle_name, - nemo_flow_tool_handle_parent_uuid, nemo_flow_tool_handle_uuid, + FfiScopeStack, FfiToolHandle, nemo_relay_atif_exporter_free, nemo_relay_event_data, + nemo_relay_event_input, nemo_relay_event_metadata, nemo_relay_event_model_name, + nemo_relay_event_name, nemo_relay_event_output, nemo_relay_event_parent_uuid, + nemo_relay_event_scope_type, nemo_relay_event_timestamp, nemo_relay_event_tool_call_id, + nemo_relay_event_uuid, nemo_relay_llm_handle_attributes, nemo_relay_llm_handle_free, + nemo_relay_llm_handle_name, nemo_relay_llm_handle_parent_uuid, nemo_relay_llm_handle_uuid, + nemo_relay_llm_request_content, nemo_relay_llm_request_free, nemo_relay_llm_request_headers, + nemo_relay_llm_request_new, nemo_relay_otel_subscriber_free, + nemo_relay_scope_handle_attributes, nemo_relay_scope_handle_data, nemo_relay_scope_handle_free, + nemo_relay_scope_handle_metadata, nemo_relay_scope_handle_name, + nemo_relay_scope_handle_parent_uuid, nemo_relay_scope_handle_scope_type, + nemo_relay_scope_handle_uuid, nemo_relay_scope_stack_free, nemo_relay_tool_handle_attributes, + nemo_relay_tool_handle_free, nemo_relay_tool_handle_name, nemo_relay_tool_handle_parent_uuid, + nemo_relay_tool_handle_uuid, }; use crate::{api, callable, types}; @@ -68,18 +69,18 @@ fn cstring(s: &str) -> CString { } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_push_scope( +unsafe fn nemo_relay_push_scope( name: *const c_char, - scope_type: NemoFlowScopeType, + scope_type: NemoRelayScopeType, parent: *const FfiScopeHandle, attributes: u32, data_json: *const c_char, metadata_json: *const c_char, input_json: *const c_char, out: *mut *mut FfiScopeHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_push_scope( + api::nemo_relay_push_scope( name, scope_type, parent, @@ -93,24 +94,24 @@ unsafe fn nemo_flow_push_scope( } } -unsafe fn nemo_flow_pop_scope( +unsafe fn nemo_relay_pop_scope( handle: *const FfiScopeHandle, output_json: *const c_char, -) -> NemoFlowStatus { - unsafe { api::nemo_flow_pop_scope(handle, output_json, ptr::null()) } +) -> NemoRelayStatus { + unsafe { api::nemo_relay_pop_scope(handle, output_json, ptr::null()) } } -unsafe fn nemo_flow_event( +unsafe fn nemo_relay_event( name: *const c_char, parent: *const FfiScopeHandle, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { - unsafe { api::nemo_flow_event(name, parent, data_json, metadata_json, ptr::null()) } +) -> NemoRelayStatus { + unsafe { api::nemo_relay_event(name, parent, data_json, metadata_json, ptr::null()) } } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_tool_call( +unsafe fn nemo_relay_tool_call( name: *const c_char, args_json: *const c_char, parent: *const FfiScopeHandle, @@ -119,9 +120,9 @@ unsafe fn nemo_flow_tool_call( metadata_json: *const c_char, tool_call_id: *const c_char, out: *mut *mut FfiToolHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_tool_call( + api::nemo_relay_tool_call( name, args_json, parent, @@ -135,19 +136,19 @@ unsafe fn nemo_flow_tool_call( } } -unsafe fn nemo_flow_tool_call_end( +unsafe fn nemo_relay_tool_call_end( handle: *const FfiToolHandle, result_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_tool_call_end(handle, result_json, data_json, metadata_json, ptr::null()) + api::nemo_relay_tool_call_end(handle, result_json, data_json, metadata_json, ptr::null()) } } #[allow(clippy::too_many_arguments)] -unsafe fn nemo_flow_llm_call( +unsafe fn nemo_relay_llm_call( name: *const c_char, native_json: *const c_char, parent: *const FfiScopeHandle, @@ -156,9 +157,9 @@ unsafe fn nemo_flow_llm_call( metadata_json: *const c_char, model_name: *const c_char, out: *mut *mut FfiLLMHandle, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_llm_call( + api::nemo_relay_llm_call( name, native_json, parent, @@ -172,14 +173,14 @@ unsafe fn nemo_flow_llm_call( } } -unsafe fn nemo_flow_llm_call_end( +unsafe fn nemo_relay_llm_call_end( handle: *const FfiLLMHandle, response_json: *const c_char, data_json: *const c_char, metadata_json: *const c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { - api::nemo_flow_llm_call_end(handle, response_json, data_json, metadata_json, ptr::null()) + api::nemo_relay_llm_call_end(handle, response_json, data_json, metadata_json, ptr::null()) } } @@ -190,12 +191,12 @@ unsafe fn take_string(ptr: *mut c_char) -> Option { let s = unsafe { CStr::from_ptr(ptr) } .to_string_lossy() .into_owned(); - unsafe { nemo_flow_string_free(ptr) }; + unsafe { nemo_relay_string_free(ptr) }; Some(s) } unsafe fn read_last_error() -> Option { - let ptr = nemo_flow_last_error(); + let ptr = nemo_relay_last_error(); if ptr.is_null() { None } else { @@ -214,13 +215,13 @@ unsafe fn returned_json(ptr: *mut c_char) -> Json { unsafe fn fresh_scope_stack() -> *mut FfiScopeStack { let mut stack = ptr::null_mut(); assert_eq!( - unsafe { nemo_flow_scope_stack_create(&mut stack) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_scope_stack_create(&mut stack) }, + NemoRelayStatus::Ok ); assert!(!stack.is_null()); assert_eq!( - unsafe { nemo_flow_scope_stack_set_thread(stack) }, - NemoFlowStatus::Ok + unsafe { nemo_relay_scope_stack_set_thread(stack) }, + NemoRelayStatus::Ok ); stack } @@ -234,24 +235,24 @@ fn reset_globals() { unsafe extern "C" fn subscriber_cb(_user_data: *mut libc::c_void, event: *const FfiEvent) { let payload = json!({ - "uuid": unsafe { take_string(nemo_flow_event_uuid(event)) }.unwrap_or_default(), - "name": unsafe { take_string(nemo_flow_event_name(event)) }.unwrap_or_default(), - "kind": unsafe { take_string(crate::types::nemo_flow_event_kind(event)) }.unwrap_or_default(), - "json": unsafe { take_string(crate::types::nemo_flow_event_json(event)) } + "uuid": unsafe { take_string(nemo_relay_event_uuid(event)) }.unwrap_or_default(), + "name": unsafe { take_string(nemo_relay_event_name(event)) }.unwrap_or_default(), + "kind": unsafe { take_string(crate::types::nemo_relay_event_kind(event)) }.unwrap_or_default(), + "json": unsafe { take_string(crate::types::nemo_relay_event_json(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "data": unsafe { take_string(nemo_flow_event_data(event)) } + "data": unsafe { take_string(nemo_relay_event_data(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "metadata": unsafe { take_string(nemo_flow_event_metadata(event)) } + "metadata": unsafe { take_string(nemo_relay_event_metadata(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "timestamp": unsafe { take_string(nemo_flow_event_timestamp(event)) }.unwrap_or_default(), - "input": unsafe { take_string(nemo_flow_event_input(event)) } + "timestamp": unsafe { take_string(nemo_relay_event_timestamp(event)) }.unwrap_or_default(), + "input": unsafe { take_string(nemo_relay_event_input(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "output": unsafe { take_string(nemo_flow_event_output(event)) } + "output": unsafe { take_string(nemo_relay_event_output(event)) } .map(|s| serde_json::from_str::(&s).unwrap()), - "model_name": unsafe { take_string(nemo_flow_event_model_name(event)) }, - "tool_call_id": unsafe { take_string(nemo_flow_event_tool_call_id(event)) }, - "parent_uuid": unsafe { take_string(nemo_flow_event_parent_uuid(event)) }, - "scope_type": unsafe { take_string(nemo_flow_event_scope_type(event)) }, + "model_name": unsafe { take_string(nemo_relay_event_model_name(event)) }, + "tool_call_id": unsafe { take_string(nemo_relay_event_tool_call_id(event)) }, + "parent_uuid": unsafe { take_string(nemo_relay_event_parent_uuid(event)) }, + "scope_type": unsafe { take_string(nemo_relay_event_scope_type(event)) }, }); lock_unpoisoned(event_log()).push(payload); } @@ -321,7 +322,7 @@ unsafe extern "C" fn tool_exec_fail_cb( unsafe extern "C" fn tool_exec_intercept_cb( _user_data: *mut libc::c_void, args_json: *const c_char, - next_fn: NemoFlowToolExecNextFn, + next_fn: NemoRelayToolExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(args_json, next_ctx) } @@ -375,9 +376,9 @@ unsafe extern "C" fn llm_request_intercept_cb( _annotated_json: *const c_char, out_request: *mut *mut FfiLLMRequest, _out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { unsafe { *out_request = llm_request_cb(ptr::null_mut(), request) }; - NemoFlowStatus::Ok + NemoRelayStatus::Ok } unsafe extern "C" fn llm_request_intercept_fail_cb( @@ -387,9 +388,9 @@ unsafe extern "C" fn llm_request_intercept_fail_cb( _annotated_json: *const c_char, _out_request: *mut *mut FfiLLMRequest, _out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { crate::error::set_last_error("llm request intercept callback failed"); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } unsafe extern "C" fn llm_exec_cb( @@ -519,7 +520,7 @@ unsafe extern "C" fn codec_encode_cb( unsafe extern "C" fn llm_exec_intercept_cb( _user_data: *mut libc::c_void, native_json: *const c_char, - next_fn: NemoFlowLlmExecNextFn, + next_fn: NemoRelayLlmExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { unsafe { next_fn(native_json, next_ctx) } @@ -584,10 +585,10 @@ unsafe extern "C" fn plugin_register_subscriber( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { +) -> NemoRelayStatus { let name = CString::new("subscriber").unwrap(); unsafe { - nemo_flow_plugin_context_register_subscriber( + nemo_relay_plugin_context_register_subscriber( ctx, name.as_ptr(), subscriber_cb, @@ -601,17 +602,17 @@ unsafe extern "C" fn plugin_register_fail( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, _ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { - NemoFlowStatus::Internal +) -> NemoRelayStatus { + NemoRelayStatus::Internal } unsafe extern "C" fn plugin_register_fail_with_last_error( _user_data: *mut libc::c_void, _plugin_config_json: *const c_char, _ctx: *mut FfiPluginContext, -) -> NemoFlowStatus { +) -> NemoRelayStatus { set_last_error("plugin register callback set last error explicitly"); - NemoFlowStatus::Internal + NemoRelayStatus::Internal } #[path = "api/core_tests.rs"] diff --git a/crates/ffi/tests/unit/callable_private_tests.rs b/crates/ffi/tests/unit/callable_private_tests.rs index cdc232f6a..a2684dd2f 100644 --- a/crates/ffi/tests/unit/callable_private_tests.rs +++ b/crates/ffi/tests/unit/callable_private_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for callable private in the NeMo Flow FFI crate. +//! Unit tests for callable private in the NeMo Relay FFI crate. use super::*; @@ -15,5 +15,5 @@ fn test_callable_private_helper_paths() { let raw = CString::new("ffi-string").unwrap().into_raw(); assert_eq!(ptr_to_opt_string(raw), Some("ffi-string".into())); - unsafe { nemo_flow_string_free_internal(raw) }; + unsafe { nemo_relay_string_free_internal(raw) }; } diff --git a/crates/ffi/tests/unit/callable_tests.rs b/crates/ffi/tests/unit/callable_tests.rs index e6747fa46..3089f5e83 100644 --- a/crates/ffi/tests/unit/callable_tests.rs +++ b/crates/ffi/tests/unit/callable_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for callable in the NeMo Flow FFI crate. +//! Unit tests for callable in the NeMo Relay FFI crate. use super::*; use std::sync::atomic::{AtomicUsize, Ordering}; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::{LlmAttributes, LlmHandle}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::{LlmAttributes, LlmHandle}; use serde_json::json; use tokio_stream::StreamExt; @@ -82,7 +82,7 @@ unsafe extern "C" fn tool_exec_error_cb( unsafe extern "C" fn tool_exec_intercept_cb( _user_data: *mut libc::c_void, args_json: *const c_char, - next_fn: NemoFlowToolExecNextFn, + next_fn: NemoRelayToolExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { let result_ptr = unsafe { next_fn(args_json, next_ctx) }; @@ -91,7 +91,7 @@ unsafe extern "C" fn tool_exec_intercept_cb( } let mut result: Json = serde_json::from_str(unsafe { CStr::from_ptr(result_ptr) }.to_str().unwrap()).unwrap(); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; result["intercepted"] = json!(true); CString::new(result.to_string()).unwrap().into_raw() } @@ -105,7 +105,7 @@ unsafe extern "C" fn llm_request_intercept_cb( annotated_json: *const c_char, out_request: *mut *mut FfiLLMRequest, out_annotated_json: *mut *mut c_char, -) -> NemoFlowStatus { +) -> NemoRelayStatus { let mut req = unsafe { (&*request).0.clone() }; req.content["intercepted"] = json!(true); unsafe { *out_request = Box::into_raw(Box::new(FfiLLMRequest(req))) }; @@ -117,7 +117,7 @@ unsafe extern "C" fn llm_request_intercept_cb( .into_owned(); unsafe { *out_annotated_json = CString::new(s).unwrap().into_raw() }; } - NemoFlowStatus::Ok + NemoRelayStatus::Ok } unsafe extern "C" fn llm_request_null_cb( @@ -169,7 +169,7 @@ unsafe extern "C" fn llm_exec_error_cb( unsafe extern "C" fn llm_exec_intercept_cb( _user_data: *mut libc::c_void, native_json: *const c_char, - next_fn: NemoFlowLlmExecNextFn, + next_fn: NemoRelayLlmExecNextFn, next_ctx: *mut libc::c_void, ) -> *mut c_char { let result_ptr = unsafe { next_fn(native_json, next_ctx) }; @@ -178,7 +178,7 @@ unsafe extern "C" fn llm_exec_intercept_cb( } let mut value: Json = serde_json::from_str(unsafe { CStr::from_ptr(result_ptr) }.to_str().unwrap()).unwrap(); - unsafe { nemo_flow_string_free_internal(result_ptr) }; + unsafe { nemo_relay_string_free_internal(result_ptr) }; value["intercepted"] = json!(true); CString::new(value.to_string()).unwrap().into_raw() } @@ -186,7 +186,7 @@ unsafe extern "C" fn llm_exec_intercept_cb( unsafe extern "C" fn llm_exec_short_circuit_cb( _user_data: *mut libc::c_void, native_json: *const c_char, - _next_fn: NemoFlowLlmExecNextFn, + _next_fn: NemoRelayLlmExecNextFn, _next_ctx: *mut libc::c_void, ) -> *mut c_char { let request: Json = @@ -317,7 +317,7 @@ fn test_wrap_llm_request_response_and_conditional_callbacks() { fn test_wrap_llm_request_intercept_with_annotated_input() { let request_intercept = wrap_llm_request_intercept_fn(llm_request_intercept_cb, std::ptr::null_mut(), None); - let annotated = nemo_flow::codec::request::AnnotatedLlmRequest { + let annotated = nemo_relay::codec::request::AnnotatedLlmRequest { messages: vec![], model: Some("test-model".into()), params: None, @@ -422,15 +422,15 @@ fn test_wrap_llm_exec_stream_and_event_callbacks() { let (user_data, seen) = user_data_counter(); let subscriber = wrap_event_subscriber(subscriber_cb, user_data, Some(free_arc_counter)); - let event = Event::Scope(nemo_flow::api::event::ScopeEvent::new( - nemo_flow::api::event::BaseEvent::builder() + let event = Event::Scope(nemo_relay::api::event::ScopeEvent::new( + nemo_relay::api::event::BaseEvent::builder() .name("ffi-event") .build(), - nemo_flow::api::event::ScopeCategory::Start, + nemo_relay::api::event::ScopeCategory::Start, Vec::new(), - nemo_flow::api::event::EventCategory::llm(), + nemo_relay::api::event::EventCategory::llm(), Some( - nemo_flow::api::event::CategoryProfile::builder() + nemo_relay::api::event::CategoryProfile::builder() .model_name("test-model") .build(), ), diff --git a/crates/ffi/tests/unit/types_tests.rs b/crates/ffi/tests/unit/types_tests.rs index dd404a73f..839ca7d97 100644 --- a/crates/ffi/tests/unit/types_tests.rs +++ b/crates/ffi/tests/unit/types_tests.rs @@ -1,17 +1,17 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for types in the NeMo Flow FFI crate. +//! Unit tests for types in the NeMo Relay FFI crate. use super::*; use std::ffi::{CStr, CString}; use std::sync::Arc; -use nemo_flow::api::event::{ +use nemo_relay::api::event::{ BaseEvent, CategoryProfile, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, llm_attributes_to_strings, scope_attributes_to_strings, tool_attributes_to_strings, }; -use nemo_flow::api::runtime::create_scope_stack; +use nemo_relay::api::runtime::create_scope_stack; use serde_json::json; use uuid::Uuid; @@ -20,7 +20,7 @@ fn take_string(ptr: *mut c_char) -> Option { return None; } let value = unsafe { CStr::from_ptr(ptr) }.to_str().unwrap().to_string(); - unsafe { convert::nemo_flow_string_free(ptr) }; + unsafe { convert::nemo_relay_string_free(ptr) }; Some(value) } @@ -70,7 +70,7 @@ fn make_scope_event(fixture: ScopeEventFixture) -> Event { #[test] fn test_scope_handle_accessors_and_null_metadata_guard() { - assert!(unsafe { nemo_flow_scope_handle_metadata(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_metadata(std::ptr::null()) }.is_null()); let parent_uuid = Uuid::now_v7(); let handle = FfiScopeHandle( @@ -85,27 +85,27 @@ fn test_scope_handle_accessors_and_null_metadata_guard() { ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_name(&handle) }), + take_string(unsafe { nemo_relay_scope_handle_name(&handle) }), Some("scope".into()) ); assert_eq!( - unsafe { nemo_flow_scope_handle_scope_type(&handle) } as i32, - NemoFlowScopeType::Tool as i32 + unsafe { nemo_relay_scope_handle_scope_type(&handle) } as i32, + NemoRelayScopeType::Tool as i32 ); assert_eq!( - unsafe { nemo_flow_scope_handle_attributes(&handle) }, + unsafe { nemo_relay_scope_handle_attributes(&handle) }, ScopeAttributes::PARALLEL.bits() ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_parent_uuid(&handle) }), + take_string(unsafe { nemo_relay_scope_handle_parent_uuid(&handle) }), Some(parent_uuid.to_string()) ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_data(&handle) }), + take_string(unsafe { nemo_relay_scope_handle_data(&handle) }), Some(r#"{"data":true}"#.into()) ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_metadata(&handle) }), + take_string(unsafe { nemo_relay_scope_handle_metadata(&handle) }), Some(r#"{"meta":true}"#.into()) ); } @@ -113,39 +113,39 @@ fn test_scope_handle_accessors_and_null_metadata_guard() { #[test] fn test_scope_type_conversions_and_handle_null_guards() { let scope_types = [ - (NemoFlowScopeType::Agent, ScopeType::Agent), - (NemoFlowScopeType::Function, ScopeType::Function), - (NemoFlowScopeType::Tool, ScopeType::Tool), - (NemoFlowScopeType::Llm, ScopeType::Llm), - (NemoFlowScopeType::Retriever, ScopeType::Retriever), - (NemoFlowScopeType::Embedder, ScopeType::Embedder), - (NemoFlowScopeType::Reranker, ScopeType::Reranker), - (NemoFlowScopeType::Guardrail, ScopeType::Guardrail), - (NemoFlowScopeType::Evaluator, ScopeType::Evaluator), - (NemoFlowScopeType::Custom, ScopeType::Custom), - (NemoFlowScopeType::Unknown, ScopeType::Unknown), + (NemoRelayScopeType::Agent, ScopeType::Agent), + (NemoRelayScopeType::Function, ScopeType::Function), + (NemoRelayScopeType::Tool, ScopeType::Tool), + (NemoRelayScopeType::Llm, ScopeType::Llm), + (NemoRelayScopeType::Retriever, ScopeType::Retriever), + (NemoRelayScopeType::Embedder, ScopeType::Embedder), + (NemoRelayScopeType::Reranker, ScopeType::Reranker), + (NemoRelayScopeType::Guardrail, ScopeType::Guardrail), + (NemoRelayScopeType::Evaluator, ScopeType::Evaluator), + (NemoRelayScopeType::Custom, ScopeType::Custom), + (NemoRelayScopeType::Unknown, ScopeType::Unknown), ]; for (ffi, core) in scope_types { - let round_trip: NemoFlowScopeType = core.into(); + let round_trip: NemoRelayScopeType = core.into(); assert_eq!(round_trip as i32, ffi as i32); let back: ScopeType = ffi.into(); assert_eq!(back, core); } - assert!(unsafe { nemo_flow_scope_handle_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_scope_handle_name(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_name(std::ptr::null()) }.is_null()); assert_eq!( - unsafe { nemo_flow_scope_handle_scope_type(std::ptr::null()) } as i32, - NemoFlowScopeType::Unknown as i32 + unsafe { nemo_relay_scope_handle_scope_type(std::ptr::null()) } as i32, + NemoRelayScopeType::Unknown as i32 ); assert_eq!( - unsafe { nemo_flow_scope_handle_attributes(std::ptr::null()) }, + unsafe { nemo_relay_scope_handle_attributes(std::ptr::null()) }, 0 ); - assert!(unsafe { nemo_flow_scope_handle_parent_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_scope_handle_data(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_scope_handle_metadata(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_parent_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_data(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_scope_handle_metadata(std::ptr::null()) }.is_null()); } #[test] @@ -159,19 +159,19 @@ fn test_tool_and_llm_handle_accessors_and_null_guards() { .build(), ); assert_eq!( - take_string(unsafe { nemo_flow_tool_handle_uuid(&tool) }), + take_string(unsafe { nemo_relay_tool_handle_uuid(&tool) }), Some(tool.0.uuid.to_string()) ); assert_eq!( - take_string(unsafe { nemo_flow_tool_handle_name(&tool) }), + take_string(unsafe { nemo_relay_tool_handle_name(&tool) }), Some("tool".into()) ); assert_eq!( - unsafe { nemo_flow_tool_handle_attributes(&tool) }, + unsafe { nemo_relay_tool_handle_attributes(&tool) }, ToolAttributes::REMOTE.bits() ); assert_eq!( - take_string(unsafe { nemo_flow_tool_handle_parent_uuid(&tool) }), + take_string(unsafe { nemo_relay_tool_handle_parent_uuid(&tool) }), Some(parent_uuid.to_string()) ); @@ -183,79 +183,79 @@ fn test_tool_and_llm_handle_accessors_and_null_guards() { .build(), ); assert_eq!( - take_string(unsafe { nemo_flow_llm_handle_uuid(&llm) }), + take_string(unsafe { nemo_relay_llm_handle_uuid(&llm) }), Some(llm.0.uuid.to_string()) ); assert_eq!( - take_string(unsafe { nemo_flow_llm_handle_name(&llm) }), + take_string(unsafe { nemo_relay_llm_handle_name(&llm) }), Some("llm".into()) ); assert_eq!( - unsafe { nemo_flow_llm_handle_attributes(&llm) }, + unsafe { nemo_relay_llm_handle_attributes(&llm) }, (LlmAttributes::STATEFUL | LlmAttributes::STREAMING).bits() ); assert_eq!( - take_string(unsafe { nemo_flow_llm_handle_parent_uuid(&llm) }), + take_string(unsafe { nemo_relay_llm_handle_parent_uuid(&llm) }), Some(parent_uuid.to_string()) ); - assert!(unsafe { nemo_flow_tool_handle_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_tool_handle_name(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_tool_handle_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_tool_handle_name(std::ptr::null()) }.is_null()); assert_eq!( - unsafe { nemo_flow_tool_handle_attributes(std::ptr::null()) }, + unsafe { nemo_relay_tool_handle_attributes(std::ptr::null()) }, 0 ); - assert!(unsafe { nemo_flow_tool_handle_parent_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_tool_handle_parent_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_llm_handle_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_llm_handle_name(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_llm_handle_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_llm_handle_name(std::ptr::null()) }.is_null()); assert_eq!( - unsafe { nemo_flow_llm_handle_attributes(std::ptr::null()) }, + unsafe { nemo_relay_llm_handle_attributes(std::ptr::null()) }, 0 ); - assert!(unsafe { nemo_flow_llm_handle_parent_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_llm_handle_parent_uuid(std::ptr::null()) }.is_null()); } #[test] fn test_llm_request_null_inputs_event_null_guards_and_free_nulls() { - let request_ptr = unsafe { nemo_flow_llm_request_new(std::ptr::null(), std::ptr::null()) }; + let request_ptr = unsafe { nemo_relay_llm_request_new(std::ptr::null(), std::ptr::null()) }; assert!(!request_ptr.is_null()); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_headers(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_headers(request_ptr) }), Some("{}".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_content(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_content(request_ptr) }), Some("null".into()) ); - unsafe { nemo_flow_llm_request_free(request_ptr) }; - - assert!(unsafe { nemo_flow_llm_request_headers(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_llm_request_content(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_name(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_kind(std::ptr::null()) }.is_null()); - assert_eq!(unsafe { nemo_flow_event_attributes(std::ptr::null()) }, 0); - assert!(unsafe { nemo_flow_event_data(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_metadata(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_timestamp(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_input(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_output(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_model_name(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_tool_call_id(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_parent_uuid(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_scope_type(std::ptr::null()) }.is_null()); + unsafe { nemo_relay_llm_request_free(request_ptr) }; + + assert!(unsafe { nemo_relay_llm_request_headers(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_llm_request_content(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_name(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_kind(std::ptr::null()) }.is_null()); + assert_eq!(unsafe { nemo_relay_event_attributes(std::ptr::null()) }, 0); + assert!(unsafe { nemo_relay_event_data(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_metadata(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_timestamp(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_input(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_output(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_model_name(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_tool_call_id(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_parent_uuid(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_scope_type(std::ptr::null()) }.is_null()); unsafe { - nemo_flow_scope_handle_free(std::ptr::null_mut()); - nemo_flow_tool_handle_free(std::ptr::null_mut()); - nemo_flow_llm_handle_free(std::ptr::null_mut()); - nemo_flow_llm_request_free(std::ptr::null_mut()); - nemo_flow_event_free(std::ptr::null_mut()); - nemo_flow_scope_stack_free(std::ptr::null_mut()); - nemo_flow_atif_exporter_free(std::ptr::null_mut()); - nemo_flow_otel_subscriber_free(std::ptr::null_mut()); - nemo_flow_openinference_subscriber_free(std::ptr::null_mut()); + nemo_relay_scope_handle_free(std::ptr::null_mut()); + nemo_relay_tool_handle_free(std::ptr::null_mut()); + nemo_relay_llm_handle_free(std::ptr::null_mut()); + nemo_relay_llm_request_free(std::ptr::null_mut()); + nemo_relay_event_free(std::ptr::null_mut()); + nemo_relay_scope_stack_free(std::ptr::null_mut()); + nemo_relay_atif_exporter_free(std::ptr::null_mut()); + nemo_relay_otel_subscriber_free(std::ptr::null_mut()); + nemo_relay_openinference_subscriber_free(std::ptr::null_mut()); } } @@ -268,42 +268,42 @@ fn test_valid_free_functions_and_none_backed_accessors() { .build(), ))); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_parent_uuid(scope_ptr) }), + take_string(unsafe { nemo_relay_scope_handle_parent_uuid(scope_ptr) }), None ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_data(scope_ptr) }), + take_string(unsafe { nemo_relay_scope_handle_data(scope_ptr) }), None ); assert_eq!( - take_string(unsafe { nemo_flow_scope_handle_metadata(scope_ptr) }), + take_string(unsafe { nemo_relay_scope_handle_metadata(scope_ptr) }), None ); - unsafe { nemo_flow_scope_handle_free(scope_ptr) }; + unsafe { nemo_relay_scope_handle_free(scope_ptr) }; let tool_ptr = Box::into_raw(Box::new(FfiToolHandle( ToolHandle::builder().name("tool-none").build(), ))); assert_eq!( - take_string(unsafe { nemo_flow_tool_handle_parent_uuid(tool_ptr) }), + take_string(unsafe { nemo_relay_tool_handle_parent_uuid(tool_ptr) }), None ); - unsafe { nemo_flow_tool_handle_free(tool_ptr) }; + unsafe { nemo_relay_tool_handle_free(tool_ptr) }; let llm_ptr = Box::into_raw(Box::new(FfiLLMHandle( LlmHandle::builder().name("llm-none").build(), ))); assert_eq!( - take_string(unsafe { nemo_flow_llm_handle_parent_uuid(llm_ptr) }), + take_string(unsafe { nemo_relay_llm_handle_parent_uuid(llm_ptr) }), None ); - unsafe { nemo_flow_llm_handle_free(llm_ptr) }; + unsafe { nemo_relay_llm_handle_free(llm_ptr) }; let request_ptr = Box::into_raw(Box::new(FfiLLMRequest(LlmRequest { headers: serde_json::Map::new(), content: json!(null), }))); - unsafe { nemo_flow_llm_request_free(request_ptr) }; + unsafe { nemo_relay_llm_request_free(request_ptr) }; let event_ptr = Box::into_raw(Box::new(FfiEvent(mark_event( "free-event", @@ -311,15 +311,15 @@ fn test_valid_free_functions_and_none_backed_accessors() { None, None, )))); - unsafe { nemo_flow_event_free(event_ptr) }; + unsafe { nemo_relay_event_free(event_ptr) }; let stack_ptr = Box::into_raw(Box::new(FfiScopeStack(create_scope_stack()))); - unsafe { nemo_flow_scope_stack_free(stack_ptr) }; + unsafe { nemo_relay_scope_stack_free(stack_ptr) }; let exporter_ptr = Box::into_raw(Box::new(FfiAtifExporter( - nemo_flow::observability::atif::AtifExporter::new( + nemo_relay::observability::atif::AtifExporter::new( "session".into(), - nemo_flow::observability::atif::AtifAgentInfo { + nemo_relay::observability::atif::AtifAgentInfo { name: "ffi-agent".into(), version: "1.0.0".into(), model_name: None, @@ -328,7 +328,7 @@ fn test_valid_free_functions_and_none_backed_accessors() { }, ), ))); - unsafe { nemo_flow_atif_exporter_free(exporter_ptr) }; + unsafe { nemo_relay_atif_exporter_free(exporter_ptr) }; } #[test] @@ -336,34 +336,34 @@ fn test_llm_request_new_invalid_inputs_fall_back_to_defaults() { let invalid_headers = CString::new(r#"["not-an-object"]"#).unwrap(); let invalid_content = CString::new("{").unwrap(); let request_ptr = - unsafe { nemo_flow_llm_request_new(invalid_headers.as_ptr(), invalid_content.as_ptr()) }; + unsafe { nemo_relay_llm_request_new(invalid_headers.as_ptr(), invalid_content.as_ptr()) }; assert!(!request_ptr.is_null()); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_headers(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_headers(request_ptr) }), Some("{}".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_content(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_content(request_ptr) }), Some("null".into()) ); - unsafe { nemo_flow_llm_request_free(request_ptr) }; + unsafe { nemo_relay_llm_request_free(request_ptr) }; } #[test] fn test_llm_request_and_event_accessors() { let headers = CString::new(r#"{"header":"value"}"#).unwrap(); let content = CString::new(r#"{"prompt":"hi"}"#).unwrap(); - let request_ptr = unsafe { nemo_flow_llm_request_new(headers.as_ptr(), content.as_ptr()) }; + let request_ptr = unsafe { nemo_relay_llm_request_new(headers.as_ptr(), content.as_ptr()) }; assert!(!request_ptr.is_null()); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_headers(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_headers(request_ptr) }), Some(r#"{"header":"value"}"#.into()) ); assert_eq!( - take_string(unsafe { nemo_flow_llm_request_content(request_ptr) }), + take_string(unsafe { nemo_relay_llm_request_content(request_ptr) }), Some(r#"{"prompt":"hi"}"#.into()) ); - unsafe { nemo_flow_llm_request_free(request_ptr) }; + unsafe { nemo_relay_llm_request_free(request_ptr) }; let parent_uuid = Uuid::now_v7(); let scope_event = make_scope_event(ScopeEventFixture { @@ -379,65 +379,65 @@ fn test_llm_request_and_event_accessors() { let ffi_event = FfiEvent(scope_event.clone()); assert_eq!( - take_string(unsafe { nemo_flow_event_kind(&ffi_event) }), + take_string(unsafe { nemo_relay_event_kind(&ffi_event) }), Some("scope".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_scope_category(&ffi_event) }), + take_string(unsafe { nemo_relay_event_scope_category(&ffi_event) }), Some("start".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_category(&ffi_event) }), + take_string(unsafe { nemo_relay_event_category(&ffi_event) }), Some("guardrail".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_uuid(&ffi_event) }), + take_string(unsafe { nemo_relay_event_uuid(&ffi_event) }), Some(scope_event.uuid().to_string()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_name(&ffi_event) }), + take_string(unsafe { nemo_relay_event_name(&ffi_event) }), Some("ffi-event".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_data(&ffi_event) }), + take_string(unsafe { nemo_relay_event_data(&ffi_event) }), Some(r#"{"data":1}"#.into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_metadata(&ffi_event) }), + take_string(unsafe { nemo_relay_event_metadata(&ffi_event) }), Some(r#"{"meta":2}"#.into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_scope_type(&ffi_event) }), + take_string(unsafe { nemo_relay_event_scope_type(&ffi_event) }), Some("guardrail".into()) ); assert_eq!( - unsafe { nemo_flow_event_attributes(&ffi_event) }, + unsafe { nemo_relay_event_attributes(&ffi_event) }, ScopeAttributes::empty().bits() ); assert_eq!( - take_string(unsafe { nemo_flow_event_parent_uuid(&ffi_event) }), + take_string(unsafe { nemo_relay_event_parent_uuid(&ffi_event) }), Some(parent_uuid.to_string()) ); assert!( - take_string(unsafe { nemo_flow_event_timestamp(&ffi_event) }) + take_string(unsafe { nemo_relay_event_timestamp(&ffi_event) }) .unwrap() .contains('T') ); assert_eq!( - take_string(unsafe { nemo_flow_event_input(&ffi_event) }), + take_string(unsafe { nemo_relay_event_input(&ffi_event) }), Some(r#"{"data":1}"#.into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_output(&ffi_event) }), + take_string(unsafe { nemo_relay_event_output(&ffi_event) }), None ); assert_eq!( - take_string(unsafe { nemo_flow_event_model_name(&ffi_event) }), + take_string(unsafe { nemo_relay_event_model_name(&ffi_event) }), None ); assert_eq!( - take_string(unsafe { nemo_flow_event_tool_call_id(&ffi_event) }), + take_string(unsafe { nemo_relay_event_tool_call_id(&ffi_event) }), None ); @@ -453,19 +453,19 @@ fn test_llm_request_and_event_accessors() { }); let ffi_llm_event = FfiEvent(llm_event); assert_eq!( - take_string(unsafe { nemo_flow_event_input(&ffi_llm_event) }), + take_string(unsafe { nemo_relay_event_input(&ffi_llm_event) }), Some(r#"{"input":true}"#.into()) ); assert_eq!( - unsafe { nemo_flow_event_attributes(&ffi_llm_event) }, + unsafe { nemo_relay_event_attributes(&ffi_llm_event) }, LlmAttributes::empty().bits() ); assert_eq!( - take_string(unsafe { nemo_flow_event_model_name(&ffi_llm_event) }), + take_string(unsafe { nemo_relay_event_model_name(&ffi_llm_event) }), Some("model".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_scope_type(&ffi_llm_event) }), + take_string(unsafe { nemo_relay_event_scope_type(&ffi_llm_event) }), Some("llm".into()) ); @@ -485,36 +485,36 @@ fn test_llm_request_and_event_accessors() { }); let ffi_tool_event = FfiEvent(tool_event); assert_eq!( - take_string(unsafe { nemo_flow_event_output(&ffi_tool_event) }), + take_string(unsafe { nemo_relay_event_output(&ffi_tool_event) }), Some(r#"{"output":true}"#.into()) ); assert_eq!( - unsafe { nemo_flow_event_attributes(&ffi_tool_event) }, + unsafe { nemo_relay_event_attributes(&ffi_tool_event) }, ToolAttributes::empty().bits() ); assert_eq!( - take_string(unsafe { nemo_flow_event_tool_call_id(&ffi_tool_event) }), + take_string(unsafe { nemo_relay_event_tool_call_id(&ffi_tool_event) }), Some("tool-call-id".into()) ); assert_eq!( - take_string(unsafe { nemo_flow_event_scope_type(&ffi_tool_event) }), + take_string(unsafe { nemo_relay_event_scope_type(&ffi_tool_event) }), Some("tool".into()) ); let mark_event = mark_event("ffi-mark", Some(parent_uuid), None, None); let ffi_mark_event = FfiEvent(mark_event); assert_eq!( - take_string(unsafe { nemo_flow_event_scope_type(&ffi_mark_event) }), + take_string(unsafe { nemo_relay_event_scope_type(&ffi_mark_event) }), None ); - assert_eq!(unsafe { nemo_flow_event_attributes(&ffi_mark_event) }, 0); + assert_eq!(unsafe { nemo_relay_event_attributes(&ffi_mark_event) }, 0); } #[test] fn test_annotated_event_accessors_and_codec_handles() { - let annotated_request = nemo_flow::codec::request::AnnotatedLlmRequest { - messages: vec![nemo_flow::codec::request::Message::User { - content: nemo_flow::codec::request::MessageContent::Text("hello".into()), + let annotated_request = nemo_relay::codec::request::AnnotatedLlmRequest { + messages: vec![nemo_relay::codec::request::Message::User { + content: nemo_relay::codec::request::MessageContent::Text("hello".into()), name: Some("tester".into()), }], model: Some("gpt-test".into()), @@ -553,22 +553,22 @@ fn test_annotated_event_accessors_and_codec_handles() { }); let ffi_start = FfiEvent(llm_start); let annotated_request_json = - take_string(unsafe { nemo_flow_event_annotated_request(&ffi_start) }) + take_string(unsafe { nemo_relay_event_annotated_request(&ffi_start) }) .expect("expected annotated request json"); let annotated_request_value: serde_json::Value = serde_json::from_str(&annotated_request_json).unwrap(); assert_eq!(annotated_request_value["model"], json!("gpt-test")); assert_eq!(annotated_request_value["provider"], json!("ffi")); - assert!(unsafe { nemo_flow_event_annotated_response(&ffi_start) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_response(&ffi_start) }.is_null()); - let annotated_response = nemo_flow::codec::response::AnnotatedLlmResponse { + let annotated_response = nemo_relay::codec::response::AnnotatedLlmResponse { id: Some("resp_123".into()), model: Some("gpt-test".into()), - message: Some(nemo_flow::codec::request::MessageContent::Text( + message: Some(nemo_relay::codec::request::MessageContent::Text( "done".into(), )), tool_calls: None, - finish_reason: Some(nemo_flow::codec::response::FinishReason::Complete), + finish_reason: Some(nemo_relay::codec::response::FinishReason::Complete), usage: None, api_specific: None, extra: serde_json::Map::from_iter([("trace".into(), json!(true))]), @@ -590,13 +590,13 @@ fn test_annotated_event_accessors_and_codec_handles() { }); let ffi_end = FfiEvent(llm_end); let annotated_response_json = - take_string(unsafe { nemo_flow_event_annotated_response(&ffi_end) }) + take_string(unsafe { nemo_relay_event_annotated_response(&ffi_end) }) .expect("expected annotated response json"); let annotated_response_value: serde_json::Value = serde_json::from_str(&annotated_response_json).unwrap(); assert_eq!(annotated_response_value["id"], json!("resp_123")); assert_eq!(annotated_response_value["trace"], json!(true)); - assert!(unsafe { nemo_flow_event_annotated_request(&ffi_end) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_request(&ffi_end) }.is_null()); let scope_event = FfiEvent(make_scope_event(ScopeEventFixture { scope_category: ScopeCategory::Start, @@ -608,28 +608,28 @@ fn test_annotated_event_accessors_and_codec_handles() { attributes: scope_attributes_to_strings(ScopeAttributes::PARALLEL), category_profile: None, })); - assert!(unsafe { nemo_flow_event_annotated_request(&scope_event) }.is_null()); - assert!(unsafe { nemo_flow_event_annotated_response(&scope_event) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_request(&scope_event) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_response(&scope_event) }.is_null()); - let openai_chat = api::nemo_flow_openai_chat_codec_new(); - let openai_responses = api::nemo_flow_openai_responses_codec_new(); - let anthropic = api::nemo_flow_anthropic_messages_codec_new(); + let openai_chat = api::nemo_relay_openai_chat_codec_new(); + let openai_responses = api::nemo_relay_openai_responses_codec_new(); + let anthropic = api::nemo_relay_anthropic_messages_codec_new(); assert!(!openai_chat.is_null()); assert!(!openai_responses.is_null()); assert!(!anthropic.is_null()); unsafe { - nemo_flow_codec_free(openai_chat); - nemo_flow_codec_free(openai_responses); - nemo_flow_codec_free(anthropic); - nemo_flow_codec_free(std::ptr::null_mut()); + nemo_relay_codec_free(openai_chat); + nemo_relay_codec_free(openai_responses); + nemo_relay_codec_free(anthropic); + nemo_relay_codec_free(std::ptr::null_mut()); } } #[test] fn test_event_accessor_none_and_null_pointer_paths_for_annotations() { - assert!(unsafe { nemo_flow_event_annotated_request(std::ptr::null()) }.is_null()); - assert!(unsafe { nemo_flow_event_annotated_response(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_request(std::ptr::null()) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_response(std::ptr::null()) }.is_null()); let plain_start = FfiEvent(make_scope_event(ScopeEventFixture { scope_category: ScopeCategory::Start, @@ -642,10 +642,10 @@ fn test_event_accessor_none_and_null_pointer_paths_for_annotations() { category_profile: None, })); assert_eq!( - take_string(unsafe { nemo_flow_event_parent_uuid(&plain_start) }), + take_string(unsafe { nemo_relay_event_parent_uuid(&plain_start) }), None ); - assert!(unsafe { nemo_flow_event_annotated_request(&plain_start) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_request(&plain_start) }.is_null()); let plain_end = FfiEvent(make_scope_event(ScopeEventFixture { scope_category: ScopeCategory::End, @@ -657,5 +657,5 @@ fn test_event_accessor_none_and_null_pointer_paths_for_annotations() { attributes: Vec::new(), category_profile: None, })); - assert!(unsafe { nemo_flow_event_annotated_response(&plain_end) }.is_null()); + assert!(unsafe { nemo_relay_event_annotated_response(&plain_end) }.is_null()); } diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 12197a8f0..878a8513b 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -2,12 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-node" +name = "nemo-relay-node" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Node.js native bindings for NeMo Flow built with napi-rs." +description = "Node.js native bindings for NeMo Relay built with napi-rs." readme = "README.md" [lints] @@ -18,8 +18,8 @@ crate-type = ["cdylib"] test = false [dependencies] -nemo-flow = { workspace = true, features = ["otel", "openinference"] } -nemo-flow-adaptive = { workspace = true, features = ["redis-backend"] } +nemo-relay = { workspace = true, features = ["otel", "openinference"] } +nemo-relay-adaptive = { workspace = true, features = ["redis-backend"] } chrono = "0.4" napi = { version = "2", features = ["napi6", "async", "serde-json", "tokio_rt"] } napi-derive = "2" diff --git a/crates/node/README.md b/crates/node/README.md index de1325a8b..2d01798de 100644 --- a/crates/node/README.md +++ b/crates/node/README.md @@ -3,21 +3,21 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow-node` is the NeMo Flow package for Node.js applications. It gives +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay-node` is the NeMo Relay package for Node.js applications. It gives JavaScript and TypeScript code access to the same execution scopes, middleware, plugins, lifecycle events, and observability model used by the Rust runtime. @@ -45,16 +45,16 @@ should install it from npm rather than depend on the Rust crate directly. - ✅ **Middleware APIs**: Guardrails and intercepts for tool and LLM boundaries. - ✅ **Observability exporters**: Subscriber and exporter support for common runtime telemetry flows. -- ✅ **Additional entry points**: `nemo-flow-node/typed`, - `nemo-flow-node/plugin`, `nemo-flow-node/adaptive`, and - `nemo-flow-node/observability`. +- ✅ **Additional entry points**: `nemo-relay-node/typed`, + `nemo-relay-node/plugin`, `nemo-relay-node/adaptive`, and + `nemo-relay-node/observability`. ## Installation Install the npm package in a Node.js 20 or newer project: ```bash -npm install nemo-flow-node +npm install nemo-relay-node ``` ## Getting Started @@ -68,7 +68,7 @@ const { event, registerSubscriber, withScope, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); async function main() { registerSubscriber("printer", (runtimeEvent) => { @@ -89,10 +89,10 @@ main().catch((error) => { }); ``` -The main runtime API is exported from `nemo-flow-node`. Additional entry points -are available at `nemo-flow-node/typed`, `nemo-flow-node/plugin`, -`nemo-flow-node/adaptive`, and `nemo-flow-node/observability`. +The main runtime API is exported from `nemo-relay-node`. Additional entry points +are available at `nemo-relay-node/typed`, `nemo-relay-node/plugin`, +`nemo-relay-node/adaptive`, and `nemo-relay-node/observability`. ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/node/adaptive.d.ts b/crates/node/adaptive.d.ts index 391bde771..25fb1723b 100644 --- a/crates/node/adaptive.d.ts +++ b/crates/node/adaptive.d.ts @@ -103,7 +103,7 @@ export declare function inMemoryBackend(): BackendSpec; * @param keyPrefix - Prefix applied to Redis keys. * @returns An adaptive backend spec using Redis storage. * @remarks The default key prefix namespaces runtime records under - * `nemo_flow:` unless a different prefix is supplied. + * `nemo_relay:` unless a different prefix is supplied. */ export declare function redisBackend(url: string, keyPrefix?: string): BackendSpec; /** diff --git a/crates/node/adaptive.js b/crates/node/adaptive.js index cbf4a4726..22b125991 100644 --- a/crates/node/adaptive.js +++ b/crates/node/adaptive.js @@ -46,12 +46,12 @@ function inMemoryBackend() { * should be shared or persisted through Redis. * * @param {string} url - Redis connection URL for the backend. - * @param {string} [keyPrefix='nemo_flow:'] - Prefix applied to Redis keys. + * @param {string} [keyPrefix='nemo_relay:'] - Prefix applied to Redis keys. * @returns {object} An adaptive backend spec using Redis storage. * @remarks The default key prefix namespaces runtime records under - * `nemo_flow:` unless a different prefix is supplied. + * `nemo_relay:` unless a different prefix is supplied. */ -function redisBackend(url, keyPrefix = 'nemo_flow:') { +function redisBackend(url, keyPrefix = 'nemo_relay:') { return { kind: 'redis', config: { diff --git a/crates/node/observability.js b/crates/node/observability.js index 06a53811e..7ce69c935 100644 --- a/crates/node/observability.js +++ b/crates/node/observability.js @@ -41,9 +41,9 @@ function atofConfig(config = {}) { function atifConfig(config = {}) { return { enabled: false, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', ...config, }; } @@ -60,7 +60,7 @@ function otlpConfig(config = {}) { transport: 'http_binary', headers: {}, resource_attributes: {}, - service_name: 'nemo-flow', + service_name: 'nemo-relay', timeout_millis: 3000, ...config, }; diff --git a/crates/node/package.json b/crates/node/package.json index d5f13af72..411cc8421 100644 --- a/crates/node/package.json +++ b/crates/node/package.json @@ -1,24 +1,24 @@ { - "name": "nemo-flow-node", + "name": "nemo-relay-node", "version": "0.3.0", - "description": "Node.js bindings for the NeMo Flow agent runtime.", + "description": "Node.js bindings for the NeMo Relay agent runtime.", "keywords": [ "agents", "ai", "llm", "middleware", - "nemo-flow", + "nemo-relay", "observability", "runtime", "tools" ], - "homepage": "https://github.com/NVIDIA/NeMo-Flow#readme", + "homepage": "https://github.com/NVIDIA/NeMo-Relay#readme", "bugs": { - "url": "https://github.com/NVIDIA/NeMo-Flow/issues" + "url": "https://github.com/NVIDIA/NeMo-Relay/issues" }, "repository": { "type": "git", - "url": "git+https://github.com/NVIDIA/NeMo-Flow.git", + "url": "git+https://github.com/NVIDIA/NeMo-Relay.git", "directory": "crates/node" }, "author": "NVIDIA Corporation & Affiliates", @@ -50,7 +50,7 @@ "node": ">=20.0.0" }, "napi": { - "name": "nemo-flow", + "name": "nemo-relay", "triples": {} }, "scripts": { diff --git a/crates/node/src/api/mod.rs b/crates/node/src/api/mod.rs index 8c1aacddb..a7465ae1d 100644 --- a/crates/node/src/api/mod.rs +++ b/crates/node/src/api/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Public NAPI API functions for the NeMo Flow Node.js bindings. +//! Public NAPI API functions for the NeMo Relay Node.js bindings. //! //! This module exposes the full agent runtime API to JavaScript/TypeScript: //! scope stack management, tool and LLM lifecycle operations, guardrail and @@ -25,22 +25,22 @@ use napi_derive::napi; use serde_json::Value as Json; use tokio_stream::StreamExt; -use nemo_flow::api::llm as core_llm_api; -use nemo_flow::api::llm::{LlmAttributes, LlmRequest}; -use nemo_flow::api::registry as core_registry_api; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::runtime::{ +use nemo_relay::api::llm as core_llm_api; +use nemo_relay::api::llm::{LlmAttributes, LlmRequest}; +use nemo_relay::api::registry as core_registry_api; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::runtime::{ TASK_SCOPE_STACK, create_scope_stack as create_scope_stack_handle, current_scope_stack as current_scope_stack_handle, scope_stack_active as scope_stack_is_active, set_thread_scope_stack as bind_thread_scope_stack, task_scope_top, }; -use nemo_flow::api::scope as core_scope_api; -use nemo_flow::api::scope::ScopeAttributes; -use nemo_flow::api::subscriber as core_subscriber_api; -use nemo_flow::api::tool as core_tool_api; -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::error::{FlowError, Result as FlowResult}; -use nemo_flow::plugin::{ +use nemo_relay::api::scope as core_scope_api; +use nemo_relay::api::scope::ScopeAttributes; +use nemo_relay::api::subscriber as core_subscriber_api; +use nemo_relay::api::tool as core_tool_api; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::error::{FlowError, Result as FlowResult}; +use nemo_relay::plugin::{ ConfigDiagnostic, DiagnosticLevel, Plugin, PluginConfig, PluginError, PluginRegistration, PluginRegistrationContext, active_plugin_report as active_plugin_report_impl, clear_plugin_configuration as clear_plugin_configuration_impl, @@ -48,8 +48,8 @@ use nemo_flow::plugin::{ list_plugin_kinds as list_plugin_kinds_impl, register_plugin as register_plugin_impl, validate_plugin_config as validate_plugin_config_impl, }; -use nemo_flow::shared_runtime::initialize_shared_runtime_binding; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay::shared_runtime::initialize_shared_runtime_binding; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use crate::callable; use crate::convert::{ @@ -94,24 +94,24 @@ fn parse_string_map( fn build_otel_config( options: Option, -) -> napi::Result { +) -> napi::Result { let options = options.unwrap_or_default(); let transport = options .transport .unwrap_or_else(|| "http_binary".to_string()); let service_name = options .service_name - .unwrap_or_else(|| "nemo-flow".to_string()); + .unwrap_or_else(|| "nemo-relay".to_string()); let instrumentation_scope = options .instrumentation_scope - .unwrap_or_else(|| "nemo-flow-otel".to_string()); + .unwrap_or_else(|| "nemo-relay-otel".to_string()); let timeout_millis = options.timeout_millis.unwrap_or(3_000); let mut config = match transport.as_str() { "http_binary" => { - nemo_flow::observability::otel::OpenTelemetryConfig::http_binary(service_name) + nemo_relay::observability::otel::OpenTelemetryConfig::http_binary(service_name) } - "grpc" => nemo_flow::observability::otel::OpenTelemetryConfig::grpc(service_name), + "grpc" => nemo_relay::observability::otel::OpenTelemetryConfig::grpc(service_name), other => { return Err(napi::Error::from_reason(format!( "transport must be 'http_binary' or 'grpc', got {other:?}", @@ -142,9 +142,9 @@ fn build_otel_config( fn build_atof_config( options: Option, -) -> napi::Result { +) -> napi::Result { let options = options.unwrap_or_default(); - let mut config = nemo_flow::observability::atof::AtofExporterConfig::new(); + let mut config = nemo_relay::observability::atof::AtofExporterConfig::new(); if let Some(output_directory) = options.output_directory { config = config.with_output_directory(PathBuf::from(output_directory)); @@ -153,7 +153,7 @@ fn build_atof_config( config = config.with_filename(filename); } if let Some(mode) = options.mode { - let Some(mode) = nemo_flow::observability::atof::AtofExporterMode::parse(&mode) else { + let Some(mode) = nemo_relay::observability::atof::AtofExporterMode::parse(&mode) else { return Err(napi::Error::from_reason( "mode must be 'append' or 'overwrite'", )); @@ -166,22 +166,22 @@ fn build_atof_config( fn build_openinference_config( options: Option, -) -> napi::Result { +) -> napi::Result { let options = options.unwrap_or_default(); let transport = options .transport .unwrap_or_else(|| "http_binary".to_string()); let service_name = options .service_name - .unwrap_or_else(|| "nemo-flow".to_string()); + .unwrap_or_else(|| "nemo-relay".to_string()); let instrumentation_scope = options .instrumentation_scope - .unwrap_or_else(|| "nemo-flow-openinference".to_string()); + .unwrap_or_else(|| "nemo-relay-openinference".to_string()); let timeout_millis = options.timeout_millis.unwrap_or(3_000); let transport = match transport.as_str() { - "http_binary" => nemo_flow::observability::openinference::OtlpTransport::HttpBinary, - "grpc" => nemo_flow::observability::openinference::OtlpTransport::Grpc, + "http_binary" => nemo_relay::observability::openinference::OtlpTransport::HttpBinary, + "grpc" => nemo_relay::observability::openinference::OtlpTransport::Grpc, other => { return Err(napi::Error::from_reason(format!( "transport must be 'http_binary' or 'grpc', got {other:?}", @@ -189,7 +189,7 @@ fn build_openinference_config( } }; - let mut config = nemo_flow::observability::openinference::OpenInferenceConfig::new() + let mut config = nemo_relay::observability::openinference::OpenInferenceConfig::new() .with_transport(transport) .with_service_name(service_name) .with_instrumentation_scope(instrumentation_scope) @@ -368,8 +368,9 @@ fn build_plugin_context( let subscriber_regs = registrations.clone(); let subscriber_namespace = namespace_prefix.clone(); - let register_subscriber = - env.create_function_from_closure("__nemo_flow_adaptive_register_subscriber", move |ctx| { + let register_subscriber = env.create_function_from_closure( + "__nemo_relay_adaptive_register_subscriber", + move |ctx| { let name = format!("{}{}", subscriber_namespace, ctx.get::(0)?); let callback = ctx.get::(1)?; let tsfn = json_callback_tsfn(ctx.env, &callback)?; @@ -397,13 +398,14 @@ fn build_plugin_context( }), )); ctx.env.get_undefined() - })?; + }, + )?; context.set_named_property("registerSubscriber", register_subscriber)?; let tool_sanitize_request_regs = registrations.clone(); let tool_sanitize_request_namespace = namespace_prefix.clone(); let register_tool_sanitize_request_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_tool_sanitize_request_guardrail", + "__nemo_relay_plugin_register_tool_sanitize_request_guardrail", move |ctx| { let name = format!( "{}{}", @@ -448,7 +450,7 @@ fn build_plugin_context( let tool_sanitize_response_regs = registrations.clone(); let tool_sanitize_response_namespace = namespace_prefix.clone(); let register_tool_sanitize_response_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_tool_sanitize_response_guardrail", + "__nemo_relay_plugin_register_tool_sanitize_response_guardrail", move |ctx| { let name = format!( "{}{}", @@ -493,7 +495,7 @@ fn build_plugin_context( let tool_conditional_regs = registrations.clone(); let tool_conditional_namespace = namespace_prefix.clone(); let register_tool_conditional_execution_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_tool_conditional_execution_guardrail", + "__nemo_relay_plugin_register_tool_conditional_execution_guardrail", move |ctx| { let name = format!("{}{}", tool_conditional_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -536,7 +538,7 @@ fn build_plugin_context( let llm_sanitize_request_regs = registrations.clone(); let llm_sanitize_request_namespace = namespace_prefix.clone(); let register_llm_sanitize_request_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_llm_sanitize_request_guardrail", + "__nemo_relay_plugin_register_llm_sanitize_request_guardrail", move |ctx| { let name = format!( "{}{}", @@ -580,7 +582,7 @@ fn build_plugin_context( let llm_sanitize_response_regs = registrations.clone(); let llm_sanitize_response_namespace = namespace_prefix.clone(); let register_llm_sanitize_response_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_llm_sanitize_response_guardrail", + "__nemo_relay_plugin_register_llm_sanitize_response_guardrail", move |ctx| { let name = format!( "{}{}", @@ -624,7 +626,7 @@ fn build_plugin_context( let llm_conditional_regs = registrations.clone(); let llm_conditional_namespace = namespace_prefix.clone(); let register_llm_conditional_execution_guardrail = env.create_function_from_closure( - "__nemo_flow_plugin_register_llm_conditional_execution_guardrail", + "__nemo_relay_plugin_register_llm_conditional_execution_guardrail", move |ctx| { let name = format!("{}{}", llm_conditional_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -666,7 +668,7 @@ fn build_plugin_context( let llm_regs = registrations.clone(); let llm_request_namespace = namespace_prefix.clone(); let register_llm_request_intercept = env.create_function_from_closure( - "__nemo_flow_adaptive_register_llm_request_intercept", + "__nemo_relay_adaptive_register_llm_request_intercept", move |ctx| { let name = format!("{}{}", llm_request_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -706,7 +708,7 @@ fn build_plugin_context( let llm_exec_regs = registrations.clone(); let llm_exec_namespace = namespace_prefix.clone(); let register_llm_execution_intercept = env.create_function_from_closure( - "__nemo_flow_adaptive_register_llm_execution_intercept", + "__nemo_relay_adaptive_register_llm_execution_intercept", move |ctx| { let name = format!("{}{}", llm_exec_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -748,7 +750,7 @@ fn build_plugin_context( let llm_stream_exec_regs = registrations.clone(); let llm_stream_namespace = namespace_prefix.clone(); let register_llm_stream_execution_intercept = env.create_function_from_closure( - "__nemo_flow_adaptive_register_llm_stream_execution_intercept", + "__nemo_relay_adaptive_register_llm_stream_execution_intercept", move |ctx| { let name = format!("{}{}", llm_stream_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -795,7 +797,7 @@ fn build_plugin_context( let tool_request_regs = registrations.clone(); let tool_request_namespace = namespace_prefix.clone(); let register_tool_request_intercept = env.create_function_from_closure( - "__nemo_flow_adaptive_register_tool_request_intercept", + "__nemo_relay_adaptive_register_tool_request_intercept", move |ctx| { let name = format!("{}{}", tool_request_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -838,7 +840,7 @@ fn build_plugin_context( let tool_regs = registrations.clone(); let tool_exec_namespace = namespace_prefix; let register_tool_execution_intercept = env.create_function_from_closure( - "__nemo_flow_adaptive_register_tool_execution_intercept", + "__nemo_relay_adaptive_register_tool_execution_intercept", move |ctx| { let name = format!("{}{}", tool_exec_namespace, ctx.get::(0)?); let priority = ctx.get::(1)?; @@ -1850,8 +1852,8 @@ pub fn llm_stream_call_execute( // Serialize the LlmRequest to JSON and wrap with streamId so JS can extract both let req_json = serde_json::to_value(&req).unwrap_or(Json::Null); let wrapper = serde_json::json!({ - "__nemo_flow_native": req_json, - "__nemo_flow_stream_id": stream_id, + "__nemo_relay_native": req_json, + "__nemo_relay_stream_id": stream_id, }); // NonBlocking: queue the call on the JS event loop and return immediately. @@ -2897,7 +2899,7 @@ pub fn llm_conditional_execution(env: Env, request: Json) -> Result { /// When ready, call `exportJson()` to serialize the collected trajectory. #[napi] pub struct AtifExporter { - inner: nemo_flow::observability::atif::AtifExporter, + inner: nemo_relay::observability::atif::AtifExporter, } #[napi] @@ -2913,7 +2915,7 @@ impl AtifExporter { agent_version: String, model_name: Option, ) -> napi::Result { - let agent_info = nemo_flow::observability::atif::AtifAgentInfo { + let agent_info = nemo_relay::observability::atif::AtifAgentInfo { name: agent_name, version: agent_version, model_name, @@ -2921,7 +2923,7 @@ impl AtifExporter { extra: None, }; Ok(Self { - inner: nemo_flow::observability::atif::AtifExporter::new(session_id, agent_info), + inner: nemo_relay::observability::atif::AtifExporter::new(session_id, agent_info), }) } @@ -2968,14 +2970,14 @@ pub struct AtofExporterConfig { pub output_directory: Option, /// `"append"` (default) or `"overwrite"`. pub mode: Option, - /// Output filename. Defaults to `nemo-flow-events-YYYY-MM-DD-HH.MM.SS.jsonl`. + /// Output filename. Defaults to `nemo-relay-events-YYYY-MM-DD-HH.MM.SS.jsonl`. pub filename: Option, } /// Filesystem-backed Agent Trajectory Observability Format (ATOF) JSONL event exporter. #[napi] pub struct AtofExporter { - inner: nemo_flow::observability::atof::AtofExporter, + inner: nemo_relay::observability::atof::AtofExporter, } #[napi] @@ -2984,7 +2986,7 @@ impl AtofExporter { /// from a config object. #[napi(constructor)] pub fn new(config: Option) -> napi::Result { - let inner = nemo_flow::observability::atof::AtofExporter::new(build_atof_config(config)?) + let inner = nemo_relay::observability::atof::AtofExporter::new(build_atof_config(config)?) .map_err(|e| napi::Error::from_reason(e.to_string()))?; Ok(Self { inner }) } @@ -3040,13 +3042,13 @@ pub struct OpenTelemetryConfig { pub headers: Option, /// Extra OpenTelemetry resource attributes as string key/value pairs. pub resource_attributes: Option, - /// `service.name` resource attribute. Defaults to `"nemo-flow"`. + /// `service.name` resource attribute. Defaults to `"nemo-relay"`. pub service_name: Option, /// Optional `service.namespace` resource attribute. pub service_namespace: Option, /// Optional `service.version` resource attribute. pub service_version: Option, - /// Instrumentation scope name. Defaults to `"nemo-flow-otel"`. + /// Instrumentation scope name. Defaults to `"nemo-relay-otel"`. pub instrumentation_scope: Option, /// Export timeout in milliseconds. Defaults to `3000`. pub timeout_millis: Option, @@ -3064,13 +3066,13 @@ pub struct OpenInferenceConfig { pub headers: Option, /// Extra OpenInference resource attributes as string key/value pairs. pub resource_attributes: Option, - /// `service.name` resource attribute. Defaults to `"nemo-flow"`. + /// `service.name` resource attribute. Defaults to `"nemo-relay"`. pub service_name: Option, /// Optional `service.namespace` resource attribute. pub service_namespace: Option, /// Optional `service.version` resource attribute. pub service_version: Option, - /// Instrumentation scope name. Defaults to `"nemo-flow-openinference"`. + /// Instrumentation scope name. Defaults to `"nemo-relay-openinference"`. pub instrumentation_scope: Option, /// Export timeout in milliseconds. Defaults to `3000`. pub timeout_millis: Option, @@ -3079,7 +3081,7 @@ pub struct OpenInferenceConfig { /// OpenTelemetry-backed event subscriber. #[napi] pub struct OpenTelemetrySubscriber { - inner: nemo_flow::observability::otel::OpenTelemetrySubscriber, + inner: nemo_relay::observability::otel::OpenTelemetrySubscriber, } #[napi] @@ -3087,7 +3089,7 @@ impl OpenTelemetrySubscriber { /// Create a new OpenTelemetry subscriber from a config object. #[napi(constructor)] pub fn new(config: Option) -> napi::Result { - let inner = nemo_flow::observability::otel::OpenTelemetrySubscriber::new( + let inner = nemo_relay::observability::otel::OpenTelemetrySubscriber::new( build_otel_config(config)?, ) .map_err(|e| napi::Error::from_reason(e.to_string()))?; @@ -3130,7 +3132,7 @@ impl OpenTelemetrySubscriber { /// OpenInference-backed event subscriber. #[napi] pub struct OpenInferenceSubscriber { - inner: nemo_flow::observability::openinference::OpenInferenceSubscriber, + inner: nemo_relay::observability::openinference::OpenInferenceSubscriber, } #[napi] @@ -3138,7 +3140,7 @@ impl OpenInferenceSubscriber { /// Create a new OpenInference subscriber from a config object. #[napi(constructor)] pub fn new(config: Option) -> napi::Result { - let inner = nemo_flow::observability::openinference::OpenInferenceSubscriber::new( + let inner = nemo_relay::observability::openinference::OpenInferenceSubscriber::new( build_openinference_config(config)?, ) .map_err(|e| napi::Error::from_reason(e.to_string()))?; diff --git a/crates/node/src/callable.rs b/crates/node/src/callable.rs index 8a079bbdd..71f591089 100644 --- a/crates/node/src/callable.rs +++ b/crates/node/src/callable.rs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::type_complexity)] -//! JavaScript callable wrappers for NeMo Flow callbacks. +//! JavaScript callable wrappers for NeMo Relay callbacks. //! //! This module bridges JavaScript functions (received as NAPI `ThreadsafeFunction` values) -//! into the Rust closure signatures expected by the NeMo Flow core runtime. Each wrapper +//! into the Rust closure signatures expected by the NeMo Relay core runtime. Each wrapper //! handles serialization of arguments to/from JSON and manages cross-thread communication //! between the Rust async runtime and the Node.js event loop. @@ -14,7 +14,7 @@ use std::pin::Pin; use std::sync::Arc; use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ EventSubscriberFn, LlmConditionalFn, LlmExecutionNextFn, LlmRequestInterceptFn, LlmSanitizeRequestFn, LlmSanitizeResponseFn, LlmStreamExecutionNextFn, ToolConditionalFn, ToolExecutionNextFn, ToolInterceptFn, ToolSanitizeFn, @@ -22,12 +22,12 @@ use nemo_flow::api::runtime::{ use serde_json::Value as Json; use tokio_stream::StreamExt; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::response::AnnotatedLlmResponse; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::{FlowError, Result}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::response::AnnotatedLlmResponse; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::{FlowError, Result}; use crate::convert::{callback_json, record_callback_error}; use crate::promise_call::{JsonNextFn, JsonStreamNextFn, PromiseAwareFn}; @@ -114,13 +114,13 @@ pub fn wrap_js_tool_fn( ); if status != napi::Status::Ok { record_callback_error(format!( - "nemo_flow: failed to queue JS tool callback: {status:?}" + "nemo_relay: failed to queue JS tool callback: {status:?}" )); return Json::Null; } // TODO: This closure returns Json (not Result), so we cannot propagate // errors through the type system. Log the error so failures are not silent. - recv_json_or_null(rx, "nemo_flow: JS tool callback failed") + recv_json_or_null(rx, "nemo_relay: JS tool callback failed") }) } @@ -295,7 +295,7 @@ pub fn wrap_js_llm_sanitize_request_fn( ); if status != napi::Status::Ok { record_callback_error(format!( - "nemo_flow: failed to queue JS LLM sanitize request callback: {status:?}" + "nemo_relay: failed to queue JS LLM sanitize request callback: {status:?}" )); return request; } @@ -303,7 +303,7 @@ pub fn wrap_js_llm_sanitize_request_fn( // errors through the type system. Log the error so failures are not silent. recv_llm_request_or_value( rx, - "nemo_flow: JS LLM sanitize request callback failed", + "nemo_relay: JS LLM sanitize request callback failed", request, ) }) @@ -327,13 +327,13 @@ pub fn wrap_js_llm_response_fn( ); if status != napi::Status::Ok { record_callback_error(format!( - "nemo_flow: failed to queue JS LLM response callback: {status:?}" + "nemo_relay: failed to queue JS LLM response callback: {status:?}" )); return response; } // TODO: This closure returns Json (not Result), so we cannot propagate // errors through the type system. Log the error and fall back to original response. - recv_json_or_value(rx, "nemo_flow: JS LLM response callback failed", response) + recv_json_or_value(rx, "nemo_relay: JS LLM response callback failed", response) }) } @@ -409,7 +409,7 @@ pub fn wrap_js_collector_fn( if status == napi::Status::Ok { Ok(()) } else { - let message = format!("nemo_flow: failed to queue JS collector callback: {status:?}"); + let message = format!("nemo_relay: failed to queue JS collector callback: {status:?}"); record_callback_error(message.clone()); Err(FlowError::Internal(message)) } @@ -436,13 +436,13 @@ pub fn wrap_js_finalizer_fn( ); if status != napi::Status::Ok { record_callback_error(format!( - "nemo_flow: failed to queue JS finalizer callback: {status:?}" + "nemo_relay: failed to queue JS finalizer callback: {status:?}" )); return Json::Null; } // TODO: This closure returns Json (not Result), so we cannot propagate // errors through the type system. Log the error so failures are not silent. - recv_json_or_null(rx, "nemo_flow: JS finalizer callback failed") + recv_json_or_null(rx, "nemo_relay: JS finalizer callback failed") }) } @@ -456,7 +456,7 @@ pub fn wrap_js_event_subscriber( Ok(event) => event.into_json(), Err(error) => { record_callback_error(format!( - "nemo_flow: failed to serialize JS event subscriber payload: {error}" + "nemo_relay: failed to serialize JS event subscriber payload: {error}" )); return; } @@ -464,7 +464,7 @@ pub fn wrap_js_event_subscriber( let status = func.call(event_json, ThreadsafeFunctionCallMode::NonBlocking); if status != napi::Status::Ok { record_callback_error(format!( - "nemo_flow: failed to queue JS event subscriber callback: {status:?}" + "nemo_relay: failed to queue JS event subscriber callback: {status:?}" )); } }) diff --git a/crates/node/src/convert.rs b/crates/node/src/convert.rs index 08fde44bc..92ceba0b3 100644 --- a/crates/node/src/convert.rs +++ b/crates/node/src/convert.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Conversion utilities for bridging between NeMo Flow core types and NAPI types. +//! Conversion utilities for bridging between NeMo Relay core types and NAPI types. //! //! Provides helpers to convert errors and optional JSON values between the core //! runtime representation and the NAPI binding layer. @@ -11,7 +11,7 @@ use std::sync::{LazyLock, Mutex}; use chrono::{DateTime, Utc}; use serde_json::Value as Json; -use nemo_flow::error::FlowError; +use nemo_relay::error::FlowError; static LAST_CALLBACK_ERROR: LazyLock>> = LazyLock::new(|| Mutex::new(None)); diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index ca13a1433..7a0e49c17 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! NAPI-RS bindings for NeMo Flow, exposing the agent runtime framework to Node.js. +//! NAPI-RS bindings for NeMo Relay, exposing the agent runtime framework to Node.js. //! //! This crate provides JavaScript/TypeScript access to scope management, tool and LLM //! lifecycle operations, guardrails, intercepts, event subscriptions, and ATIF trajectory diff --git a/crates/node/src/promise_call.rs b/crates/node/src/promise_call.rs index 2871502bc..82a461a45 100644 --- a/crates/node/src/promise_call.rs +++ b/crates/node/src/promise_call.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Promise-aware JS function calling for NeMo Flow NAPI bindings. +//! Promise-aware JS function calling for NeMo Relay NAPI bindings. //! //! This module wraps JS middleware callbacks so Rust can call them from any thread //! and await either synchronous return values or Promise-returning callbacks. @@ -20,7 +20,7 @@ use napi::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction}; use napi::{Env, JsFunction, JsUnknown, NapiRaw, NapiValue}; use serde_json::Value as Json; -use nemo_flow::error::{FlowError, Result as FlowResult}; +use nemo_relay::error::{FlowError, Result as FlowResult}; pub type JsonNextFn = Arc Pin> + Send>> + Send + Sync>; @@ -101,20 +101,22 @@ fn undefined_to_unknown(env: &Env) -> napi::Result { fn build_next_unknown(env: &Env, next: NextFn) -> napi::Result { let next_fn = match next { - NextFn::Json(next) => env.create_function_from_closure("__nemo_flow_next", move |ctx| { - let arg = ctx.get::(0).unwrap_or(Json::Null); - let next = next.clone(); - ctx.env.execute_tokio_future( - async move { - next(arg) - .await - .map_err(|e| napi::Error::from_reason(e.to_string())) - }, - |_env, value| Ok(value), - ) - })?, + NextFn::Json(next) => { + env.create_function_from_closure("__nemo_relay_next", move |ctx| { + let arg = ctx.get::(0).unwrap_or(Json::Null); + let next = next.clone(); + ctx.env.execute_tokio_future( + async move { + next(arg) + .await + .map_err(|e| napi::Error::from_reason(e.to_string())) + }, + |_env, value| Ok(value), + ) + })? + } NextFn::Stream(next) => { - env.create_function_from_closure("__nemo_flow_next", move |ctx| { + env.create_function_from_closure("__nemo_relay_next", move |ctx| { let arg = ctx.get::(0).unwrap_or(Json::Null); let next = next.clone(); ctx.env.execute_tokio_future( @@ -137,13 +139,13 @@ fn build_completion_unknowns( completion: CallCompletion, ) -> napi::Result<(JsUnknown, JsUnknown)> { let resolve_completion = completion.clone(); - let resolve = env.create_function_from_closure("__nemo_flow_resolve", move |ctx| { + let resolve = env.create_function_from_closure("__nemo_relay_resolve", move |ctx| { let value = ctx.get::(0).unwrap_or(Json::Null); resolve_completion.send(Ok(value)); ctx.env.get_undefined() })?; - let reject = env.create_function_from_closure("__nemo_flow_reject", move |ctx| { + let reject = env.create_function_from_closure("__nemo_relay_reject", move |ctx| { let message = rejection_message( ctx.get::(0), ctx.get::(0) @@ -162,7 +164,7 @@ fn build_completion_unknowns( fn create_promise_wrapper(env: &Env, callable: &JsFunction) -> napi::Result { let factory: JsFunction = env.run_script( - r#"((fn) => function __nemo_flow_promise_wrapper(error, arg0, next, resolve, reject) { + r#"((fn) => function __nemo_relay_promise_wrapper(error, arg0, next, resolve, reject) { if (error != null) { reject(error); return; diff --git a/crates/node/src/stream.rs b/crates/node/src/stream.rs index d4a968e45..3cac321cc 100644 --- a/crates/node/src/stream.rs +++ b/crates/node/src/stream.rs @@ -9,7 +9,7 @@ use napi::bindgen_prelude::*; use napi_derive::napi; -use nemo_flow::error::Result as FlowResult; +use nemo_relay::error::Result as FlowResult; use serde_json::Value as Json; /// An async iterator over chunks from a streaming LLM response. diff --git a/crates/node/src/types/mod.rs b/crates/node/src/types/mod.rs index 3327ddc5d..58cb37c04 100644 --- a/crates/node/src/types/mod.rs +++ b/crates/node/src/types/mod.rs @@ -1,23 +1,23 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Type definitions for the NeMo Flow Node.js NAPI bindings. +//! Type definitions for the NeMo Relay Node.js NAPI bindings. //! //! Contains enums, handle wrappers, request/response structures, event types, //! and attribute constants that are exposed to JavaScript/TypeScript consumers. //! Doc comments on `#[napi]` items are emitted into the generated `index.d.ts`. use napi_derive::napi; -use nemo_flow::api::runtime::{ScopeStackHandle, create_scope_stack}; +use nemo_relay::api::runtime::{ScopeStackHandle, create_scope_stack}; use serde::Serialize; use serde_json::Value as Json; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::{LlmHandle as CoreLlmHandle, LlmRequest as CoreLlmRequest}; -use nemo_flow::api::scope::{ScopeHandle as CoreScopeHandle, ScopeType as CoreScopeType}; -use nemo_flow::api::tool::ToolHandle as CoreToolHandle; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::{LlmHandle as CoreLlmHandle, LlmRequest as CoreLlmRequest}; +use nemo_relay::api::scope::{ScopeHandle as CoreScopeHandle, ScopeType as CoreScopeType}; +use nemo_relay::api::tool::ToolHandle as CoreToolHandle; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; // --------------------------------------------------------------------------- // Enums @@ -338,9 +338,9 @@ impl OpenAIChatCodec { #[napi(constructor)] pub fn new() -> Self { Self { - inner_codec: std::sync::Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), + inner_codec: std::sync::Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::openai_chat::OpenAIChatCodec, + nemo_relay::codec::openai_chat::OpenAIChatCodec, ), } } @@ -398,10 +398,10 @@ impl OpenAIResponsesCodec { pub fn new() -> Self { Self { inner_codec: std::sync::Arc::new( - nemo_flow::codec::openai_responses::OpenAIResponsesCodec, + nemo_relay::codec::openai_responses::OpenAIResponsesCodec, ), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::openai_responses::OpenAIResponsesCodec, + nemo_relay::codec::openai_responses::OpenAIResponsesCodec, ), } } @@ -458,9 +458,9 @@ impl AnthropicMessagesCodec { #[napi(constructor)] pub fn new() -> Self { Self { - inner_codec: std::sync::Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), + inner_codec: std::sync::Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::anthropic::AnthropicMessagesCodec, + nemo_relay::codec::anthropic::AnthropicMessagesCodec, ), } } diff --git a/crates/node/tests/adaptive_tests.mjs b/crates/node/tests/adaptive_tests.mjs index 727328147..540590fa2 100644 --- a/crates/node/tests/adaptive_tests.mjs +++ b/crates/node/tests/adaptive_tests.mjs @@ -168,7 +168,7 @@ describe('adaptive helpers', () => { kind: 'redis', config: { url: 'redis://127.0.0.1:6379', - key_prefix: 'nemo_flow:', + key_prefix: 'nemo_relay:', }, }); }); diff --git a/crates/node/tests/atof_tests.mjs b/crates/node/tests/atof_tests.mjs index 45d5ba931..acaba9698 100644 --- a/crates/node/tests/atof_tests.mjs +++ b/crates/node/tests/atof_tests.mjs @@ -12,7 +12,7 @@ const require = createRequire(import.meta.url); const { AtofExporter, ScopeType, pushScope, popScope, event } = require('../index.js'); function tempDir(prefix) { - return mkdtempSync(join(tmpdir(), `nemo-flow-${prefix}-`)); + return mkdtempSync(join(tmpdir(), `nemo-relay-${prefix}-`)); } function lines(path) { @@ -26,7 +26,7 @@ function lines(path) { describe('AtofExporter', () => { it('constructs with defaults and rejects invalid mode', () => { const exporter = new AtofExporter({ outputDirectory: tempDir('node-atof-defaults') }); - assert.match(exporter.path, /nemo-flow-events-\d{4}-\d{2}-\d{2}-\d{2}\.\d{2}\.\d{2}\.jsonl$/); + assert.match(exporter.path, /nemo-relay-events-\d{4}-\d{2}-\d{2}-\d{2}\.\d{2}\.\d{2}\.jsonl$/); exporter.shutdown(); assert.throws(() => new AtofExporter({ mode: 'invalid' }), /mode must be/i); diff --git a/crates/node/tests/index_loader_tests.mjs b/crates/node/tests/index_loader_tests.mjs index 6c7b88f67..054ceb9b8 100644 --- a/crates/node/tests/index_loader_tests.mjs +++ b/crates/node/tests/index_loader_tests.mjs @@ -116,17 +116,17 @@ describe('index.js loader', () => { const binding = realLib; const localCases = [ - ['android', 'arm64', 'nemo-flow.android-arm64.node', './nemo-flow.android-arm64.node'], - ['android', 'arm', 'nemo-flow.android-arm-eabi.node', './nemo-flow.android-arm-eabi.node'], - ['win32', 'x64', 'nemo-flow.win32-x64-msvc.node', './nemo-flow.win32-x64-msvc.node'], - ['win32', 'ia32', 'nemo-flow.win32-ia32-msvc.node', './nemo-flow.win32-ia32-msvc.node'], - ['win32', 'arm64', 'nemo-flow.win32-arm64-msvc.node', './nemo-flow.win32-arm64-msvc.node'], - ['freebsd', 'x64', 'nemo-flow.freebsd-x64.node', './nemo-flow.freebsd-x64.node'], - ['linux', 'x64', 'nemo-flow.linux-x64-gnu.node', './nemo-flow.linux-x64-gnu.node'], - ['linux', 'arm64', 'nemo-flow.linux-arm64-gnu.node', './nemo-flow.linux-arm64-gnu.node'], - ['linux', 'arm', 'nemo-flow.linux-arm-gnueabihf.node', './nemo-flow.linux-arm-gnueabihf.node'], - ['linux', 'riscv64', 'nemo-flow.linux-riscv64-gnu.node', './nemo-flow.linux-riscv64-gnu.node'], - ['linux', 's390x', 'nemo-flow.linux-s390x-gnu.node', './nemo-flow.linux-s390x-gnu.node'], + ['android', 'arm64', 'nemo-relay.android-arm64.node', './nemo-relay.android-arm64.node'], + ['android', 'arm', 'nemo-relay.android-arm-eabi.node', './nemo-relay.android-arm-eabi.node'], + ['win32', 'x64', 'nemo-relay.win32-x64-msvc.node', './nemo-relay.win32-x64-msvc.node'], + ['win32', 'ia32', 'nemo-relay.win32-ia32-msvc.node', './nemo-relay.win32-ia32-msvc.node'], + ['win32', 'arm64', 'nemo-relay.win32-arm64-msvc.node', './nemo-relay.win32-arm64-msvc.node'], + ['freebsd', 'x64', 'nemo-relay.freebsd-x64.node', './nemo-relay.freebsd-x64.node'], + ['linux', 'x64', 'nemo-relay.linux-x64-gnu.node', './nemo-relay.linux-x64-gnu.node'], + ['linux', 'arm64', 'nemo-relay.linux-arm64-gnu.node', './nemo-relay.linux-arm64-gnu.node'], + ['linux', 'arm', 'nemo-relay.linux-arm-gnueabihf.node', './nemo-relay.linux-arm-gnueabihf.node'], + ['linux', 'riscv64', 'nemo-relay.linux-riscv64-gnu.node', './nemo-relay.linux-riscv64-gnu.node'], + ['linux', 's390x', 'nemo-relay.linux-s390x-gnu.node', './nemo-relay.linux-s390x-gnu.node'], ]; it('loads local binary branches for supported platforms', () => { @@ -147,18 +147,18 @@ describe('index.js loader', () => { it('loads package branches for supported platforms', () => { const packageCases = [ - ['android', 'arm64', 'nemo-flow-node-android-arm64'], - ['android', 'arm', 'nemo-flow-node-android-arm-eabi'], - ['win32', 'x64', 'nemo-flow-node-win32-x64-msvc'], - ['win32', 'ia32', 'nemo-flow-node-win32-ia32-msvc'], - ['win32', 'arm64', 'nemo-flow-node-win32-arm64-msvc'], - ['darwin', 'x64', 'nemo-flow-node-darwin-universal'], - ['freebsd', 'x64', 'nemo-flow-node-freebsd-x64'], - ['linux', 'x64', 'nemo-flow-node-linux-x64-gnu'], - ['linux', 'arm64', 'nemo-flow-node-linux-arm64-gnu'], - ['linux', 'arm', 'nemo-flow-node-linux-arm-gnueabihf'], - ['linux', 'riscv64', 'nemo-flow-node-linux-riscv64-gnu'], - ['linux', 's390x', 'nemo-flow-node-linux-s390x-gnu'], + ['android', 'arm64', 'nemo-relay-node-android-arm64'], + ['android', 'arm', 'nemo-relay-node-android-arm-eabi'], + ['win32', 'x64', 'nemo-relay-node-win32-x64-msvc'], + ['win32', 'ia32', 'nemo-relay-node-win32-ia32-msvc'], + ['win32', 'arm64', 'nemo-relay-node-win32-arm64-msvc'], + ['darwin', 'x64', 'nemo-relay-node-darwin-universal'], + ['freebsd', 'x64', 'nemo-relay-node-freebsd-x64'], + ['linux', 'x64', 'nemo-relay-node-linux-x64-gnu'], + ['linux', 'arm64', 'nemo-relay-node-linux-arm64-gnu'], + ['linux', 'arm', 'nemo-relay-node-linux-arm-gnueabihf'], + ['linux', 'riscv64', 'nemo-relay-node-linux-riscv64-gnu'], + ['linux', 's390x', 'nemo-relay-node-linux-s390x-gnu'], ]; for (const [platformName, archName, specifier] of packageCases) { @@ -185,11 +185,11 @@ describe('index.js loader', () => { }, }, providedModules: { - 'nemo-flow-node-linux-x64-musl': binding, + 'nemo-relay-node-linux-x64-musl': binding, }, }); assert.equal(viaReport.exports.toolCall, binding.toolCall); - assert.ok(viaReport.calls.includes('nemo-flow-node-linux-x64-musl')); + assert.ok(viaReport.calls.includes('nemo-relay-node-linux-x64-musl')); const viaLdd = loadIndexForTest({ platform: 'linux', @@ -197,12 +197,12 @@ describe('index.js loader', () => { processReport: null, lddContent: 'musl libc', providedModules: { - 'nemo-flow-node-linux-arm64-musl': binding, + 'nemo-relay-node-linux-arm64-musl': binding, }, }); assert.equal(viaLdd.exports.toolCall, binding.toolCall); assert.ok(viaLdd.calls.includes('child_process')); - assert.ok(viaLdd.calls.includes('nemo-flow-node-linux-arm64-musl')); + assert.ok(viaLdd.calls.includes('nemo-relay-node-linux-arm64-musl')); const viaLddFailure = loadIndexForTest({ platform: 'linux', @@ -210,59 +210,59 @@ describe('index.js loader', () => { processReport: null, childProcessThrows: true, providedModules: { - 'nemo-flow-node-linux-arm-musleabihf': binding, + 'nemo-relay-node-linux-arm-musleabihf': binding, }, }); assert.equal(viaLddFailure.exports.toolCall, binding.toolCall); - assert.ok(viaLddFailure.calls.includes('nemo-flow-node-linux-arm-musleabihf')); + assert.ok(viaLddFailure.calls.includes('nemo-relay-node-linux-arm-musleabihf')); }); it('falls back from darwin universal to arch-specific binaries', () => { const universalLocal = loadIndexForTest({ platform: 'darwin', arch: 'arm64', - existingFiles: ['nemo-flow.darwin-universal.node'], + existingFiles: ['nemo-relay.darwin-universal.node'], providedModules: { - './nemo-flow.darwin-universal.node': binding, + './nemo-relay.darwin-universal.node': binding, }, }); assert.equal(universalLocal.exports.toolCall, binding.toolCall); - assert.ok(universalLocal.calls.includes('./nemo-flow.darwin-universal.node')); + assert.ok(universalLocal.calls.includes('./nemo-relay.darwin-universal.node')); const x64 = loadIndexForTest({ platform: 'darwin', arch: 'x64', - existingFiles: ['nemo-flow.darwin-x64.node'], + existingFiles: ['nemo-relay.darwin-x64.node'], providedModules: { - 'nemo-flow-node-darwin-universal': new Error('universal missing'), - './nemo-flow.darwin-x64.node': binding, + 'nemo-relay-node-darwin-universal': new Error('universal missing'), + './nemo-relay.darwin-x64.node': binding, }, }); assert.equal(x64.exports.toolCall, binding.toolCall); - assert.ok(x64.calls.includes('nemo-flow-node-darwin-universal')); - assert.ok(x64.calls.includes('./nemo-flow.darwin-x64.node')); + assert.ok(x64.calls.includes('nemo-relay-node-darwin-universal')); + assert.ok(x64.calls.includes('./nemo-relay.darwin-x64.node')); const x64PackageFallback = loadIndexForTest({ platform: 'darwin', arch: 'x64', providedModules: { - 'nemo-flow-node-darwin-universal': new Error('universal missing'), - 'nemo-flow-node-darwin-x64': binding, + 'nemo-relay-node-darwin-universal': new Error('universal missing'), + 'nemo-relay-node-darwin-x64': binding, }, }); assert.equal(x64PackageFallback.exports.toolCall, binding.toolCall); - assert.ok(x64PackageFallback.calls.includes('nemo-flow-node-darwin-x64')); + assert.ok(x64PackageFallback.calls.includes('nemo-relay-node-darwin-x64')); const arm64 = loadIndexForTest({ platform: 'darwin', arch: 'arm64', providedModules: { - 'nemo-flow-node-darwin-universal': new Error('universal missing'), - 'nemo-flow-node-darwin-arm64': binding, + 'nemo-relay-node-darwin-universal': new Error('universal missing'), + 'nemo-relay-node-darwin-arm64': binding, }, }); assert.equal(arm64.exports.toolCall, binding.toolCall); - assert.ok(arm64.calls.includes('nemo-flow-node-darwin-arm64')); + assert.ok(arm64.calls.includes('nemo-relay-node-darwin-arm64')); }); it('throws unsupported platform and architecture errors', () => { @@ -324,7 +324,7 @@ describe('index.js loader', () => { platform: 'freebsd', arch: 'x64', providedModules: { - 'nemo-flow-node-freebsd-x64': failure, + 'nemo-relay-node-freebsd-x64': failure, }, }), /package missing/, @@ -339,7 +339,7 @@ describe('index.js loader', () => { platform: 'android', arch: 'arm64', providedModules: { - 'nemo-flow-node-android-arm64': androidArm64Failure, + 'nemo-relay-node-android-arm64': androidArm64Failure, }, }), /android arm64 package missing/, @@ -352,7 +352,7 @@ describe('index.js loader', () => { platform: 'android', arch: 'arm', providedModules: { - 'nemo-flow-node-android-arm-eabi': androidArmFailure, + 'nemo-relay-node-android-arm-eabi': androidArmFailure, }, }), /android arm package missing/, @@ -365,7 +365,7 @@ describe('index.js loader', () => { platform: 'win32', arch: 'x64', providedModules: { - 'nemo-flow-node-win32-x64-msvc': win32X64Failure, + 'nemo-relay-node-win32-x64-msvc': win32X64Failure, }, }), /win32 x64 package missing/, @@ -378,7 +378,7 @@ describe('index.js loader', () => { platform: 'win32', arch: 'ia32', providedModules: { - 'nemo-flow-node-win32-ia32-msvc': win32Ia32Failure, + 'nemo-relay-node-win32-ia32-msvc': win32Ia32Failure, }, }), /win32 ia32 package missing/, @@ -391,7 +391,7 @@ describe('index.js loader', () => { platform: 'win32', arch: 'arm64', providedModules: { - 'nemo-flow-node-win32-arm64-msvc': win32Arm64Failure, + 'nemo-relay-node-win32-arm64-msvc': win32Arm64Failure, }, }), /win32 arm64 package missing/, @@ -403,10 +403,10 @@ describe('index.js loader', () => { loadIndexForTest({ platform: 'darwin', arch: 'x64', - existingFiles: ['nemo-flow.darwin-x64.node'], + existingFiles: ['nemo-relay.darwin-x64.node'], providedModules: { - 'nemo-flow-node-darwin-universal': new Error('universal missing'), - './nemo-flow.darwin-x64.node': darwinX64LocalFailure, + 'nemo-relay-node-darwin-universal': new Error('universal missing'), + './nemo-relay.darwin-x64.node': darwinX64LocalFailure, }, }), /darwin x64 local missing/, @@ -418,10 +418,10 @@ describe('index.js loader', () => { loadIndexForTest({ platform: 'darwin', arch: 'arm64', - existingFiles: ['nemo-flow.darwin-arm64.node'], + existingFiles: ['nemo-relay.darwin-arm64.node'], providedModules: { - 'nemo-flow-node-darwin-universal': new Error('universal missing'), - './nemo-flow.darwin-arm64.node': darwinArm64LocalFailure, + 'nemo-relay-node-darwin-universal': new Error('universal missing'), + './nemo-relay.darwin-arm64.node': darwinArm64LocalFailure, }, }), /darwin arm64 local missing/, @@ -438,9 +438,9 @@ describe('index.js loader', () => { glibcVersionRuntime: null, }, }, - existingFiles: ['nemo-flow.linux-x64-musl.node'], + existingFiles: ['nemo-relay.linux-x64-musl.node'], providedModules: { - './nemo-flow.linux-x64-musl.node': x64MuslLocalFailure, + './nemo-relay.linux-x64-musl.node': x64MuslLocalFailure, }, }), /x64 musl local missing/, @@ -452,9 +452,9 @@ describe('index.js loader', () => { loadIndexForTest({ platform: 'linux', arch: 'x64', - existingFiles: ['nemo-flow.linux-x64-gnu.node'], + existingFiles: ['nemo-relay.linux-x64-gnu.node'], providedModules: { - './nemo-flow.linux-x64-gnu.node': x64GnuLocalFailure, + './nemo-relay.linux-x64-gnu.node': x64GnuLocalFailure, }, }), /x64 gnu local missing/, @@ -471,9 +471,9 @@ describe('index.js loader', () => { glibcVersionRuntime: null, }, }, - existingFiles: ['nemo-flow.linux-arm64-musl.node'], + existingFiles: ['nemo-relay.linux-arm64-musl.node'], providedModules: { - './nemo-flow.linux-arm64-musl.node': arm64MuslLocalFailure, + './nemo-relay.linux-arm64-musl.node': arm64MuslLocalFailure, }, }), /arm64 musl local missing/, @@ -486,7 +486,7 @@ describe('index.js loader', () => { platform: 'linux', arch: 'arm64', providedModules: { - 'nemo-flow-node-linux-arm64-gnu': arm64GnuFailure, + 'nemo-relay-node-linux-arm64-gnu': arm64GnuFailure, }, }), /arm64 gnu package missing/, @@ -503,9 +503,9 @@ describe('index.js loader', () => { glibcVersionRuntime: null, }, }, - existingFiles: ['nemo-flow.linux-arm-musleabihf.node'], + existingFiles: ['nemo-relay.linux-arm-musleabihf.node'], providedModules: { - './nemo-flow.linux-arm-musleabihf.node': armMuslLocalFailure, + './nemo-relay.linux-arm-musleabihf.node': armMuslLocalFailure, }, }), /arm musl local missing/, @@ -518,7 +518,7 @@ describe('index.js loader', () => { platform: 'linux', arch: 'arm', providedModules: { - 'nemo-flow-node-linux-arm-gnueabihf': armGnuFailure, + 'nemo-relay-node-linux-arm-gnueabihf': armGnuFailure, }, }), /arm gnu package missing/, @@ -535,9 +535,9 @@ describe('index.js loader', () => { glibcVersionRuntime: null, }, }, - existingFiles: ['nemo-flow.linux-riscv64-musl.node'], + existingFiles: ['nemo-relay.linux-riscv64-musl.node'], providedModules: { - './nemo-flow.linux-riscv64-musl.node': riscvMuslLocalFailure, + './nemo-relay.linux-riscv64-musl.node': riscvMuslLocalFailure, }, }), /riscv musl local missing/, @@ -555,7 +555,7 @@ describe('index.js loader', () => { }, }, providedModules: { - 'nemo-flow-node-linux-riscv64-musl': riscvMuslFailure, + 'nemo-relay-node-linux-riscv64-musl': riscvMuslFailure, }, }), /riscv musl package missing/, @@ -568,7 +568,7 @@ describe('index.js loader', () => { platform: 'linux', arch: 'riscv64', providedModules: { - 'nemo-flow-node-linux-riscv64-gnu': riscvGnuFailure, + 'nemo-relay-node-linux-riscv64-gnu': riscvGnuFailure, }, }), /riscv gnu package missing/, @@ -581,7 +581,7 @@ describe('index.js loader', () => { platform: 'linux', arch: 's390x', providedModules: { - 'nemo-flow-node-linux-s390x-gnu': s390xFailure, + 'nemo-relay-node-linux-s390x-gnu': s390xFailure, }, }), /s390x package missing/, @@ -595,7 +595,7 @@ describe('index.js loader', () => { platform: 'freebsd', arch: 'x64', providedModules: { - 'nemo-flow-node-freebsd-x64': null, + 'nemo-relay-node-freebsd-x64': null, }, }), /Failed to load native binding/, diff --git a/crates/node/tests/llm_tests.mjs b/crates/node/tests/llm_tests.mjs index e4c732927..16a3c4ffd 100644 --- a/crates/node/tests/llm_tests.mjs +++ b/crates/node/tests/llm_tests.mjs @@ -642,10 +642,10 @@ describe('LLM intercepts', () => { 'stream_llm', native, (wrapper) => { - lib.pushStreamChunk(wrapper.__nemo_flow_stream_id, { - chunk: wrapper.__nemo_flow_native.content.intercepted, + lib.pushStreamChunk(wrapper.__nemo_relay_stream_id, { + chunk: wrapper.__nemo_relay_native.content.intercepted, }); - lib.endStream(wrapper.__nemo_flow_stream_id); + lib.endStream(wrapper.__nemo_relay_stream_id); }, null, null, @@ -728,10 +728,10 @@ describe('LLM intercepts', () => { 'stream_invalid_next_llm', makeNative(), (wrapper) => { - lib.pushStreamChunk(wrapper.__nemo_flow_stream_id, { + lib.pushStreamChunk(wrapper.__nemo_relay_stream_id, { chunk: true, }); - lib.endStream(wrapper.__nemo_flow_stream_id); + lib.endStream(wrapper.__nemo_relay_stream_id); }, null, null, diff --git a/crates/node/tests/observability_plugin_tests.mjs b/crates/node/tests/observability_plugin_tests.mjs index 7c6625fbd..c4e21fc1a 100644 --- a/crates/node/tests/observability_plugin_tests.mjs +++ b/crates/node/tests/observability_plugin_tests.mjs @@ -14,7 +14,7 @@ const observability = require('../observability.js'); const { ScopeType, pushScope, popScope, event } = require('../index.js'); function tempDir(prefix) { - return mkdtempSync(join(tmpdir(), `nemo-flow-${prefix}-`)); + return mkdtempSync(join(tmpdir(), `nemo-relay-${prefix}-`)); } describe('observability plugin helpers', () => { @@ -23,16 +23,16 @@ describe('observability plugin helpers', () => { assert.deepEqual(observability.atofConfig(), { enabled: false, mode: 'append' }); assert.deepEqual(observability.atifConfig(), { enabled: false, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', }); assert.deepEqual(observability.otlpConfig(), { enabled: false, transport: 'http_binary', headers: {}, resource_attributes: {}, - service_name: 'nemo-flow', + service_name: 'nemo-relay', timeout_millis: 3000, }); @@ -53,10 +53,7 @@ describe('observability plugin helpers', () => { }), ], }); - assert.deepEqual( - report.diagnostics.map((diagnostic) => diagnostic.field).sort(), - ['filename_template', 'mode'], - ); + assert.deepEqual(report.diagnostics.map((diagnostic) => diagnostic.field).sort(), ['filename_template', 'mode']); }); it('activates ATOF and ATIF file sinks', async () => { @@ -99,7 +96,10 @@ describe('observability plugin helpers', () => { } const records = readFileSync(join(outputDirectory, 'events.jsonl'), 'utf8').trim().split('\n').map(JSON.parse); - assert.deepEqual(records.map((record) => record.kind), ['scope', 'mark', 'scope']); + assert.deepEqual( + records.map((record) => record.kind), + ['scope', 'mark', 'scope'], + ); const trajectory = JSON.parse(readFileSync(join(outputDirectory, `trajectory-${records[0].uuid}.json`), 'utf8')); assert.equal(trajectory.agent.name, 'node-agent'); diff --git a/crates/node/tests/scope_local_tests.mjs b/crates/node/tests/scope_local_tests.mjs index 9acacbdf4..ebefb65d1 100644 --- a/crates/node/tests/scope_local_tests.mjs +++ b/crates/node/tests/scope_local_tests.mjs @@ -574,10 +574,10 @@ describe('Scope-local auto-cleanup on scope pop', () => { 'sl_cleanup_llm_stream_exec_call', makeNative(), (wrapper) => { - lib.pushStreamChunk(wrapper.__nemo_flow_stream_id, { - sawIntercept: wrapper.__nemo_flow_native.content.fromPoppedScope || false, + lib.pushStreamChunk(wrapper.__nemo_relay_stream_id, { + sawIntercept: wrapper.__nemo_relay_native.content.fromPoppedScope || false, }); - lib.endStream(wrapper.__nemo_flow_stream_id); + lib.endStream(wrapper.__nemo_relay_stream_id); }, null, null, @@ -1035,10 +1035,10 @@ describe('Scope-local LLM intercepts', () => { 'sl_llm_stream_compose_call', makeNative(), (wrapper) => { - lib.pushStreamChunk(wrapper.__nemo_flow_stream_id, { - downstream: wrapper.__nemo_flow_native.content.touchedByScopeStream, + lib.pushStreamChunk(wrapper.__nemo_relay_stream_id, { + downstream: wrapper.__nemo_relay_native.content.touchedByScopeStream, }); - lib.endStream(wrapper.__nemo_flow_stream_id); + lib.endStream(wrapper.__nemo_relay_stream_id); }, null, null, @@ -1090,10 +1090,10 @@ describe('Scope-local LLM intercepts', () => { 'sl_llm_stream_invalid_call', makeNative(), (wrapper) => { - lib.pushStreamChunk(wrapper.__nemo_flow_stream_id, { + lib.pushStreamChunk(wrapper.__nemo_relay_stream_id, { shouldNotRun: true, }); - lib.endStream(wrapper.__nemo_flow_stream_id); + lib.endStream(wrapper.__nemo_relay_stream_id); }, null, null, diff --git a/crates/node/tests/typed_tests.mjs b/crates/node/tests/typed_tests.mjs index 5a5c63498..cdc27cb94 100644 --- a/crates/node/tests/typed_tests.mjs +++ b/crates/node/tests/typed_tests.mjs @@ -552,18 +552,9 @@ describe('typedLlmExecute', () => { event.scope_category === 'end' && event.name === 'typed_anthropic_codec_llm', ); - assert.equal( - endEvent.category_profile.annotated_response.model, - 'claude-3-5-sonnet', - ); - assert.equal( - endEvent.category_profile.annotated_response.message, - 'Anthropic hello', - ); - assert.equal( - endEvent.category_profile.annotated_response.finish_reason, - 'complete', - ); + assert.equal(endEvent.category_profile.annotated_response.model, 'claude-3-5-sonnet'); + assert.equal(endEvent.category_profile.annotated_response.message, 'Anthropic hello'); + assert.equal(endEvent.category_profile.annotated_response.finish_reason, 'complete'); } finally { deregisterSubscriber('typed_anthropic_codec_sub'); popScope(scope); @@ -795,18 +786,9 @@ describe('typedLlmStreamExecute', () => { event.scope_category === 'end' && event.name === 'typed_responses_stream_llm', ); - assert.equal( - endEvent.category_profile.annotated_response.model, - 'gpt-4.1-mini', - ); - assert.equal( - endEvent.category_profile.annotated_response.message, - 'hello world', - ); - assert.equal( - endEvent.category_profile.annotated_response.finish_reason, - 'complete', - ); + assert.equal(endEvent.category_profile.annotated_response.model, 'gpt-4.1-mini'); + assert.equal(endEvent.category_profile.annotated_response.message, 'hello world'); + assert.equal(endEvent.category_profile.annotated_response.finish_reason, 'complete'); } finally { deregisterSubscriber('typed_responses_stream_sub'); deregisterLlmRequestIntercept('typed_responses_stream_req'); diff --git a/crates/node/typed.d.ts b/crates/node/typed.d.ts index c8570358c..fdbaf21cc 100644 --- a/crates/node/typed.d.ts +++ b/crates/node/typed.d.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Typed wrappers for NeMo Flow Node.js execute APIs. + * Typed wrappers for NeMo Relay Node.js execute APIs. * * Provides generic typed versions of `toolCallExecute` and `llmCallExecute` * that use explicit `Codec` objects to serialize/deserialize at the API @@ -32,7 +32,7 @@ export interface LlmRequestShape { * A codec for annotating and unwrapping LLM JSON request payloads. * * Use when an LLM integration needs custom request parsing or normalization - * before the raw payload is passed through the NeMo Flow LLM middleware + * before the raw payload is passed through the NeMo Relay LLM middleware * pipeline. */ export interface LlmCodec { diff --git a/crates/node/typed.js b/crates/node/typed.js index f35b44ef6..5b9cceab5 100644 --- a/crates/node/typed.js +++ b/crates/node/typed.js @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Typed wrappers for NeMo Flow Node.js execute APIs. + * Typed wrappers for NeMo Relay Node.js execute APIs. * * Provides generic typed versions of `toolCallExecute` and `llmCallExecute` * that use explicit `Codec` objects to serialize/deserialize at the API @@ -222,8 +222,8 @@ async function typedLlmStreamExecute(name, request, func, collector, finalizer, // and pushes each chunk into Rust via the exported pushStreamChunk function. // The request and stream ID are passed as a wrapper object. const jsonFunc = (wrapper) => { - const req = wrapper.__nemo_flow_native; - const streamId = wrapper.__nemo_flow_stream_id; + const req = wrapper.__nemo_relay_native; + const streamId = wrapper.__nemo_relay_stream_id; (async () => { try { for await (const typedChunk of func(req)) { diff --git a/crates/python/Cargo.toml b/crates/python/Cargo.toml index 8cb2c3d0d..6f20de35a 100644 --- a/crates/python/Cargo.toml +++ b/crates/python/Cargo.toml @@ -2,12 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-python" +name = "nemo-relay-python" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Python native extension bindings for NeMo Flow built with PyO3." +description = "Python native extension bindings for NeMo Relay built with PyO3." readme = "README.md" [lints] @@ -18,8 +18,8 @@ name = "_native" crate-type = ["cdylib", "rlib"] [dependencies] -nemo-flow = { workspace = true, features = ["otel", "openinference"] } -nemo-flow-adaptive = { workspace = true, features = ["redis-backend"] } +nemo-relay = { workspace = true, features = ["otel", "openinference"] } +nemo-relay-adaptive = { workspace = true, features = ["redis-backend"] } pyo3 = { version = "0.28.2", features = ["abi3", "abi3-py311", "experimental-inspect", "macros"] } pyo3-async-runtimes = { version = "0.28.0", features = ["tokio-runtime"] } pythonize = "0.28.0" diff --git a/crates/python/README.md b/crates/python/README.md index e15b3b9bc..b5c0e3336 100644 --- a/crates/python/README.md +++ b/crates/python/README.md @@ -3,22 +3,22 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow Python Bindings +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay Python Bindings This crate builds the native extension behind the public Python package -`nemo-flow`. It connects Python applications to the Rust NeMo Flow runtime +`nemo-relay`. It connects Python applications to the Rust NeMo Relay runtime through PyO3 and Maturin. Most Python users should install the Python package rather than depend on this @@ -27,16 +27,16 @@ crate directly. ## Why Use It? - 🧩 **Bridge Python to the shared runtime**: Connect Python applications to the - Rust NeMo Flow runtime without reimplementing runtime semantics in Python. + Rust NeMo Relay runtime without reimplementing runtime semantics in Python. - 🛠️ **Build through standard Python packaging**: Use the repository `pyproject.toml`, Maturin, and PyO3 to produce the native extension behind - `nemo-flow`. + `nemo-relay`. - 🔁 **Keep binding behavior aligned**: Expose the same scopes, middleware, - plugins, lifecycle events, and adaptive helpers used by the rest of NeMo Flow. + plugins, lifecycle events, and adaptive helpers used by the rest of NeMo Relay. ## What You Get -- ✅ **Native extension**: The compiled `nemo_flow._native` module used by the +- ✅ **Native extension**: The compiled `nemo_relay._native` module used by the public Python package. - ✅ **Runtime APIs for Python**: Access to scopes, tool calls, LLM calls, middleware, subscribers, plugins, typed helpers, codecs, and adaptive helpers. @@ -50,13 +50,13 @@ crate directly. Install the published Python package: ```bash -uv add nemo-flow +uv add nemo-relay ``` If you are not using `uv`, install it with `pip`: ```bash -pip install nemo-flow +pip install nemo-relay ``` For local source development from the repository root: @@ -70,12 +70,12 @@ uv sync Import the public Python package and create a scoped runtime boundary: ```python -import nemo_flow +import nemo_relay -with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope.event("initialized", handle=handle, data={"binding": "python"}) +with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope.event("initialized", handle=handle, data={"binding": "python"}) ``` ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/python/src/lib.rs b/crates/python/src/lib.rs index 0ad824aa1..a1b127f21 100644 --- a/crates/python/src/lib.rs +++ b/crates/python/src/lib.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! PyO3 native extension module for NeMo Flow. +//! PyO3 native extension module for NeMo Relay. //! //! This crate compiles to a `_native` Python C extension that is imported by the -//! `nemo_flow` Python package. It exposes all core runtime types and API functions +//! `nemo_relay` Python package. It exposes all core runtime types and API functions //! to Python via PyO3. //! //! ## Modules @@ -20,8 +20,8 @@ //! - `py_adaptive` — Python-facing adaptive helpers (`set_latency_sensitivity`) //! - `py_plugin` — Python-facing generic plugin config/registration helpers //! - `convert` — JSON ↔ Python conversion utilities -use nemo_flow::shared_runtime::initialize_shared_runtime_binding; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay::shared_runtime::initialize_shared_runtime_binding; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use pyo3::prelude::*; mod convert; @@ -44,7 +44,7 @@ mod test_support; fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> { initialize_shared_runtime_binding("python").map_err(|e| { pyo3::exceptions::PyRuntimeError::new_err(format!( - "failed to initialize NeMo Flow runtime ownership: {e}" + "failed to initialize NeMo Relay runtime ownership: {e}" )) })?; register_adaptive_component().map_err(|e| { diff --git a/crates/python/src/py_adaptive.rs b/crates/python/src/py_adaptive.rs index 1a2f68427..96e287fdc 100644 --- a/crates/python/src/py_adaptive.rs +++ b/crates/python/src/py_adaptive.rs @@ -7,13 +7,13 @@ use std::sync::Arc; use chrono::{DateTime, Utc}; -use nemo_flow::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; -use nemo_flow::codec::response::Usage; -use nemo_flow_adaptive::acg::{ +use nemo_relay::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; +use nemo_relay::codec::response::Usage; +use nemo_relay_adaptive::acg::{ AgentIdentity, CacheRequestFacts, CacheTelemetryEvent, CacheTelemetryProvider, }; -use nemo_flow_adaptive::context_helpers::set_latency_sensitivity as adaptive_set_latency_sensitivity; -use nemo_flow_adaptive::{AdaptiveConfig, AdaptiveRuntime}; +use nemo_relay_adaptive::context_helpers::set_latency_sensitivity as adaptive_set_latency_sensitivity; +use nemo_relay_adaptive::{AdaptiveConfig, AdaptiveRuntime}; use pyo3::prelude::*; use uuid::Uuid; @@ -28,7 +28,7 @@ pub struct PyAdaptiveRuntime { enum PyAdaptiveRuntimeState { Pending { config: AdaptiveConfig, - report: nemo_flow::plugin::ConfigReport, + report: nemo_relay::plugin::ConfigReport, }, Ready(AdaptiveRuntime), } @@ -236,13 +236,13 @@ impl PyAdaptiveRuntime { fn validate_adaptive_config_or_err( config: &AdaptiveConfig, -) -> PyResult { +) -> PyResult { let report = AdaptiveRuntime::validate_config(config); if report.has_errors() { let joined = report .diagnostics .iter() - .filter(|diag| diag.level == nemo_flow::plugin::DiagnosticLevel::Error) + .filter(|diag| diag.level == nemo_relay::plugin::DiagnosticLevel::Error) .map(|diag| diag.message.as_str()) .collect::>() .join("; "); diff --git a/crates/python/src/py_api/mod.rs b/crates/python/src/py_api/mod.rs index 532f18cfe..4912045d7 100644 --- a/crates/python/src/py_api/mod.rs +++ b/crates/python/src/py_api/mod.rs @@ -1,33 +1,33 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Python-facing API functions for the NeMo Flow runtime. +//! Python-facing API functions for the NeMo Relay runtime. //! //! Each `#[pyfunction]` here is registered into the `_native` module and -//! delegates to the corresponding function in [`nemo_flow::api`]. -//! The Python wrapper modules (`nemo_flow.scope`, `nemo_flow.tools`, etc.) +//! delegates to the corresponding function in [`nemo_relay::api`]. +//! The Python wrapper modules (`nemo_relay.scope`, `nemo_relay.tools`, etc.) //! re-export these under shorter, idiomatic names. use std::sync::Arc; -use nemo_flow::api::llm as core_llm_api; -use nemo_flow::api::llm::LlmAttributes; -use nemo_flow::api::registry as core_registry_api; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::runtime::{ +use nemo_relay::api::llm as core_llm_api; +use nemo_relay::api::llm::LlmAttributes; +use nemo_relay::api::registry as core_registry_api; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::runtime::{ TASK_SCOPE_STACK, create_scope_stack as create_scope_stack_handle, current_scope_stack as current_scope_stack_handle, scope_stack_active as scope_stack_is_active, set_thread_scope_stack as bind_thread_scope_stack, sync_thread_scope_stack as sync_bound_thread_scope_stack, task_scope_top, }; -use nemo_flow::api::scope as core_scope_api; -use nemo_flow::api::scope::ScopeAttributes; -use nemo_flow::api::subscriber as core_subscriber_api; -use nemo_flow::api::tool as core_tool_api; -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::codec::response::AnnotatedLlmResponse; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::{FlowError, Result as FlowResult}; +use nemo_relay::api::scope as core_scope_api; +use nemo_relay::api::scope::ScopeAttributes; +use nemo_relay::api::subscriber as core_subscriber_api; +use nemo_relay::api::tool as core_tool_api; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::codec::response::AnnotatedLlmResponse; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::{FlowError, Result as FlowResult}; use pyo3::prelude::*; use tokio_stream::StreamExt; use uuid::Uuid; @@ -123,7 +123,7 @@ pub fn create_scope_stack() -> PyScopeStack { /// Bind a ``ScopeStack`` to the current thread's thread-local storage. /// -/// This ensures that subsequent NeMo Flow API calls on this thread use the given +/// This ensures that subsequent NeMo Relay API calls on this thread use the given /// scope stack rather than a default one. Primarily useful when propagating /// scope context into worker threads (e.g. ``ThreadPoolExecutor``). /// @@ -137,7 +137,7 @@ pub fn set_thread_scope_stack(stack: &PyScopeStack) { /// Sync a ``ScopeStack`` to the current thread's Rust thread-local storage /// **without** marking it as explicitly set. /// -/// This is used internally by ``nemo_flow.get_scope_stack()`` to keep the Rust +/// This is used internally by ``nemo_relay.get_scope_stack()`` to keep the Rust /// thread-local in sync with the Python ``contextvars.ContextVar`` without /// affecting ``scope_stack_active()``. #[pyfunction] @@ -154,7 +154,7 @@ pub fn sync_thread_scope_stack(stack: &PyScopeStack) { /// present. /// /// .. note:: -/// The Python-level ``nemo_flow.scope_stack_active()`` wrapper also +/// The Python-level ``nemo_relay.scope_stack_active()`` wrapper also /// checks the ``contextvars.ContextVar`` and should be preferred in /// Python code. This native function is useful for non-async contexts /// where ``contextvars`` are not involved. diff --git a/crates/python/src/py_callable.rs b/crates/python/src/py_callable.rs index 79f6f09a9..07bc392ea 100644 --- a/crates/python/src/py_callable.rs +++ b/crates/python/src/py_callable.rs @@ -24,21 +24,21 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; -use nemo_flow::api::runtime::{ +use nemo_relay::api::runtime::{ EventSubscriberFn, LlmConditionalFn, LlmExecutionNextFn, LlmRequestInterceptFn, LlmSanitizeRequestFn, LlmSanitizeResponseFn, LlmStreamExecutionNextFn, ToolConditionalFn, ToolExecutionNextFn, ToolInterceptFn, ToolSanitizeFn, }; -use nemo_flow::error::{FlowError, Result as FlowResult}; +use nemo_relay::error::{FlowError, Result as FlowResult}; use pyo3::prelude::*; use serde_json::Value as Json; use tokio_stream::Stream; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; -use nemo_flow::codec::response::AnnotatedLlmResponse as AnnotatedLLMResponse; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest as AnnotatedLLMRequest; +use nemo_relay::codec::response::AnnotatedLlmResponse as AnnotatedLLMResponse; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; use crate::convert::{json_to_py, py_to_json}; use crate::py_types::{PyAnnotatedLLMRequest, PyAnnotatedLLMResponse, PyLLMRequest}; @@ -189,19 +189,19 @@ pub fn wrap_py_tool_fn(py_fn: Py) -> ToolSanitizeFn { let py_args = match json_to_py(py, &args) { Ok(v) => v, Err(e) => { - eprintln!("nemo_flow: json_to_py failed in tool fn for '{name}': {e}"); + eprintln!("nemo_relay: json_to_py failed in tool fn for '{name}': {e}"); return args.clone(); } }; let result = match py_fn.call1(py, (name, py_args)) { Ok(v) => v, Err(e) => { - eprintln!("nemo_flow: Python tool callable failed for '{name}': {e}"); + eprintln!("nemo_relay: Python tool callable failed for '{name}': {e}"); return args.clone(); } }; py_to_json(result.bind(py)).unwrap_or_else(|e| { - eprintln!("nemo_flow: py_to_json failed in tool fn for '{name}': {e}"); + eprintln!("nemo_relay: py_to_json failed in tool fn for '{name}': {e}"); args.clone() }) }) @@ -597,7 +597,7 @@ pub fn wrap_py_llm_sanitize_request_fn(py_fn: Py) -> LlmSanitizeRequestFn let result = match py_fn.call1(py, (py_req,)) { Ok(v) => v, Err(e) => { - eprintln!("nemo_flow: LLM sanitize request guardrail callable failed: {e}"); + eprintln!("nemo_relay: LLM sanitize request guardrail callable failed: {e}"); return request; } }; @@ -606,7 +606,7 @@ pub fn wrap_py_llm_sanitize_request_fn(py_fn: Py) -> LlmSanitizeRequestFn Ok(r) => r.inner, Err(e) => { eprintln!( - "nemo_flow: LLM sanitize request guardrail returned unexpected type \ + "nemo_relay: LLM sanitize request guardrail returned unexpected type \ (expected LlmRequest): {e}" ); request @@ -805,12 +805,12 @@ pub fn wrap_py_finalizer_fn(py_fn: Py) -> Box Json + Send let result = match py_fn.call0(py) { Ok(v) => v, Err(e) => { - eprintln!("nemo_flow: Python finalizer callable failed: {e}"); + eprintln!("nemo_relay: Python finalizer callable failed: {e}"); return Json::Null; } }; py_to_json(result.bind(py)).unwrap_or_else(|e| { - eprintln!("nemo_flow: py_to_json failed in finalizer: {e}"); + eprintln!("nemo_relay: py_to_json failed in finalizer: {e}"); Json::Null }) }) @@ -825,7 +825,7 @@ pub fn wrap_py_llm_sanitize_response_fn(py_fn: Py) -> LlmSanitizeResponse Ok(v) => v, Err(e) => { eprintln!( - "nemo_flow: json_to_py failed in LLM sanitize response guardrail: {e}" + "nemo_relay: json_to_py failed in LLM sanitize response guardrail: {e}" ); return response.clone(); } @@ -833,12 +833,12 @@ pub fn wrap_py_llm_sanitize_response_fn(py_fn: Py) -> LlmSanitizeResponse let result = match py_fn.call1(py, (py_resp,)) { Ok(v) => v, Err(e) => { - eprintln!("nemo_flow: LLM sanitize response guardrail callable failed: {e}"); + eprintln!("nemo_relay: LLM sanitize response guardrail callable failed: {e}"); return response.clone(); } }; py_to_json(result.bind(py)).unwrap_or_else(|e| { - eprintln!("nemo_flow: py_to_json failed in LLM sanitize response guardrail: {e}"); + eprintln!("nemo_relay: py_to_json failed in LLM sanitize response guardrail: {e}"); response.clone() }) }) diff --git a/crates/python/src/py_plugin.rs b/crates/python/src/py_plugin.rs index e7a80a72a..d483375bf 100644 --- a/crates/python/src/py_plugin.rs +++ b/crates/python/src/py_plugin.rs @@ -12,7 +12,7 @@ use std::{collections::HashSet, sync::LazyLock}; use pyo3::prelude::*; use serde_json::{Map, Value as Json}; -use nemo_flow::api::registry::{ +use nemo_relay::api::registry::{ deregister_llm_conditional_execution_guardrail, deregister_llm_execution_intercept, deregister_llm_request_intercept, deregister_llm_sanitize_request_guardrail, deregister_llm_sanitize_response_guardrail, deregister_llm_stream_execution_intercept, @@ -25,8 +25,8 @@ use nemo_flow::api::registry::{ register_tool_execution_intercept, register_tool_request_intercept, register_tool_sanitize_request_guardrail, register_tool_sanitize_response_guardrail, }; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::plugin::{ +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::plugin::{ ConfigDiagnostic, DiagnosticLevel, Plugin, PluginConfig, PluginError, PluginRegistration, PluginRegistrationContext, active_plugin_report, clear_plugin_configuration, deregister_plugin, initialize_plugins, list_plugin_kinds, register_plugin, validate_plugin_config, diff --git a/crates/python/src/py_storage.rs b/crates/python/src/py_storage.rs index 4a30122ce..8d37a5cfa 100644 --- a/crates/python/src/py_storage.rs +++ b/crates/python/src/py_storage.rs @@ -13,17 +13,17 @@ use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex}; -use nemo_flow_adaptive::acg::prompt_ir::PromptIR; -use nemo_flow_adaptive::acg::stability::StabilityAnalysisResult; +use nemo_relay_adaptive::acg::prompt_ir::PromptIR; +use nemo_relay_adaptive::acg::stability::StabilityAnalysisResult; use pyo3::prelude::*; use pyo3_async_runtimes::TaskLocals; -use nemo_flow_adaptive::error::{AdaptiveError, Result}; -use nemo_flow_adaptive::storage::traits::StorageBackendDyn; -use nemo_flow_adaptive::trie::accumulator::AccumulatorState; -use nemo_flow_adaptive::trie::serialization::TrieEnvelope; -use nemo_flow_adaptive::types::plan::ExecutionPlan; -use nemo_flow_adaptive::types::records::RunRecord; +use nemo_relay_adaptive::error::{AdaptiveError, Result}; +use nemo_relay_adaptive::storage::traits::StorageBackendDyn; +use nemo_relay_adaptive::trie::accumulator::AccumulatorState; +use nemo_relay_adaptive::trie::serialization::TrieEnvelope; +use nemo_relay_adaptive::types::plan::ExecutionPlan; +use nemo_relay_adaptive::types::records::RunRecord; use crate::convert::{json_to_py, py_to_json}; diff --git a/crates/python/src/py_types/codecs.rs b/crates/python/src/py_types/codecs.rs index 9db3ea282..936f3afe5 100644 --- a/crates/python/src/py_types/codecs.rs +++ b/crates/python/src/py_types/codecs.rs @@ -576,7 +576,7 @@ impl PyAnnotatedLLMResponse { /// /// Example: /// ```python -/// from nemo_flow.codecs import OpenAIChatCodec +/// from nemo_relay.codecs import OpenAIChatCodec /// codec = OpenAIChatCodec() /// annotated_req = codec.decode(request) /// annotated_resp = codec.decode_response(response) @@ -592,8 +592,8 @@ impl PyOpenAIChatCodec { #[new] pub(crate) fn new() -> Self { Self { - inner_codec: Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), - inner_response_codec: Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), + inner_codec: Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), + inner_response_codec: Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), } } @@ -641,7 +641,7 @@ impl PyOpenAIChatCodec { /// /// Example: /// ```python -/// from nemo_flow.codecs import OpenAIResponsesCodec +/// from nemo_relay.codecs import OpenAIResponsesCodec /// codec = OpenAIResponsesCodec() /// annotated_req = codec.decode(request) /// annotated_resp = codec.decode_response(response) @@ -657,9 +657,9 @@ impl PyOpenAIResponsesCodec { #[new] pub(crate) fn new() -> Self { Self { - inner_codec: Arc::new(nemo_flow::codec::openai_responses::OpenAIResponsesCodec), + inner_codec: Arc::new(nemo_relay::codec::openai_responses::OpenAIResponsesCodec), inner_response_codec: Arc::new( - nemo_flow::codec::openai_responses::OpenAIResponsesCodec, + nemo_relay::codec::openai_responses::OpenAIResponsesCodec, ), } } @@ -708,7 +708,7 @@ impl PyOpenAIResponsesCodec { /// /// Example: /// ```python -/// from nemo_flow.codecs import AnthropicMessagesCodec +/// from nemo_relay.codecs import AnthropicMessagesCodec /// codec = AnthropicMessagesCodec() /// annotated_req = codec.decode(request) /// annotated_resp = codec.decode_response(response) @@ -724,8 +724,8 @@ impl PyAnthropicMessagesCodec { #[new] pub(crate) fn new() -> Self { Self { - inner_codec: Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), - inner_response_codec: Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), + inner_codec: Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), + inner_response_codec: Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), } } diff --git a/crates/python/src/py_types/events.rs b/crates/python/src/py_types/events.rs index 95537577a..d5ebcdf2d 100644 --- a/crates/python/src/py_types/events.rs +++ b/crates/python/src/py_types/events.rs @@ -24,8 +24,8 @@ impl PyScopeEvent { #[getter] pub(crate) fn scope_category(&self) -> &'static str { match self.inner.scope_category { - nemo_flow::api::event::ScopeCategory::Start => "start", - nemo_flow::api::event::ScopeCategory::End => "end", + nemo_relay::api::event::ScopeCategory::Start => "start", + nemo_relay::api::event::ScopeCategory::End => "end", } } @@ -112,7 +112,7 @@ impl PyScopeEvent { /// Return this event as the canonical subscriber JSON dictionary. pub(crate) fn to_dict(&self, py: Python<'_>) -> PyResult> { - let event = nemo_flow::api::event::Event::Scope(self.inner.clone()); + let event = nemo_relay::api::event::Event::Scope(self.inner.clone()); let value = event .try_to_json_value() .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; @@ -121,7 +121,7 @@ impl PyScopeEvent { /// Return this event as canonical subscriber JSON. pub(crate) fn to_json(&self) -> PyResult { - let event = nemo_flow::api::event::Event::Scope(self.inner.clone()); + let event = nemo_relay::api::event::Event::Scope(self.inner.clone()); event .to_json_string() .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string())) @@ -200,7 +200,7 @@ impl PyMarkEvent { /// Return this event as the canonical subscriber JSON dictionary. pub(crate) fn to_dict(&self, py: Python<'_>) -> PyResult> { - let event = nemo_flow::api::event::Event::Mark(self.inner.clone()); + let event = nemo_relay::api::event::Event::Mark(self.inner.clone()); let value = event .try_to_json_value() .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; @@ -209,7 +209,7 @@ impl PyMarkEvent { /// Return this event as canonical subscriber JSON. pub(crate) fn to_json(&self) -> PyResult { - let event = nemo_flow::api::event::Event::Mark(self.inner.clone()); + let event = nemo_relay::api::event::Event::Mark(self.inner.clone()); event .to_json_string() .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string())) diff --git a/crates/python/src/py_types/mod.rs b/crates/python/src/py_types/mod.rs index 25d6a3e39..2f00ecb66 100644 --- a/crates/python/src/py_types/mod.rs +++ b/crates/python/src/py_types/mod.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Python-facing type wrappers for NeMo Flow core types. +//! Python-facing type wrappers for NeMo Relay core types. //! -//! Each type wraps its corresponding `nemo_flow::types` struct and exposes +//! Each type wraps its corresponding `nemo_relay::types` struct and exposes //! properties via `#[getter]`. Doc comments on `#[pyclass]` and `#[pymethods]` //! become Python `help()` output. @@ -13,18 +13,18 @@ use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; -use nemo_flow::api::event::{MarkEvent, ScopeEvent}; -use nemo_flow::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; -use nemo_flow::api::runtime::ScopeStackHandle; -use nemo_flow::api::scope::{ScopeAttributes, ScopeHandle, ScopeType as CoreScopeType}; -use nemo_flow::api::tool::{ToolAttributes, ToolHandle}; -use nemo_flow::codec::request::{ +use nemo_relay::api::event::{MarkEvent, ScopeEvent}; +use nemo_relay::api::llm::{LlmAttributes, LlmHandle, LlmRequest}; +use nemo_relay::api::runtime::ScopeStackHandle; +use nemo_relay::api::scope::{ScopeAttributes, ScopeHandle, ScopeType as CoreScopeType}; +use nemo_relay::api::tool::{ToolAttributes, ToolHandle}; +use nemo_relay::codec::request::{ AnnotatedLlmRequest as AnnotatedLLMRequest, GenerationParams, Message, ToolChoice, ToolDefinition, }; -use nemo_flow::codec::response::AnnotatedLlmResponse as AnnotatedLLMResponse; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::Result as FlowResult; +use nemo_relay::codec::response::AnnotatedLlmResponse as AnnotatedLLMResponse; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::Result as FlowResult; use pyo3::prelude::*; use serde::Serialize; diff --git a/crates/python/src/py_types/observability.rs b/crates/python/src/py_types/observability.rs index cc2748a33..83ef54c95 100644 --- a/crates/python/src/py_types/observability.rs +++ b/crates/python/src/py_types/observability.rs @@ -33,7 +33,7 @@ use super::{ /// ``` #[pyclass(name = "AtifExporter")] pub struct PyAtifExporter { - inner: nemo_flow::observability::atif::AtifExporter, + inner: nemo_relay::observability::atif::AtifExporter, } #[pymethods] @@ -62,7 +62,7 @@ impl PyAtifExporter { Some(obj) if !obj.is_none() => Some(py_to_json(obj)?), _ => None, }; - let agent_info = nemo_flow::observability::atif::AtifAgentInfo { + let agent_info = nemo_relay::observability::atif::AtifAgentInfo { name: agent_name, version: agent_version, model_name, @@ -70,14 +70,14 @@ impl PyAtifExporter { extra: extra_json, }; Ok(Self { - inner: nemo_flow::observability::atif::AtifExporter::new(session_id, agent_info), + inner: nemo_relay::observability::atif::AtifExporter::new(session_id, agent_info), }) } /// Register this exporter as an event subscriber with the given name. pub(crate) fn register(&self, name: String) -> PyResult<()> { let subscriber = self.inner.subscriber(); - nemo_flow::api::subscriber::register_subscriber(&name, subscriber) + nemo_relay::api::subscriber::register_subscriber(&name, subscriber) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string())) } @@ -85,7 +85,7 @@ impl PyAtifExporter { /// /// Returns ``True`` if a subscriber with that name was found and removed. pub(crate) fn deregister(&self, name: String) -> PyResult { - nemo_flow::api::subscriber::deregister_subscriber(&name) + nemo_relay::api::subscriber::deregister_subscriber(&name) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string())) } @@ -140,7 +140,7 @@ pub enum PyAtofExporterMode { Overwrite = 1, } -impl From for nemo_flow::observability::atof::AtofExporterMode { +impl From for nemo_relay::observability::atof::AtofExporterMode { fn from(value: PyAtofExporterMode) -> Self { match value { PyAtofExporterMode::Append => Self::Append, @@ -149,11 +149,11 @@ impl From for nemo_flow::observability::atof::AtofExporterMo } } -impl From for PyAtofExporterMode { - fn from(value: nemo_flow::observability::atof::AtofExporterMode) -> Self { +impl From for PyAtofExporterMode { + fn from(value: nemo_relay::observability::atof::AtofExporterMode) -> Self { match value { - nemo_flow::observability::atof::AtofExporterMode::Append => Self::Append, - nemo_flow::observability::atof::AtofExporterMode::Overwrite => Self::Overwrite, + nemo_relay::observability::atof::AtofExporterMode::Append => Self::Append, + nemo_relay::observability::atof::AtofExporterMode::Overwrite => Self::Overwrite, } } } @@ -170,8 +170,8 @@ pub struct PyAtofExporterConfig { } impl PyAtofExporterConfig { - fn to_rust_config(&self) -> nemo_flow::observability::atof::AtofExporterConfig { - nemo_flow::observability::atof::AtofExporterConfig::new() + fn to_rust_config(&self) -> nemo_relay::observability::atof::AtofExporterConfig { + nemo_relay::observability::atof::AtofExporterConfig::new() .with_output_directory(PathBuf::from(self.output_directory.clone())) .with_mode(self.mode.clone().into()) .with_filename(self.filename.clone()) @@ -182,7 +182,7 @@ impl PyAtofExporterConfig { impl PyAtofExporterConfig { #[new] pub(crate) fn new() -> Self { - let config = nemo_flow::observability::atof::AtofExporterConfig::new(); + let config = nemo_relay::observability::atof::AtofExporterConfig::new(); Self { output_directory: config.output_directory.to_string_lossy().into_owned(), mode: config.mode.into(), @@ -204,14 +204,14 @@ impl PyAtofExporterConfig { /// code, then deregister and shut down the exporter to flush output. #[pyclass(name = "AtofExporter")] pub struct PyAtofExporter { - inner: nemo_flow::observability::atof::AtofExporter, + inner: nemo_relay::observability::atof::AtofExporter, } #[pymethods] impl PyAtofExporter { #[new] pub(crate) fn new(config: PyRef<'_, PyAtofExporterConfig>) -> PyResult { - let inner = nemo_flow::observability::atof::AtofExporter::new(config.to_rust_config()) + let inner = nemo_relay::observability::atof::AtofExporter::new(config.to_rust_config()) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; Ok(Self { inner }) } @@ -294,14 +294,14 @@ pub struct PyOpenTelemetryConfig { impl PyOpenTelemetryConfig { pub(crate) fn to_rust_config( &self, - ) -> PyResult { + ) -> PyResult { let mut config = match self.transport.as_str() { - "http_binary" => nemo_flow::observability::otel::OpenTelemetryConfig::http_binary( + "http_binary" => nemo_relay::observability::otel::OpenTelemetryConfig::http_binary( + self.service_name.clone(), + ), + "grpc" => nemo_relay::observability::otel::OpenTelemetryConfig::grpc( self.service_name.clone(), ), - "grpc" => { - nemo_flow::observability::otel::OpenTelemetryConfig::grpc(self.service_name.clone()) - } other => { return Err(pyo3::exceptions::PyValueError::new_err(format!( "transport must be 'http_binary' or 'grpc', got {other:?}" @@ -337,10 +337,10 @@ impl PyOpenTelemetryConfig { Self { transport: "http_binary".to_string(), endpoint: None, - service_name: "nemo-flow".to_string(), + service_name: "nemo-relay".to_string(), service_namespace: None, service_version: None, - instrumentation_scope: "nemo-flow-otel".to_string(), + instrumentation_scope: "nemo-relay-otel".to_string(), timeout_millis: 3_000, headers: HashMap::new(), resource_attributes: HashMap::new(), @@ -397,7 +397,7 @@ impl PyOpenTelemetryConfig { /// name, then call ``force_flush()`` or ``shutdown()`` when appropriate. #[pyclass(name = "OpenTelemetrySubscriber")] pub struct PyOpenTelemetrySubscriber { - inner: nemo_flow::observability::otel::OpenTelemetrySubscriber, + inner: nemo_relay::observability::otel::OpenTelemetrySubscriber, } #[pymethods] @@ -405,7 +405,7 @@ impl PyOpenTelemetrySubscriber { #[new] pub(crate) fn new(config: PyRef<'_, PyOpenTelemetryConfig>) -> PyResult { let inner = - nemo_flow::observability::otel::OpenTelemetrySubscriber::new(config.to_rust_config()?) + nemo_relay::observability::otel::OpenTelemetrySubscriber::new(config.to_rust_config()?) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; Ok(Self { inner }) } @@ -475,10 +475,10 @@ pub struct PyOpenInferenceConfig { impl PyOpenInferenceConfig { pub(crate) fn to_rust_config( &self, - ) -> PyResult { + ) -> PyResult { let transport = match self.transport.as_str() { - "http_binary" => nemo_flow::observability::openinference::OtlpTransport::HttpBinary, - "grpc" => nemo_flow::observability::openinference::OtlpTransport::Grpc, + "http_binary" => nemo_relay::observability::openinference::OtlpTransport::HttpBinary, + "grpc" => nemo_relay::observability::openinference::OtlpTransport::Grpc, other => { return Err(pyo3::exceptions::PyValueError::new_err(format!( "transport must be 'http_binary' or 'grpc', got {other:?}" @@ -486,7 +486,7 @@ impl PyOpenInferenceConfig { } }; - let mut config = nemo_flow::observability::openinference::OpenInferenceConfig::new() + let mut config = nemo_relay::observability::openinference::OpenInferenceConfig::new() .with_transport(transport) .with_service_name(self.service_name.clone()) .with_instrumentation_scope(self.instrumentation_scope.clone()) @@ -518,10 +518,10 @@ impl PyOpenInferenceConfig { Self { transport: "http_binary".to_string(), endpoint: None, - service_name: "nemo-flow".to_string(), + service_name: "nemo-relay".to_string(), service_namespace: None, service_version: None, - instrumentation_scope: "nemo-flow-openinference".to_string(), + instrumentation_scope: "nemo-relay-openinference".to_string(), timeout_millis: 3_000, headers: HashMap::new(), resource_attributes: HashMap::new(), @@ -575,7 +575,7 @@ impl PyOpenInferenceConfig { /// OpenInference-backed event subscriber. #[pyclass(name = "OpenInferenceSubscriber")] pub struct PyOpenInferenceSubscriber { - inner: nemo_flow::observability::openinference::OpenInferenceSubscriber, + inner: nemo_relay::observability::openinference::OpenInferenceSubscriber, owned_runtime: Option, } @@ -593,7 +593,7 @@ impl PyOpenInferenceSubscriber { .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; let _guard = runtime.enter(); let inner = - nemo_flow::observability::openinference::OpenInferenceSubscriber::new(rust_config) + nemo_relay::observability::openinference::OpenInferenceSubscriber::new(rust_config) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; Ok(Self { inner, @@ -601,7 +601,7 @@ impl PyOpenInferenceSubscriber { }) } else { let inner = - nemo_flow::observability::openinference::OpenInferenceSubscriber::new(rust_config) + nemo_relay::observability::openinference::OpenInferenceSubscriber::new(rust_config) .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; Ok(Self { inner, diff --git a/crates/python/src/test_support.rs b/crates/python/src/test_support.rs index 670ba77ec..662d6c255 100644 --- a/crates/python/src/test_support.rs +++ b/crates/python/src/test_support.rs @@ -6,8 +6,8 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use pyo3::Python; -const BINDING_KIND_ENV: &str = "NEMO_FLOW_BINDING_KIND"; -const RUNTIME_OWNER_ENV: &str = "NEMO_FLOW_RUNTIME_OWNER"; +const BINDING_KIND_ENV: &str = "NEMO_RELAY_BINDING_KIND"; +const RUNTIME_OWNER_ENV: &str = "NEMO_RELAY_RUNTIME_OWNER"; fn python_test_lock() -> &'static Mutex<()> { static PYTHON_TEST_LOCK: OnceLock> = OnceLock::new(); diff --git a/crates/python/tests/coverage/coverage_tests.rs b/crates/python/tests/coverage/coverage_tests.rs index d815d6bd9..6c3205e00 100644 --- a/crates/python/tests/coverage/coverage_tests.rs +++ b/crates/python/tests/coverage/coverage_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for coverage in the NeMo Flow Python crate. +//! Coverage tests for coverage in the NeMo Relay Python crate. use std::ffi::CString; use std::pin::Pin; @@ -22,9 +22,9 @@ use crate::py_callable::{ wrap_py_llm_stream_exec_intercept_fn, wrap_py_tool_conditional_fn, wrap_py_tool_exec_fn, wrap_py_tool_exec_intercept_fn, wrap_py_tool_fn, wrap_py_tool_request_intercept_fn, }; -use nemo_flow::api::event::{BaseEvent, Event, EventCategory, ScopeCategory, ScopeEvent}; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::event::{BaseEvent, Event, EventCategory, ScopeCategory, ScopeEvent}; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; fn load_module<'py>(py: Python<'py>, code: &str) -> Bound<'py, PyModule> { let code = CString::new(code).unwrap(); @@ -98,18 +98,18 @@ fn test_native_pymodule_entrypoint_registers_bindings() { fn test_python_test_guard_restores_existing_runtime_env() { let lock = crate::test_support::lock_python_test(); unsafe { - std::env::set_var("NEMO_FLOW_BINDING_KIND", "python"); - std::env::set_var("NEMO_FLOW_RUNTIME_OWNER", "owner"); + std::env::set_var("NEMO_RELAY_BINDING_KIND", "python"); + std::env::set_var("NEMO_RELAY_RUNTIME_OWNER", "owner"); } { let _guard = crate::test_support::init_python_test_locked(lock); - assert!(std::env::var_os("NEMO_FLOW_BINDING_KIND").is_none()); - assert!(std::env::var_os("NEMO_FLOW_RUNTIME_OWNER").is_none()); + assert!(std::env::var_os("NEMO_RELAY_BINDING_KIND").is_none()); + assert!(std::env::var_os("NEMO_RELAY_RUNTIME_OWNER").is_none()); } let _lock = crate::test_support::lock_python_test(); unsafe { - std::env::remove_var("NEMO_FLOW_BINDING_KIND"); - std::env::remove_var("NEMO_FLOW_RUNTIME_OWNER"); + std::env::remove_var("NEMO_RELAY_BINDING_KIND"); + std::env::remove_var("NEMO_RELAY_RUNTIME_OWNER"); } } @@ -117,31 +117,31 @@ fn test_python_test_guard_restores_existing_runtime_env() { fn test_python_test_guard_keeps_absent_runtime_env_absent() { let lock = crate::test_support::lock_python_test(); unsafe { - std::env::remove_var("NEMO_FLOW_BINDING_KIND"); - std::env::remove_var("NEMO_FLOW_RUNTIME_OWNER"); + std::env::remove_var("NEMO_RELAY_BINDING_KIND"); + std::env::remove_var("NEMO_RELAY_RUNTIME_OWNER"); } { let _guard = crate::test_support::init_python_test_locked(lock); unsafe { - std::env::set_var("NEMO_FLOW_BINDING_KIND", "mutated-binding"); - std::env::set_var("NEMO_FLOW_RUNTIME_OWNER", "mutated-owner"); + std::env::set_var("NEMO_RELAY_BINDING_KIND", "mutated-binding"); + std::env::set_var("NEMO_RELAY_RUNTIME_OWNER", "mutated-owner"); } assert_eq!( - std::env::var_os("NEMO_FLOW_BINDING_KIND"), + std::env::var_os("NEMO_RELAY_BINDING_KIND"), Some("mutated-binding".into()) ); assert_eq!( - std::env::var_os("NEMO_FLOW_RUNTIME_OWNER"), + std::env::var_os("NEMO_RELAY_RUNTIME_OWNER"), Some("mutated-owner".into()) ); } let _lock = crate::test_support::lock_python_test(); unsafe { - std::env::remove_var("NEMO_FLOW_BINDING_KIND"); - std::env::remove_var("NEMO_FLOW_RUNTIME_OWNER"); + std::env::remove_var("NEMO_RELAY_BINDING_KIND"); + std::env::remove_var("NEMO_RELAY_RUNTIME_OWNER"); } - assert!(std::env::var_os("NEMO_FLOW_BINDING_KIND").is_none()); - assert!(std::env::var_os("NEMO_FLOW_RUNTIME_OWNER").is_none()); + assert!(std::env::var_os("NEMO_RELAY_BINDING_KIND").is_none()); + assert!(std::env::var_os("NEMO_RELAY_RUNTIME_OWNER").is_none()); } #[test] @@ -322,7 +322,7 @@ fn test_plugin_bindings_validate_configure_and_clear() { let _python = crate::test_support::init_python_test(); let _plugin_test_state = crate::py_plugin::lock_plugin_test_state_for_tests(); Python::attach(|py| { - nemo_flow_adaptive::plugin_component::register_adaptive_component().unwrap(); + nemo_relay_adaptive::plugin_component::register_adaptive_component().unwrap(); let plugin_module = PyModule::new(py, "_plugin_test").unwrap(); crate::py_plugin::register(&plugin_module).unwrap(); @@ -801,7 +801,7 @@ async def llm_stream_intercept(request, next): let chunks = vec![Ok(json!({"chunk": "a"})), Ok(json!({"chunk": "b"}))]; Ok(Box::pin(tokio_stream::iter(chunks)) as Pin< - Box> + Send>, + Box> + Send>, >) }) }); @@ -941,7 +941,7 @@ async def llm_stream_intercept_fail(request, next): let chunks = vec![Ok(json!({"chunk": "downstream"}))]; Ok(Box::pin(tokio_stream::iter(chunks)) as Pin< - Box> + Send>, + Box> + Send>, >) }) }); @@ -960,7 +960,7 @@ async def llm_stream_intercept_fail(request, next): Box::pin(async move { Ok(Box::pin(tokio_stream::iter(vec![Ok(json!({"chunk": 1}))])) as Pin< - Box> + Send>, + Box> + Send>, >) }) }); diff --git a/crates/python/tests/coverage/py_adaptive_coverage_tests.rs b/crates/python/tests/coverage/py_adaptive_coverage_tests.rs index 157bf1122..6c040bb67 100644 --- a/crates/python/tests/coverage/py_adaptive_coverage_tests.rs +++ b/crates/python/tests/coverage/py_adaptive_coverage_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py adaptive coverage in the NeMo Flow Python crate. +//! Coverage tests for py adaptive coverage in the NeMo Relay Python crate. use super::*; use std::fs; -use nemo_flow::api::scope::{ScopeHandle, ScopeType as CoreScopeType}; +use nemo_relay::api::scope::{ScopeHandle, ScopeType as CoreScopeType}; use pyo3::types::{PyDict, PyModule}; use serde_json::json; @@ -68,8 +68,8 @@ fn py_adaptive_uses_canonical_adaptive_acg_imports() { let source = fs::read_to_string(format!("{}/src/py_adaptive.rs", env!("CARGO_MANIFEST_DIR"))).unwrap(); - assert!(source.contains("nemo_flow_adaptive::acg")); - assert!(!source.contains("nemo_flow_acg::")); + assert!(source.contains("nemo_relay_adaptive::acg")); + assert!(!source.contains("nemo_relay_acg::")); } #[test] @@ -77,7 +77,7 @@ fn python_crate_manifest_drops_direct_acg_dependency() { let manifest = fs::read_to_string(format!("{}/Cargo.toml", env!("CARGO_MANIFEST_DIR"))).unwrap(); - assert!(!manifest.contains("nemo-flow-acg =")); + assert!(!manifest.contains("nemo-relay-acg =")); } #[test] @@ -377,7 +377,7 @@ fn adaptive_runtime_locking_and_helper_errors_are_covered() { let guard = locked_runtime.inner.try_lock().unwrap(); let _llm_request = crate::py_types::PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({ "messages": [{"role": "user", "content": "hello"}], diff --git a/crates/python/tests/coverage/py_api_coverage_tests.rs b/crates/python/tests/coverage/py_api_coverage_tests.rs index 828e5dc34..c3d86e061 100644 --- a/crates/python/tests/coverage/py_api_coverage_tests.rs +++ b/crates/python/tests/coverage/py_api_coverage_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py api coverage in the NeMo Flow Python crate. +//! Coverage tests for py api coverage in the NeMo Relay Python crate. use super::*; @@ -62,7 +62,7 @@ fn py_api_helpers_and_scope_lifecycle_round_trip() { PyScopeType::Tool, Some(handle.clone()), Some(PyScopeAttributes { - inner: nemo_flow::api::scope::ScopeAttributes::PARALLEL, + inner: nemo_relay::api::scope::ScopeAttributes::PARALLEL, }), Some(&data), Some(&metadata), @@ -86,7 +86,7 @@ fn py_api_helpers_and_scope_lifecycle_round_trip() { &py_dict(py, json!({"arg": 1})), Some(child.clone()), Some(PyToolAttributes { - inner: nemo_flow::api::tool::ToolAttributes::REMOTE, + inner: nemo_relay::api::tool::ToolAttributes::REMOTE, }), Some(&py_dict(py, json!({"tool_data": true}))), Some(&py_dict(py, json!({"tool_meta": true}))), @@ -104,7 +104,7 @@ fn py_api_helpers_and_scope_lifecycle_round_trip() { .unwrap(); let llm_request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({"messages": [], "model": "demo"}), }, @@ -114,8 +114,8 @@ fn py_api_helpers_and_scope_lifecycle_round_trip() { llm_request, Some(child.clone()), Some(PyLLMAttributes { - inner: nemo_flow::api::llm::LlmAttributes::STATEFUL - | nemo_flow::api::llm::LlmAttributes::STREAMING, + inner: nemo_relay::api::llm::LlmAttributes::STATEFUL + | nemo_relay::api::llm::LlmAttributes::STREAMING, }), Some(&py_dict(py, json!({"llm_data": true}))), Some(&py_dict(py, json!({"llm_meta": true}))), @@ -450,7 +450,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute ); let llm_request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({"messages": [{"role": "user", "content": "hello"}], "model": "demo-model"}), }, @@ -463,7 +463,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute llm_conditional_execution(llm_request.clone()).unwrap(); assert!( llm_conditional_execution(PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({"messages": [], "model": "blocked"}), }, @@ -485,7 +485,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute helpers.getattr("tool_exec").unwrap(), child.clone(), PyToolAttributes { - inner: nemo_flow::api::tool::ToolAttributes::REMOTE, + inner: nemo_relay::api::tool::ToolAttributes::REMOTE, }, )) .unwrap(),), @@ -513,7 +513,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute helpers.getattr("llm_exec").unwrap(), child.clone(), PyLLMAttributes { - inner: nemo_flow::api::llm::LlmAttributes::STATEFUL, + inner: nemo_relay::api::llm::LlmAttributes::STATEFUL, }, codec, response_codec, @@ -545,7 +545,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute helpers.getattr("finalizer").unwrap(), child.clone(), PyLLMAttributes { - inner: nemo_flow::api::llm::LlmAttributes::STREAMING, + inner: nemo_relay::api::llm::LlmAttributes::STREAMING, }, stream_codec, stream_response_codec, @@ -787,7 +787,7 @@ async def run_stream(api, request, func, collector, finalizer, handle, attribute #[test] fn to_py_err_and_forward_stream_to_channel_cover_private_helpers() { let _python = crate::test_support::init_python_test(); - let err = to_py_err(nemo_flow::error::FlowError::Internal("boom".into())); + let err = to_py_err(nemo_relay::error::FlowError::Internal("boom".into())); assert!(err.to_string().contains("boom")); let runtime = tokio::runtime::Runtime::new().unwrap(); @@ -921,7 +921,7 @@ async def run_stream(api, request, func, collector, finalizer, response_codec): "#, ); let request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({"messages": [{"role": "user", "content": "hello"}], "model": "demo-model"}), }, diff --git a/crates/python/tests/coverage/py_callable_coverage_tests.rs b/crates/python/tests/coverage/py_callable_coverage_tests.rs index 26e2cb078..9c9e0f7a5 100644 --- a/crates/python/tests/coverage/py_callable_coverage_tests.rs +++ b/crates/python/tests/coverage/py_callable_coverage_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py callable coverage in the NeMo Flow Python crate. +//! Coverage tests for py callable coverage in the NeMo Relay Python crate. use super::*; diff --git a/crates/python/tests/coverage/py_plugin_coverage_tests.rs b/crates/python/tests/coverage/py_plugin_coverage_tests.rs index 71df05eb4..f774d5ea3 100644 --- a/crates/python/tests/coverage/py_plugin_coverage_tests.rs +++ b/crates/python/tests/coverage/py_plugin_coverage_tests.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py plugin coverage in the NeMo Flow Python crate. +//! Coverage tests for py plugin coverage in the NeMo Relay Python crate. use super::*; use std::ffi::CString; use std::sync::{Arc, Mutex}; -use nemo_flow::plugin::rollback_registrations; +use nemo_relay::plugin::rollback_registrations; use pyo3::types::PyModule; use serde_json::json; @@ -695,19 +695,19 @@ async def tool_execution_intercept(name, value, next): let mut registrations = context.drain_registrations().unwrap(); assert_eq!(registrations.len(), 12); - let previous_owner = std::env::var("NEMO_FLOW_RUNTIME_OWNER").ok(); + let previous_owner = std::env::var("NEMO_RELAY_RUNTIME_OWNER").ok(); let conflicting_owner = format!( "pid={};binding=node;version={}", std::process::id(), env!("CARGO_PKG_VERSION").split('.').next().unwrap() ); unsafe { - std::env::set_var("NEMO_FLOW_RUNTIME_OWNER", &conflicting_owner); + std::env::set_var("NEMO_RELAY_RUNTIME_OWNER", &conflicting_owner); } rollback_registrations(&mut registrations); match previous_owner { - Some(value) => unsafe { std::env::set_var("NEMO_FLOW_RUNTIME_OWNER", value) }, - None => unsafe { std::env::remove_var("NEMO_FLOW_RUNTIME_OWNER") }, + Some(value) => unsafe { std::env::set_var("NEMO_RELAY_RUNTIME_OWNER", value) }, + None => unsafe { std::env::remove_var("NEMO_RELAY_RUNTIME_OWNER") }, } }); } diff --git a/crates/python/tests/coverage/py_storage_coverage_tests.rs b/crates/python/tests/coverage/py_storage_coverage_tests.rs index 55a724bc6..0661dcf90 100644 --- a/crates/python/tests/coverage/py_storage_coverage_tests.rs +++ b/crates/python/tests/coverage/py_storage_coverage_tests.rs @@ -1,27 +1,27 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py storage coverage in the NeMo Flow Python crate. +//! Coverage tests for py storage coverage in the NeMo Relay Python crate. use std::ffi::CString; use chrono::Utc; -use nemo_flow_adaptive::acg::profile::{BlockStabilityScore, StabilityClass}; -use nemo_flow_adaptive::acg::prompt_ir::{ +use nemo_relay_adaptive::acg::profile::{BlockStabilityScore, StabilityClass}; +use nemo_relay_adaptive::acg::prompt_ir::{ BlockContentType, PromptBlock, PromptIR, PromptRole, ProvenanceLabel, SensitivityLabel, SpanId, }; -use nemo_flow_adaptive::acg::stability::StabilityAnalysisResult; +use nemo_relay_adaptive::acg::stability::StabilityAnalysisResult; use pyo3::prelude::*; use pyo3::types::PyModule; use serde_json::json; use uuid::Uuid; -use nemo_flow_adaptive::storage::traits::StorageBackendDyn; -use nemo_flow_adaptive::trie::accumulator::{AccumulatorState, NodeAccumulators, RunningStats}; -use nemo_flow_adaptive::trie::data_models::PredictionTrieNode; -use nemo_flow_adaptive::types::metadata::{MetadataEnvelope, ParallelHint}; -use nemo_flow_adaptive::types::plan::{ExecutionPlan, ParallelGroup}; -use nemo_flow_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::storage::traits::StorageBackendDyn; +use nemo_relay_adaptive::trie::accumulator::{AccumulatorState, NodeAccumulators, RunningStats}; +use nemo_relay_adaptive::trie::data_models::PredictionTrieNode; +use nemo_relay_adaptive::types::metadata::{MetadataEnvelope, ParallelHint}; +use nemo_relay_adaptive::types::plan::{ExecutionPlan, ParallelGroup}; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; use super::*; @@ -384,8 +384,8 @@ fn py_storage_uses_canonical_adaptive_acg_imports() { std::fs::read_to_string(format!("{}/src/py_storage.rs", env!("CARGO_MANIFEST_DIR"))) .unwrap(); - assert!(source.contains("nemo_flow_adaptive::acg")); - assert!(!source.contains("nemo_flow_acg::")); + assert!(source.contains("nemo_relay_adaptive::acg")); + assert!(!source.contains("nemo_relay_acg::")); } #[test] diff --git a/crates/python/tests/coverage/py_types_coverage_tests.rs b/crates/python/tests/coverage/py_types_coverage_tests.rs index ad38add48..59498bc79 100644 --- a/crates/python/tests/coverage/py_types_coverage_tests.rs +++ b/crates/python/tests/coverage/py_types_coverage_tests.rs @@ -1,24 +1,24 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for py types coverage in the NeMo Flow Python crate. +//! Coverage tests for py types coverage in the NeMo Relay Python crate. use super::*; use std::ffi::CString; -use nemo_flow::api::event::{ +use nemo_relay::api::event::{ BaseEvent, CategoryProfile, Event, EventCategory, MarkEvent, ScopeCategory, ScopeEvent, llm_attributes_to_strings, scope_attributes_to_strings, tool_attributes_to_strings, }; -use nemo_flow::api::llm::{LlmAttributes, LlmHandle}; -use nemo_flow::api::llm::{LlmCallParams, llm_call, llm_call_end}; -use nemo_flow::api::scope::{PushScopeParams, pop_scope, push_scope}; -use nemo_flow::api::scope::{ScopeAttributes, ScopeHandle, ScopeType}; -use nemo_flow::api::tool::{ToolAttributes, ToolHandle}; -use nemo_flow::codec::request::{ +use nemo_relay::api::llm::{LlmAttributes, LlmHandle}; +use nemo_relay::api::llm::{LlmCallParams, llm_call, llm_call_end}; +use nemo_relay::api::scope::{PushScopeParams, pop_scope, push_scope}; +use nemo_relay::api::scope::{ScopeAttributes, ScopeHandle, ScopeType}; +use nemo_relay::api::tool::{ToolAttributes, ToolHandle}; +use nemo_relay::codec::request::{ AnnotatedLlmRequest as AnnotatedLLMRequest, Message, MessageContent, }; -use nemo_flow::codec::response::{ +use nemo_relay::codec::response::{ AnnotatedLlmResponse as AnnotatedLLMResponse, ApiSpecificResponse, FinishReason, ResponseToolCall, Usage, }; @@ -342,7 +342,7 @@ fn test_atif_exporter_methods_cover_register_export_and_clear() { ) .unwrap(); llm_call_end( - nemo_flow::api::llm::LlmCallEndParams::builder() + nemo_relay::api::llm::LlmCallEndParams::builder() .handle(&handle) .response(json!({"content": "world"})) .build(), @@ -367,7 +367,7 @@ fn test_atif_exporter_methods_cover_register_export_and_clear() { assert_eq!(cleared["steps"], json!([])); pop_scope( - nemo_flow::api::scope::PopScopeParams::builder() + nemo_relay::api::scope::PopScopeParams::builder() .handle_uuid(&scope.uuid) .build(), ) @@ -512,7 +512,7 @@ fn test_stream_request_event_and_handle_wrappers_cover_remaining_methods() { assert_eq!(llm_and.value(), PyLLMAttributes::STREAMING); Python::attach(|py| { - let stack = PyScopeStack(nemo_flow::api::runtime::create_scope_stack()); + let stack = PyScopeStack(nemo_relay::api::runtime::create_scope_stack()); assert_eq!(stack.__repr__(), ""); let parent_uuid = Uuid::now_v7(); @@ -812,7 +812,7 @@ async def next_item(stream): let (tx_err, rx_err) = tokio::sync::mpsc::channel(1); tx_err - .blocking_send(Err(nemo_flow::error::FlowError::Internal( + .blocking_send(Err(nemo_relay::error::FlowError::Internal( "stream boom".into(), ))) .unwrap(); @@ -1254,7 +1254,7 @@ fn test_annotated_llm_types_and_builtin_codecs_cover_mutators_and_codecs() { ); let chat_request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({ "model": "gpt-4o-mini", @@ -1289,7 +1289,7 @@ fn test_annotated_llm_types_and_builtin_codecs_cover_mutators_and_codecs() { assert_eq!(chat_codec.__repr__(), ""); let responses_request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({ "model": "gpt-4o-mini", @@ -1333,7 +1333,7 @@ fn test_annotated_llm_types_and_builtin_codecs_cover_mutators_and_codecs() { assert_eq!(responses_codec.__repr__(), ""); let anthropic_request = PyLLMRequest { - inner: nemo_flow::api::llm::LlmRequest { + inner: nemo_relay::api::llm::LlmRequest { headers: serde_json::Map::new(), content: json!({ "model": "claude-sonnet-4-20250514", @@ -1406,20 +1406,20 @@ fn test_forced_serialization_error_hooks_cover_unreachable_wrappers() { }, ], model: Some("demo-model".into()), - params: Some(nemo_flow::codec::request::GenerationParams { + params: Some(nemo_relay::codec::request::GenerationParams { temperature: Some(0.1), max_tokens: Some(8), ..Default::default() }), - tools: Some(vec![nemo_flow::codec::request::ToolDefinition { + tools: Some(vec![nemo_relay::codec::request::ToolDefinition { tool_type: "function".into(), - function: nemo_flow::codec::request::FunctionDefinition { + function: nemo_relay::codec::request::FunctionDefinition { name: "lookup".into(), description: None, parameters: Some(json!({"type": "object"})), }, }]), - tool_choice: Some(nemo_flow::codec::request::ToolChoice::Auto), + tool_choice: Some(nemo_relay::codec::request::ToolChoice::Auto), store: None, previous_response_id: None, truncation: None, diff --git a/crates/python/tests/integration/main.rs b/crates/python/tests/integration/main.rs index 75d6afebc..e56b70724 100644 --- a/crates/python/tests/integration/main.rs +++ b/crates/python/tests/integration/main.rs @@ -1,6 +1,6 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration test support for the NeMo Flow Python crate. +//! Integration test support for the NeMo Relay Python crate. mod module_registration_tests; diff --git a/crates/python/tests/integration/module_registration_tests.rs b/crates/python/tests/integration/module_registration_tests.rs index fd1825750..b96dc5007 100644 --- a/crates/python/tests/integration/module_registration_tests.rs +++ b/crates/python/tests/integration/module_registration_tests.rs @@ -1,17 +1,17 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for module registration in the NeMo Flow Python crate. +//! Integration tests for module registration in the NeMo Relay Python crate. use _native::{py_adaptive, py_api, py_plugin, py_types}; -use nemo_flow::api::runtime::NemoFlowContextState; -use nemo_flow::api::runtime::global_context; +use nemo_relay::api::runtime::NemoRelayContextState; +use nemo_relay::api::runtime::global_context; use pyo3::prelude::*; use pyo3::types::PyModule; fn reset_global() { let context = global_context(); - *context.write().unwrap() = NemoFlowContextState::new(); + *context.write().unwrap() = NemoRelayContextState::new(); } #[test] diff --git a/crates/python/tests/unit/convert_tests.rs b/crates/python/tests/unit/convert_tests.rs index 7ffe842c2..924f14847 100644 --- a/crates/python/tests/unit/convert_tests.rs +++ b/crates/python/tests/unit/convert_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for convert in the NeMo Flow Python crate. +//! Unit tests for convert in the NeMo Relay Python crate. use super::*; use serde_json::json; diff --git a/crates/wasm/Cargo.toml b/crates/wasm/Cargo.toml index ae5ca0779..350123612 100644 --- a/crates/wasm/Cargo.toml +++ b/crates/wasm/Cargo.toml @@ -2,24 +2,24 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "nemo-flow-wasm" +name = "nemo-relay-wasm" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "WebAssembly bindings for NeMo Flow targeting JavaScript bundlers and browsers." +description = "WebAssembly bindings for NeMo Relay targeting JavaScript bundlers and browsers." readme = "README.md" [lints] workspace = true [lib] -name = "nemo_flow_wasm" +name = "nemo_relay_wasm" crate-type = ["cdylib", "rlib"] [dependencies] -nemo-flow = { workspace = true, features = ["otel", "openinference"] } -nemo-flow-adaptive.workspace = true +nemo-relay = { workspace = true, features = ["otel", "openinference"] } +nemo-relay-adaptive.workspace = true chrono = "0.4" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" diff --git a/crates/wasm/README.md b/crates/wasm/README.md index 6436991e6..aca7f4dd3 100644 --- a/crates/wasm/README.md +++ b/crates/wasm/README.md @@ -3,21 +3,21 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow-wasm` is the NeMo Flow WebAssembly package for JavaScript +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay-wasm` is the NeMo Relay WebAssembly package for JavaScript environments that load the runtime through WebAssembly. It exposes the same execution scope, middleware, plugin, lifecycle event, and observability concepts as the Rust runtime. @@ -36,7 +36,7 @@ require a host runtime with filesystem access. ## Why Use It? -- 🌐 **Bring NeMo Flow to WebAssembly**: Use the shared runtime model from +- 🌐 **Bring NeMo Relay to WebAssembly**: Use the shared runtime model from JavaScript environments that load the package through WebAssembly. - 🧭 **Keep execution context visible**: Group scope, tool, LLM, middleware, and subscriber behavior into the same runtime event tree. @@ -47,15 +47,15 @@ require a host runtime with filesystem access. ## What You Get -- ✅ **WebAssembly runtime bindings**: Access to NeMo Flow scope, tool, LLM, +- ✅ **WebAssembly runtime bindings**: Access to NeMo Relay scope, tool, LLM, middleware, subscriber, plugin, typed, and adaptive APIs. - ✅ **Managed tool and LLM execution**: Helpers that emit lifecycle events for JavaScript-managed callbacks. - ✅ **Middleware registration**: Guardrail and intercept APIs for JavaScript callbacks. -- ✅ **Additional entry points**: `nemo-flow-wasm/typed`, - `nemo-flow-wasm/plugin`, `nemo-flow-wasm/adaptive`, and - `nemo-flow-wasm/observability`. +- ✅ **Additional entry points**: `nemo-relay-wasm/typed`, + `nemo-relay-wasm/plugin`, `nemo-relay-wasm/adaptive`, and + `nemo-relay-wasm/observability`. - ✅ **Generated npm package**: A `wasm-pack` build prepared for JavaScript package consumption. @@ -64,14 +64,14 @@ require a host runtime with filesystem access. Install the npm package in a JavaScript project: ```bash -npm install nemo-flow-wasm +npm install nemo-relay-wasm ``` For local source validation from the repository root: ```bash -npm run build:pkg --workspace=nemo-flow-wasm -npm run test:pkg --workspace=nemo-flow-wasm +npm run build:pkg --workspace=nemo-relay-wasm +npm run test:pkg --workspace=nemo-relay-wasm ``` ## Getting Started @@ -85,7 +85,7 @@ const { event, registerSubscriber, withScope, -} = require("nemo-flow-wasm"); +} = require("nemo-relay-wasm"); async function main() { registerSubscriber("printer", (runtimeEvent) => { @@ -106,10 +106,10 @@ main().catch((error) => { }); ``` -The main runtime API is exported from `nemo-flow-wasm`. Additional entry points -are available at `nemo-flow-wasm/typed`, `nemo-flow-wasm/plugin`, -`nemo-flow-wasm/adaptive`, and `nemo-flow-wasm/observability`. +The main runtime API is exported from `nemo-relay-wasm`. Additional entry points +are available at `nemo-relay-wasm/typed`, `nemo-relay-wasm/plugin`, +`nemo-relay-wasm/adaptive`, and `nemo-relay-wasm/observability`. ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/crates/wasm/package.json b/crates/wasm/package.json index 43010f6ea..07738696d 100644 --- a/crates/wasm/package.json +++ b/crates/wasm/package.json @@ -1,5 +1,5 @@ { - "name": "nemo-flow-wasm", + "name": "nemo-relay-wasm", "private": true, "engines": { "node": ">=20.0.0" diff --git a/crates/wasm/scripts/build_pkg.mjs b/crates/wasm/scripts/build_pkg.mjs index c82d374ba..5dc37de5a 100644 --- a/crates/wasm/scripts/build_pkg.mjs +++ b/crates/wasm/scripts/build_pkg.mjs @@ -15,7 +15,7 @@ if (fs.existsSync(pkgDir)) { } const wasmPackArgs = ['build']; -if (process.env.NEMO_FLOW_WASM_RELEASE) { +if (process.env.NEMO_RELAY_WASM_RELEASE) { wasmPackArgs.push('--release'); } wasmPackArgs.push('--target', 'nodejs', '--out-dir', 'pkg'); diff --git a/crates/wasm/scripts/prepare_pkg.mjs b/crates/wasm/scripts/prepare_pkg.mjs index 9ceed9086..15f1c7812 100644 --- a/crates/wasm/scripts/prepare_pkg.mjs +++ b/crates/wasm/scripts/prepare_pkg.mjs @@ -16,15 +16,15 @@ const jsWrapperFiles = ['typed.js', 'plugin.js', 'adaptive.js', 'observability.j const typeWrapperFiles = ['typed.d.ts', 'plugin.d.ts', 'adaptive.d.ts', 'observability.d.ts']; const wrapperFiles = [...rootJsFiles, ...jsWrapperFiles, ...typeWrapperFiles]; const packageMetadata = { - description: 'WebAssembly bindings for the NeMo Flow agent runtime.', - keywords: ['agents', 'ai', 'llm', 'middleware', 'nemo-flow', 'observability', 'runtime', 'tools', 'wasm'], - homepage: 'https://github.com/NVIDIA/NeMo-Flow#readme', + description: 'WebAssembly bindings for the NeMo Relay agent runtime.', + keywords: ['agents', 'ai', 'llm', 'middleware', 'nemo-relay', 'observability', 'runtime', 'tools', 'wasm'], + homepage: 'https://github.com/NVIDIA/NeMo-Relay#readme', bugs: { - url: 'https://github.com/NVIDIA/NeMo-Flow/issues', + url: 'https://github.com/NVIDIA/NeMo-Relay/issues', }, repository: { type: 'git', - url: 'git+https://github.com/NVIDIA/NeMo-Flow.git', + url: 'git+https://github.com/NVIDIA/NeMo-Relay.git', directory: 'crates/wasm', }, author: 'NVIDIA Corporation & Affiliates', @@ -35,8 +35,8 @@ const packageMetadata = { // point at the package-local wasm entrypoint inside pkg/. const replacements = [ ['./pkg/index.js', './index.js'], - ['./pkg/nemo_flow_wasm.js', './nemo_flow_wasm.js'], - ['./pkg/nemo_flow_wasm', './nemo_flow_wasm'], + ['./pkg/nemo_relay_wasm.js', './nemo_relay_wasm.js'], + ['./pkg/nemo_relay_wasm', './nemo_relay_wasm'], ]; function copyWithReplacements(sourcePath, destinationPath) { @@ -68,7 +68,7 @@ function writeJsWrapperFiles(manifest) { function updatePackageManifest(manifest) { const manifestPath = path.join(pkgDir, 'package.json'); const existingFiles = Array.isArray(manifest.files) ? manifest.files : []; - const rootTypes = 'nemo_flow_wasm.d.ts'; + const rootTypes = 'nemo_relay_wasm.d.ts'; Object.assign(manifest, packageMetadata); diff --git a/crates/wasm/src/api/mod.rs b/crates/wasm/src/api/mod.rs index a42ac6817..181d9679c 100644 --- a/crates/wasm/src/api/mod.rs +++ b/crates/wasm/src/api/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Top-level NeMo Flow API functions exposed to JavaScript via `wasm_bindgen`. +//! Top-level NeMo Relay API functions exposed to JavaScript via `wasm_bindgen`. //! //! This module contains all public entry points for: //! @@ -35,22 +35,22 @@ use wasm_bindgen::JsCast; use wasm_bindgen::closure::Closure; use wasm_bindgen::prelude::*; -use nemo_flow::api::llm as flow_llm_api; -use nemo_flow::api::llm::{LlmAttributes, LlmRequest as CoreLlmRequest}; -use nemo_flow::api::registry as flow_registry_api; -use nemo_flow::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; -use nemo_flow::api::runtime::{ +use nemo_relay::api::llm as relay_llm_api; +use nemo_relay::api::llm::{LlmAttributes, LlmRequest as CoreLlmRequest}; +use nemo_relay::api::registry as relay_registry_api; +use nemo_relay::api::runtime::{LlmExecutionNextFn, LlmStreamExecutionNextFn, ToolExecutionNextFn}; +use nemo_relay::api::runtime::{ TASK_SCOPE_STACK, create_scope_stack as create_scope_stack_handle, current_scope_stack as current_scope_stack_handle, scope_stack_active as scope_stack_is_active, set_thread_scope_stack as bind_thread_scope_stack, task_scope_top, }; -use nemo_flow::api::scope as flow_scope_api; -use nemo_flow::api::scope::{ScopeAttributes, ScopeHandle as CoreScopeHandle}; -use nemo_flow::api::subscriber as flow_subscriber_api; -use nemo_flow::api::tool as flow_tool_api; -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::error::{FlowError, Result as FlowResult}; -use nemo_flow::plugin::{ +use nemo_relay::api::scope as relay_scope_api; +use nemo_relay::api::scope::{ScopeAttributes, ScopeHandle as CoreScopeHandle}; +use nemo_relay::api::subscriber as relay_subscriber_api; +use nemo_relay::api::tool as relay_tool_api; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::error::{FlowError, Result as FlowResult}; +use nemo_relay::plugin::{ ConfigDiagnostic, DiagnosticLevel, Plugin, PluginConfig, PluginError, PluginRegistration as ComponentRegistration, PluginRegistrationContext, active_plugin_report as active_plugin_report_impl, @@ -59,7 +59,7 @@ use nemo_flow::plugin::{ list_plugin_kinds as list_plugin_kinds_impl, register_plugin as register_plugin_impl, validate_plugin_config as validate_plugin_config_impl, }; -use nemo_flow_adaptive::plugin_component::register_adaptive_component; +use nemo_relay_adaptive::plugin_component::register_adaptive_component; use crate::callable; use crate::convert::{ @@ -91,10 +91,10 @@ impl Default for WasmOpenTelemetryConfig { endpoint: None, headers: Some(HashMap::new()), resource_attributes: Some(HashMap::new()), - service_name: Some("nemo-flow".to_string()), + service_name: Some("nemo-relay".to_string()), service_namespace: None, service_version: None, - instrumentation_scope: Some("nemo-flow-otel".to_string()), + instrumentation_scope: Some("nemo-relay-otel".to_string()), timeout_millis: Some(3_000), } } @@ -121,10 +121,10 @@ impl Default for WasmOpenInferenceConfig { endpoint: None, headers: Some(HashMap::new()), resource_attributes: Some(HashMap::new()), - service_name: Some("nemo-flow".to_string()), + service_name: Some("nemo-relay".to_string()), service_namespace: None, service_version: None, - instrumentation_scope: Some("nemo-flow-openinference".to_string()), + instrumentation_scope: Some("nemo-relay-openinference".to_string()), timeout_millis: Some(3_000), } } @@ -237,24 +237,24 @@ fn clone_scope_handle_arg(handle: &JsValue) -> Result, J fn build_otel_config( config: Option, -) -> Result { +) -> Result { let config = config.unwrap_or_default(); let transport = config .transport .unwrap_or_else(|| "http_binary".to_string()); let service_name = config .service_name - .unwrap_or_else(|| "nemo-flow".to_string()); + .unwrap_or_else(|| "nemo-relay".to_string()); let instrumentation_scope = config .instrumentation_scope - .unwrap_or_else(|| "nemo-flow-otel".to_string()); + .unwrap_or_else(|| "nemo-relay-otel".to_string()); let timeout_millis = config.timeout_millis.unwrap_or(3_000); let mut otel_config = match transport.as_str() { "http_binary" => { - nemo_flow::observability::otel::OpenTelemetryConfig::http_binary(service_name) + nemo_relay::observability::otel::OpenTelemetryConfig::http_binary(service_name) } - "grpc" => nemo_flow::observability::otel::OpenTelemetryConfig::grpc(service_name), + "grpc" => nemo_relay::observability::otel::OpenTelemetryConfig::grpc(service_name), other => { return Err(JsValue::from_str(&format!( "transport must be 'http_binary' or 'grpc', got {other:?}", @@ -284,22 +284,22 @@ fn build_otel_config( fn build_openinference_config( config: Option, -) -> Result { +) -> Result { let config = config.unwrap_or_default(); let transport = config .transport .unwrap_or_else(|| "http_binary".to_string()); let service_name = config .service_name - .unwrap_or_else(|| "nemo-flow".to_string()); + .unwrap_or_else(|| "nemo-relay".to_string()); let instrumentation_scope = config .instrumentation_scope - .unwrap_or_else(|| "nemo-flow-openinference".to_string()); + .unwrap_or_else(|| "nemo-relay-openinference".to_string()); let timeout_millis = config.timeout_millis.unwrap_or(3_000); let transport = match transport.as_str() { - "http_binary" => nemo_flow::observability::openinference::OtlpTransport::HttpBinary, - "grpc" => nemo_flow::observability::openinference::OtlpTransport::Grpc, + "http_binary" => nemo_relay::observability::openinference::OtlpTransport::HttpBinary, + "grpc" => nemo_relay::observability::openinference::OtlpTransport::Grpc, other => { return Err(JsValue::from_str(&format!( "transport must be 'http_binary' or 'grpc', got {other:?}", @@ -308,7 +308,7 @@ fn build_openinference_config( }; let mut openinference_config = - nemo_flow::observability::openinference::OpenInferenceConfig::new() + nemo_relay::observability::openinference::OpenInferenceConfig::new() .with_transport(transport) .with_service_name(service_name) .with_instrumentation_scope(instrumentation_scope) @@ -341,7 +341,7 @@ fn build_openinference_config( /// Throws if the scope stack is empty. #[wasm_bindgen(js_name = "getHandle")] pub fn get_handle() -> Result { - flow_scope_api::get_handle() + relay_scope_api::get_handle() .map(ScopeHandle::from) .map_err(to_js_err) } @@ -374,8 +374,8 @@ pub fn push_scope( let attrs = ScopeAttributes::from_bits_truncate(attributes.unwrap_or(0)); let handle = clone_scope_handle_arg(&handle)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_scope_api::push_scope( - flow_scope_api::PushScopeParams::builder() + relay_scope_api::push_scope( + relay_scope_api::PushScopeParams::builder() .name(name) .scope_type(scope_type.into()) .parent_opt(handle.as_ref()) @@ -403,8 +403,8 @@ pub fn pop_scope( #[wasm_bindgen(unchecked_param_type = "number | null | undefined")] timestamp: Option, ) -> Result<(), JsValue> { let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_scope_api::pop_scope( - flow_scope_api::PopScopeParams::builder() + relay_scope_api::pop_scope( + relay_scope_api::PopScopeParams::builder() .handle_uuid(&handle.inner.uuid) .output_opt(opt_js_to_json(&output)?) .timestamp_opt(timestamp) @@ -463,8 +463,8 @@ pub fn with_scope( ) -> Result { let attrs = ScopeAttributes::from_bits_truncate(attributes.unwrap_or(0)); let handle = clone_scope_handle_arg(&handle)?; - let scope_handle = flow_scope_api::push_scope( - flow_scope_api::PushScopeParams::builder() + let scope_handle = relay_scope_api::push_scope( + relay_scope_api::PushScopeParams::builder() .name(name) .scope_type(scope_type.into()) .parent_opt(handle.as_ref()) @@ -490,8 +490,8 @@ pub fn with_scope( let then_uuid = scope_uuid; let then_cb = Closure::once(move |resolved: JsValue| -> JsValue { - let _ = flow_scope_api::pop_scope( - flow_scope_api::PopScopeParams::builder() + let _ = relay_scope_api::pop_scope( + relay_scope_api::PopScopeParams::builder() .handle_uuid(&then_uuid) .build(), ); @@ -500,8 +500,8 @@ pub fn with_scope( let catch_uuid = scope_uuid; let catch_cb = Closure::once(move |rejected: JsValue| -> JsValue { - let _ = flow_scope_api::pop_scope( - flow_scope_api::PopScopeParams::builder() + let _ = relay_scope_api::pop_scope( + relay_scope_api::PopScopeParams::builder() .handle_uuid(&catch_uuid) .build(), ); @@ -519,8 +519,8 @@ pub fn with_scope( } Ok(val) => { // Synchronous return — pop immediately. - let _ = flow_scope_api::pop_scope( - flow_scope_api::PopScopeParams::builder() + let _ = relay_scope_api::pop_scope( + relay_scope_api::PopScopeParams::builder() .handle_uuid(&scope_uuid) .build(), ); @@ -528,8 +528,8 @@ pub fn with_scope( } Err(err) => { // Callback threw — pop and propagate the error. - let _ = flow_scope_api::pop_scope( - flow_scope_api::PopScopeParams::builder() + let _ = relay_scope_api::pop_scope( + relay_scope_api::PopScopeParams::builder() .handle_uuid(&scope_uuid) .build(), ); @@ -556,8 +556,8 @@ pub fn event( ) -> Result<(), JsValue> { let handle = clone_scope_handle_arg(&handle)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_scope_api::event( - flow_scope_api::EmitMarkEventParams::builder() + relay_scope_api::event( + relay_scope_api::EmitMarkEventParams::builder() .name(name) .parent_opt(handle.as_ref()) .data_opt(opt_js_to_json(&data)?) @@ -610,8 +610,8 @@ pub fn tool_call( let attrs = ToolAttributes::from_bits_truncate(attributes.unwrap_or(0)); let handle = clone_scope_handle_arg(&handle)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_tool_api::tool_call( - flow_tool_api::ToolCallParams::builder() + relay_tool_api::tool_call( + relay_tool_api::ToolCallParams::builder() .name(name) .args(args_json) .parent_opt(handle.as_ref()) @@ -648,8 +648,8 @@ pub fn tool_call_end( ) -> Result<(), JsValue> { let result_json = js_to_json(&result)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_tool_api::tool_call_end( - flow_tool_api::ToolCallEndParams::builder() + relay_tool_api::tool_call_end( + relay_tool_api::ToolCallEndParams::builder() .handle(&handle.inner) .result(result_json) .data_opt(opt_js_to_json(&data)?) @@ -695,8 +695,8 @@ pub async fn tool_call_execute( let metadata_json = opt_js_to_json(&metadata)?; let result = TASK_SCOPE_STACK .scope(scope_stack, async move { - flow_tool_api::tool_call_execute( - flow_tool_api::ToolCallExecuteParams::builder() + relay_tool_api::tool_call_execute( + relay_tool_api::ToolCallExecuteParams::builder() .name(name) .args(args_json) .func(default_fn) @@ -758,7 +758,7 @@ pub fn llm_call( let attrs = LlmAttributes::from_bits_truncate(attributes.unwrap_or(0)); let handle = clone_scope_handle_arg(&handle)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - let params = flow_llm_api::LlmCallParams::builder() + let params = relay_llm_api::LlmCallParams::builder() .name(name) .request(&llm_request) .parent_opt(handle.as_ref()) @@ -768,7 +768,7 @@ pub fn llm_call( .model_name_opt(model_name) .timestamp_opt(timestamp) .build(); - flow_llm_api::llm_call(params) + relay_llm_api::llm_call(params) .map(LlmHandle::from) .map_err(to_js_err) } @@ -795,8 +795,8 @@ pub fn llm_call_end( ) -> Result<(), JsValue> { let response_json = js_to_json(&response)?; let timestamp = opt_js_to_timestamp_micros(timestamp)?; - flow_llm_api::llm_call_end( - flow_llm_api::LlmCallEndParams::builder() + relay_llm_api::llm_call_end( + relay_llm_api::LlmCallEndParams::builder() .handle(&handle.inner) .response(response_json) .data_opt(opt_js_to_json(&data)?) @@ -876,7 +876,7 @@ pub async fn llm_call_execute( let metadata_json = opt_js_to_json(&metadata)?; let result = TASK_SCOPE_STACK .scope(scope_stack, async move { - let params = flow_llm_api::LlmCallExecuteParams::builder() + let params = relay_llm_api::LlmCallExecuteParams::builder() .name(name) .request(llm_request) .func(default_fn) @@ -888,7 +888,7 @@ pub async fn llm_call_execute( .codec_opt(codec) .response_codec_opt(response_codec) .build(); - flow_llm_api::llm_call_execute(params).await + relay_llm_api::llm_call_execute(params).await }) .await .map_err(to_js_err)?; @@ -994,7 +994,7 @@ pub async fn llm_stream_call_execute( let metadata_json = opt_js_to_json(&metadata)?; let rust_stream = TASK_SCOPE_STACK .scope(scope_stack, async move { - let params = flow_llm_api::LlmStreamCallExecuteParams::builder() + let params = relay_llm_api::LlmStreamCallExecuteParams::builder() .name(name) .request(llm_request) .func(default_fn) @@ -1008,7 +1008,7 @@ pub async fn llm_stream_call_execute( .codec_opt(codec) .response_codec_opt(response_codec) .build(); - flow_llm_api::llm_stream_call_execute(params).await + relay_llm_api::llm_stream_call_execute(params).await }) .await .map_err(to_js_err)?; @@ -1044,7 +1044,7 @@ pub fn register_tool_sanitize_request_guardrail( priority: i32, #[wasm_bindgen(unchecked_param_type = "(name: string, args: Json) => any")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_tool_sanitize_request_guardrail( + relay_registry_api::register_tool_sanitize_request_guardrail( name, priority, callable::wrap_js_tool_fn(guardrail), @@ -1057,7 +1057,7 @@ pub fn register_tool_sanitize_request_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterToolSanitizeRequestGuardrail")] pub fn deregister_tool_sanitize_request_guardrail(name: &str) -> Result { - flow_registry_api::deregister_tool_sanitize_request_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_tool_sanitize_request_guardrail(name).map_err(to_js_err) } /// Registers a guardrail that sanitizes tool response data after execution. @@ -1072,7 +1072,7 @@ pub fn register_tool_sanitize_response_guardrail( #[wasm_bindgen(unchecked_param_type = "(name: string, result: Json) => any")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_tool_sanitize_response_guardrail( + relay_registry_api::register_tool_sanitize_response_guardrail( name, priority, callable::wrap_js_tool_fn(guardrail), @@ -1085,7 +1085,7 @@ pub fn register_tool_sanitize_response_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterToolSanitizeResponseGuardrail")] pub fn deregister_tool_sanitize_response_guardrail(name: &str) -> Result { - flow_registry_api::deregister_tool_sanitize_response_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_tool_sanitize_response_guardrail(name).map_err(to_js_err) } /// Registers a guardrail that conditionally gates tool execution. @@ -1102,7 +1102,7 @@ pub fn register_tool_conditional_execution_guardrail( priority: i32, #[wasm_bindgen(unchecked_param_type = "(name: string, args: Json) => string | null")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_tool_conditional_execution_guardrail( + relay_registry_api::register_tool_conditional_execution_guardrail( name, priority, callable::wrap_js_tool_conditional_fn(guardrail), @@ -1115,7 +1115,7 @@ pub fn register_tool_conditional_execution_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterToolConditionalExecutionGuardrail")] pub fn deregister_tool_conditional_execution_guardrail(name: &str) -> Result { - flow_registry_api::deregister_tool_conditional_execution_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_tool_conditional_execution_guardrail(name).map_err(to_js_err) } // Tool intercepts @@ -1137,7 +1137,7 @@ pub fn register_tool_request_intercept( )] func: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_tool_request_intercept( + relay_registry_api::register_tool_request_intercept( name, priority, break_chain, @@ -1151,7 +1151,7 @@ pub fn register_tool_request_intercept( /// Returns `true` if the intercept was found and removed. #[wasm_bindgen(js_name = "deregisterToolRequestIntercept")] pub fn deregister_tool_request_intercept(name: &str) -> Result { - flow_registry_api::deregister_tool_request_intercept(name).map_err(to_js_err) + relay_registry_api::deregister_tool_request_intercept(name).map_err(to_js_err) } /// Registers a tool execution intercept following the middleware chain pattern. @@ -1170,7 +1170,7 @@ pub fn register_tool_execution_intercept( )] exec_fn: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_tool_execution_intercept( + relay_registry_api::register_tool_execution_intercept( name, priority, callable::wrap_js_tool_exec_intercept_fn(exec_fn), @@ -1183,7 +1183,7 @@ pub fn register_tool_execution_intercept( /// Returns `true` if the intercept was found and removed. #[wasm_bindgen(js_name = "deregisterToolExecutionIntercept")] pub fn deregister_tool_execution_intercept(name: &str) -> Result { - flow_registry_api::deregister_tool_execution_intercept(name).map_err(to_js_err) + relay_registry_api::deregister_tool_execution_intercept(name).map_err(to_js_err) } // LLM guardrails @@ -1199,7 +1199,7 @@ pub fn register_llm_sanitize_request_guardrail( priority: i32, #[wasm_bindgen(unchecked_param_type = "(request: Json) => any")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_sanitize_request_guardrail( + relay_registry_api::register_llm_sanitize_request_guardrail( name, priority, callable::wrap_js_llm_sanitize_request_fn(guardrail), @@ -1212,7 +1212,7 @@ pub fn register_llm_sanitize_request_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterLlmSanitizeRequestGuardrail")] pub fn deregister_llm_sanitize_request_guardrail(name: &str) -> Result { - flow_registry_api::deregister_llm_sanitize_request_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_llm_sanitize_request_guardrail(name).map_err(to_js_err) } /// Registers a guardrail that sanitizes LLM response data after the call. @@ -1226,7 +1226,7 @@ pub fn register_llm_sanitize_response_guardrail( priority: i32, #[wasm_bindgen(unchecked_param_type = "(response: Json) => any")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_sanitize_response_guardrail( + relay_registry_api::register_llm_sanitize_response_guardrail( name, priority, callable::wrap_js_llm_response_fn(guardrail), @@ -1239,7 +1239,7 @@ pub fn register_llm_sanitize_response_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterLlmSanitizeResponseGuardrail")] pub fn deregister_llm_sanitize_response_guardrail(name: &str) -> Result { - flow_registry_api::deregister_llm_sanitize_response_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_llm_sanitize_response_guardrail(name).map_err(to_js_err) } /// Registers a guardrail that conditionally gates LLM execution. @@ -1256,7 +1256,7 @@ pub fn register_llm_conditional_execution_guardrail( priority: i32, #[wasm_bindgen(unchecked_param_type = "(request: Json) => string | null")] guardrail: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_conditional_execution_guardrail( + relay_registry_api::register_llm_conditional_execution_guardrail( name, priority, callable::wrap_js_llm_conditional_fn(guardrail), @@ -1269,7 +1269,7 @@ pub fn register_llm_conditional_execution_guardrail( /// Returns `true` if the guardrail was found and removed. #[wasm_bindgen(js_name = "deregisterLlmConditionalExecutionGuardrail")] pub fn deregister_llm_conditional_execution_guardrail(name: &str) -> Result { - flow_registry_api::deregister_llm_conditional_execution_guardrail(name).map_err(to_js_err) + relay_registry_api::deregister_llm_conditional_execution_guardrail(name).map_err(to_js_err) } // LLM intercepts @@ -1288,7 +1288,7 @@ pub fn register_llm_request_intercept( #[wasm_bindgen(js_name = "callable", unchecked_param_type = "(request: Json) => any")] func: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_request_intercept( + relay_registry_api::register_llm_request_intercept( name, priority, break_chain, @@ -1302,7 +1302,7 @@ pub fn register_llm_request_intercept( /// Returns `true` if the intercept was found and removed. #[wasm_bindgen(js_name = "deregisterLlmRequestIntercept")] pub fn deregister_llm_request_intercept(name: &str) -> Result { - flow_registry_api::deregister_llm_request_intercept(name).map_err(to_js_err) + relay_registry_api::deregister_llm_request_intercept(name).map_err(to_js_err) } /// Registers an LLM execution intercept following the middleware chain pattern. @@ -1321,7 +1321,7 @@ pub fn register_llm_execution_intercept( )] exec_fn: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_execution_intercept( + relay_registry_api::register_llm_execution_intercept( name, priority, callable::wrap_js_llm_exec_intercept_fn(exec_fn), @@ -1334,7 +1334,7 @@ pub fn register_llm_execution_intercept( /// Returns `true` if the intercept was found and removed. #[wasm_bindgen(js_name = "deregisterLlmExecutionIntercept")] pub fn deregister_llm_execution_intercept(name: &str) -> Result { - flow_registry_api::deregister_llm_execution_intercept(name).map_err(to_js_err) + relay_registry_api::deregister_llm_execution_intercept(name).map_err(to_js_err) } /// Registers a streaming LLM execution intercept following the middleware chain pattern. @@ -1355,7 +1355,7 @@ pub fn register_llm_stream_execution_intercept( )] exec_fn: Function, ) -> Result<(), JsValue> { - flow_registry_api::register_llm_stream_execution_intercept( + relay_registry_api::register_llm_stream_execution_intercept( name, priority, callable::wrap_js_llm_stream_exec_intercept_fn(exec_fn), @@ -1368,7 +1368,7 @@ pub fn register_llm_stream_execution_intercept( /// Returns `true` if the intercept was found and removed. #[wasm_bindgen(js_name = "deregisterLlmStreamExecutionIntercept")] pub fn deregister_llm_stream_execution_intercept(name: &str) -> Result { - flow_registry_api::deregister_llm_stream_execution_intercept(name).map_err(to_js_err) + relay_registry_api::deregister_llm_stream_execution_intercept(name).map_err(to_js_err) } // --------------------------------------------------------------------------- @@ -1384,7 +1384,7 @@ pub fn register_subscriber( name: &str, #[wasm_bindgen(unchecked_param_type = "(event: Json) => any")] callback: Function, ) -> Result<(), JsValue> { - flow_subscriber_api::register_subscriber(name, callable::wrap_js_event_subscriber(callback)) + relay_subscriber_api::register_subscriber(name, callable::wrap_js_event_subscriber(callback)) .map_err(to_js_err) } @@ -1393,7 +1393,7 @@ pub fn register_subscriber( /// Returns `true` if the subscriber was found and removed. #[wasm_bindgen(js_name = "deregisterSubscriber")] pub fn deregister_subscriber(name: &str) -> Result { - flow_subscriber_api::deregister_subscriber(name).map_err(to_js_err) + relay_subscriber_api::deregister_subscriber(name).map_err(to_js_err) } // --------------------------------------------------------------------------- @@ -1415,7 +1415,7 @@ pub fn scope_register_tool_sanitize_request_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_tool_sanitize_request_guardrail( + relay_registry_api::scope_register_tool_sanitize_request_guardrail( &uuid, name, priority, @@ -1434,7 +1434,7 @@ pub fn scope_deregister_tool_sanitize_request_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_tool_sanitize_request_guardrail(&uuid, name) + relay_registry_api::scope_deregister_tool_sanitize_request_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1454,7 +1454,7 @@ pub fn scope_register_tool_sanitize_response_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_tool_sanitize_response_guardrail( + relay_registry_api::scope_register_tool_sanitize_response_guardrail( &uuid, name, priority, @@ -1473,7 +1473,7 @@ pub fn scope_deregister_tool_sanitize_response_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_tool_sanitize_response_guardrail(&uuid, name) + relay_registry_api::scope_deregister_tool_sanitize_response_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1495,7 +1495,7 @@ pub fn scope_register_tool_conditional_execution_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_tool_conditional_execution_guardrail( + relay_registry_api::scope_register_tool_conditional_execution_guardrail( &uuid, name, priority, @@ -1514,7 +1514,7 @@ pub fn scope_deregister_tool_conditional_execution_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_tool_conditional_execution_guardrail(&uuid, name) + relay_registry_api::scope_deregister_tool_conditional_execution_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1543,7 +1543,7 @@ pub fn scope_register_tool_request_intercept( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_tool_request_intercept( + relay_registry_api::scope_register_tool_request_intercept( &uuid, name, priority, @@ -1563,7 +1563,7 @@ pub fn scope_deregister_tool_request_intercept( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_tool_request_intercept(&uuid, name).map_err(to_js_err) + relay_registry_api::scope_deregister_tool_request_intercept(&uuid, name).map_err(to_js_err) } /// Registers a scope-local tool execution intercept following the middleware chain pattern. @@ -1586,7 +1586,7 @@ pub fn scope_register_tool_execution_intercept( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_tool_execution_intercept( + relay_registry_api::scope_register_tool_execution_intercept( &uuid, name, priority, @@ -1605,7 +1605,7 @@ pub fn scope_deregister_tool_execution_intercept( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_tool_execution_intercept(&uuid, name).map_err(to_js_err) + relay_registry_api::scope_deregister_tool_execution_intercept(&uuid, name).map_err(to_js_err) } // --------------------------------------------------------------------------- @@ -1627,7 +1627,7 @@ pub fn scope_register_llm_sanitize_request_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_sanitize_request_guardrail( + relay_registry_api::scope_register_llm_sanitize_request_guardrail( &uuid, name, priority, @@ -1646,7 +1646,7 @@ pub fn scope_deregister_llm_sanitize_request_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_sanitize_request_guardrail(&uuid, name) + relay_registry_api::scope_deregister_llm_sanitize_request_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1665,7 +1665,7 @@ pub fn scope_register_llm_sanitize_response_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_sanitize_response_guardrail( + relay_registry_api::scope_register_llm_sanitize_response_guardrail( &uuid, name, priority, @@ -1684,7 +1684,7 @@ pub fn scope_deregister_llm_sanitize_response_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_sanitize_response_guardrail(&uuid, name) + relay_registry_api::scope_deregister_llm_sanitize_response_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1706,7 +1706,7 @@ pub fn scope_register_llm_conditional_execution_guardrail( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_conditional_execution_guardrail( + relay_registry_api::scope_register_llm_conditional_execution_guardrail( &uuid, name, priority, @@ -1725,7 +1725,7 @@ pub fn scope_deregister_llm_conditional_execution_guardrail( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_conditional_execution_guardrail(&uuid, name) + relay_registry_api::scope_deregister_llm_conditional_execution_guardrail(&uuid, name) .map_err(to_js_err) } @@ -1751,7 +1751,7 @@ pub fn scope_register_llm_request_intercept( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_request_intercept( + relay_registry_api::scope_register_llm_request_intercept( &uuid, name, priority, @@ -1771,7 +1771,7 @@ pub fn scope_deregister_llm_request_intercept( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_request_intercept(&uuid, name).map_err(to_js_err) + relay_registry_api::scope_deregister_llm_request_intercept(&uuid, name).map_err(to_js_err) } /// Registers a scope-local LLM execution intercept following the middleware chain pattern. @@ -1794,7 +1794,7 @@ pub fn scope_register_llm_execution_intercept( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_execution_intercept( + relay_registry_api::scope_register_llm_execution_intercept( &uuid, name, priority, @@ -1813,7 +1813,7 @@ pub fn scope_deregister_llm_execution_intercept( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_execution_intercept(&uuid, name).map_err(to_js_err) + relay_registry_api::scope_deregister_llm_execution_intercept(&uuid, name).map_err(to_js_err) } /// Registers a scope-local streaming LLM execution intercept following the middleware chain pattern. @@ -1838,7 +1838,7 @@ pub fn scope_register_llm_stream_execution_intercept( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_register_llm_stream_execution_intercept( + relay_registry_api::scope_register_llm_stream_execution_intercept( &uuid, name, priority, @@ -1857,7 +1857,7 @@ pub fn scope_deregister_llm_stream_execution_intercept( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_registry_api::scope_deregister_llm_stream_execution_intercept(&uuid, name) + relay_registry_api::scope_deregister_llm_stream_execution_intercept(&uuid, name) .map_err(to_js_err) } @@ -1879,7 +1879,7 @@ pub fn scope_register_subscriber( ) -> Result<(), JsValue> { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_subscriber_api::scope_register_subscriber( + relay_subscriber_api::scope_register_subscriber( &uuid, name, callable::wrap_js_event_subscriber(callback), @@ -1897,7 +1897,7 @@ pub fn scope_deregister_subscriber( ) -> Result { let uuid = uuid::Uuid::parse_str(scope_uuid) .map_err(|e| JsValue::from_str(&format!("invalid UUID: {e}")))?; - flow_subscriber_api::scope_deregister_subscriber(&uuid, name).map_err(to_js_err) + relay_subscriber_api::scope_deregister_subscriber(&uuid, name).map_err(to_js_err) } // --------------------------------------------------------------------------- @@ -1947,7 +1947,7 @@ pub fn tool_request_intercepts_wasm( #[wasm_bindgen(unchecked_param_type = "Json")] args: JsValue, ) -> Result { let args_json = js_to_json(&args)?; - let result = flow_tool_api::tool_request_intercepts(name, args_json).map_err(to_js_err)?; + let result = relay_tool_api::tool_request_intercepts(name, args_json).map_err(to_js_err)?; Ok(json_to_js(&result)) } @@ -1958,7 +1958,7 @@ pub fn tool_conditional_execution_wasm( #[wasm_bindgen(unchecked_param_type = "Json")] args: JsValue, ) -> Result<(), JsValue> { let args_json = js_to_json(&args)?; - flow_tool_api::tool_conditional_execution(name, &args_json).map_err(to_js_err) + relay_tool_api::tool_conditional_execution(name, &args_json).map_err(to_js_err) } /// Runs the registered LLM request intercept chain on the given `LlmRequest`. @@ -1970,7 +1970,7 @@ pub fn llm_request_intercepts_wasm( let request_json = js_to_json(&request)?; let llm_request: CoreLlmRequest = serde_json::from_value(request_json) .map_err(|e| to_js_err(FlowError::Internal(e.to_string())))?; - let result = flow_llm_api::llm_request_intercepts(name, llm_request).map_err(to_js_err)?; + let result = relay_llm_api::llm_request_intercepts(name, llm_request).map_err(to_js_err)?; let result_json = serde_json::to_value(&result).map_err(|e| to_js_err(FlowError::Internal(e.to_string())))?; Ok(json_to_js(&result_json)) @@ -1986,7 +1986,7 @@ pub fn llm_conditional_execution_wasm( let request_json = js_to_json(&request)?; let llm_request: CoreLlmRequest = serde_json::from_value(request_json) .map_err(|e| to_js_err(FlowError::Internal(e.to_string())))?; - flow_llm_api::llm_conditional_execution(&llm_request).map_err(to_js_err) + relay_llm_api::llm_conditional_execution(&llm_request).map_err(to_js_err) } // --------------------------------------------------------------------------- @@ -1996,7 +1996,7 @@ pub fn llm_conditional_execution_wasm( /// ATIF trajectory exporter for collecting events and producing ATIF JSON. #[wasm_bindgen(js_name = AtifExporter)] pub struct AtifExporter { - inner: nemo_flow::observability::atif::AtifExporter, + inner: nemo_relay::observability::atif::AtifExporter, } #[wasm_bindgen(js_class = AtifExporter)] @@ -2014,7 +2014,7 @@ impl AtifExporter { )] model_name: Option, ) -> Self { - let agent_info = nemo_flow::observability::atif::AtifAgentInfo { + let agent_info = nemo_relay::observability::atif::AtifAgentInfo { name: agent_name, version: agent_version, model_name, @@ -2022,20 +2022,20 @@ impl AtifExporter { extra: None, }; Self { - inner: nemo_flow::observability::atif::AtifExporter::new(session_id, agent_info), + inner: nemo_relay::observability::atif::AtifExporter::new(session_id, agent_info), } } /// Registers the exporter as an event subscriber. pub fn register(&self, name: &str) -> Result<(), JsValue> { let subscriber = self.inner.subscriber(); - flow_subscriber_api::register_subscriber(name, subscriber) + relay_subscriber_api::register_subscriber(name, subscriber) .map_err(|e| JsValue::from_str(&e.to_string())) } /// Deregisters the exporter subscriber. pub fn deregister(&self, name: &str) -> Result { - flow_subscriber_api::deregister_subscriber(name) + relay_subscriber_api::deregister_subscriber(name) .map_err(|e| JsValue::from_str(&e.to_string())) } @@ -2066,7 +2066,7 @@ pub fn default_open_telemetry_config() -> Result { /// OpenTelemetry-backed event subscriber. #[wasm_bindgen(js_name = OpenTelemetrySubscriber)] pub struct OpenTelemetrySubscriber { - inner: nemo_flow::observability::otel::OpenTelemetrySubscriber, + inner: nemo_relay::observability::otel::OpenTelemetrySubscriber, } #[wasm_bindgen(js_class = OpenTelemetrySubscriber)] @@ -2089,7 +2089,7 @@ impl OpenTelemetrySubscriber { _ => None, }; - let inner = nemo_flow::observability::otel::OpenTelemetrySubscriber::new( + let inner = nemo_relay::observability::otel::OpenTelemetrySubscriber::new( build_otel_config(config)?, ) .map_err(|e| JsValue::from_str(&e.to_string()))?; @@ -2203,7 +2203,7 @@ impl PluginContext { #[wasm_bindgen(unchecked_param_type = "(event: Json) => any")] callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_subscriber_api::register_subscriber( + relay_subscriber_api::register_subscriber( &qualified_name, crate::callable::wrap_js_event_subscriber(callback), ) @@ -2214,7 +2214,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_subscriber_api::deregister_subscriber(&name_owned) + relay_subscriber_api::deregister_subscriber(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2243,7 +2243,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_tool_sanitize_request_guardrail( + relay_registry_api::register_tool_sanitize_request_guardrail( &qualified_name, priority, crate::callable::wrap_js_tool_fn(callback), @@ -2255,7 +2255,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_tool_sanitize_request_guardrail(&name_owned) + relay_registry_api::deregister_tool_sanitize_request_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2284,7 +2284,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_tool_sanitize_response_guardrail( + relay_registry_api::register_tool_sanitize_response_guardrail( &qualified_name, priority, crate::callable::wrap_js_tool_fn(callback), @@ -2296,7 +2296,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_tool_sanitize_response_guardrail(&name_owned) + relay_registry_api::deregister_tool_sanitize_response_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2326,7 +2326,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_tool_conditional_execution_guardrail( + relay_registry_api::register_tool_conditional_execution_guardrail( &qualified_name, priority, crate::callable::wrap_js_tool_conditional_fn(callback), @@ -2338,7 +2338,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_tool_conditional_execution_guardrail(&name_owned) + relay_registry_api::deregister_tool_conditional_execution_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2366,7 +2366,7 @@ impl PluginContext { #[wasm_bindgen(unchecked_param_type = "(request: Json) => any")] callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_sanitize_request_guardrail( + relay_registry_api::register_llm_sanitize_request_guardrail( &qualified_name, priority, crate::callable::wrap_js_llm_sanitize_request_fn(callback), @@ -2378,7 +2378,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_sanitize_request_guardrail(&name_owned) + relay_registry_api::deregister_llm_sanitize_request_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2406,7 +2406,7 @@ impl PluginContext { #[wasm_bindgen(unchecked_param_type = "(response: Json) => any")] callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_sanitize_response_guardrail( + relay_registry_api::register_llm_sanitize_response_guardrail( &qualified_name, priority, crate::callable::wrap_js_llm_response_fn(callback), @@ -2418,7 +2418,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_sanitize_response_guardrail(&name_owned) + relay_registry_api::deregister_llm_sanitize_response_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2448,7 +2448,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_conditional_execution_guardrail( + relay_registry_api::register_llm_conditional_execution_guardrail( &qualified_name, priority, crate::callable::wrap_js_llm_conditional_fn(callback), @@ -2460,7 +2460,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_conditional_execution_guardrail(&name_owned) + relay_registry_api::deregister_llm_conditional_execution_guardrail(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2490,7 +2490,7 @@ impl PluginContext { #[wasm_bindgen(unchecked_param_type = "(request: Json) => any")] callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_request_intercept( + relay_registry_api::register_llm_request_intercept( &qualified_name, priority, break_chain, @@ -2503,7 +2503,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_request_intercept(&name_owned) + relay_registry_api::deregister_llm_request_intercept(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2535,7 +2535,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_execution_intercept( + relay_registry_api::register_llm_execution_intercept( &qualified_name, priority, crate::callable::wrap_js_llm_exec_intercept_fn(callback), @@ -2547,7 +2547,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_execution_intercept(&name_owned) + relay_registry_api::deregister_llm_execution_intercept(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2579,7 +2579,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_llm_stream_execution_intercept( + relay_registry_api::register_llm_stream_execution_intercept( &qualified_name, priority, crate::callable::wrap_js_llm_stream_exec_intercept_fn(callback), @@ -2591,7 +2591,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_llm_stream_execution_intercept(&name_owned) + relay_registry_api::deregister_llm_stream_execution_intercept(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2622,7 +2622,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_tool_request_intercept( + relay_registry_api::register_tool_request_intercept( &qualified_name, priority, break_chain, @@ -2635,7 +2635,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_tool_request_intercept(&name_owned) + relay_registry_api::deregister_tool_request_intercept(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2667,7 +2667,7 @@ impl PluginContext { callback: Function, ) -> Result<(), JsValue> { let qualified_name = self.qualify_name(name); - flow_registry_api::register_tool_execution_intercept( + relay_registry_api::register_tool_execution_intercept( &qualified_name, priority, crate::callable::wrap_js_tool_exec_intercept_fn(callback), @@ -2679,7 +2679,7 @@ impl PluginContext { "plugin", name_owned.clone(), Box::new(move || { - flow_registry_api::deregister_tool_execution_intercept(&name_owned) + relay_registry_api::deregister_tool_execution_intercept(&name_owned) .map(|_| ()) .map_err(|e| { PluginError::RegistrationFailed(format!( @@ -2847,7 +2847,7 @@ pub fn list_plugin_kinds() -> Result { /// OpenInference-backed event subscriber. #[wasm_bindgen(js_name = OpenInferenceSubscriber)] pub struct OpenInferenceSubscriber { - inner: nemo_flow::observability::openinference::OpenInferenceSubscriber, + inner: nemo_relay::observability::openinference::OpenInferenceSubscriber, } #[wasm_bindgen(js_class = OpenInferenceSubscriber)] @@ -2866,7 +2866,7 @@ impl OpenInferenceSubscriber { _ => None, }; - let inner = nemo_flow::observability::openinference::OpenInferenceSubscriber::new( + let inner = nemo_relay::observability::openinference::OpenInferenceSubscriber::new( build_openinference_config(config)?, ) .map_err(|e| JsValue::from_str(&e.to_string()))?; diff --git a/crates/wasm/src/callable.rs b/crates/wasm/src/callable.rs index f8e0a8643..4cf4b2135 100644 --- a/crates/wasm/src/callable.rs +++ b/crates/wasm/src/callable.rs @@ -28,18 +28,18 @@ use wasm_bindgen::JsValue; #[cfg(target_arch = "wasm32")] use wasm_bindgen_futures::JsFuture; -use nemo_flow::api::event::Event; -use nemo_flow::api::llm::LlmRequest; -use nemo_flow::api::runtime::{ +use nemo_relay::api::event::Event; +use nemo_relay::api::llm::LlmRequest; +use nemo_relay::api::runtime::{ EventSubscriberFn, LlmConditionalFn, LlmExecutionNextFn, LlmRequestInterceptFn, LlmSanitizeRequestFn, LlmSanitizeResponseFn, LlmStreamExecutionNextFn, ToolConditionalFn, ToolExecutionNextFn, ToolInterceptFn, ToolSanitizeFn, }; -use nemo_flow::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest; #[cfg(target_arch = "wasm32")] -use nemo_flow::codec::response::AnnotatedLlmResponse; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::{FlowError, Result}; +use nemo_relay::codec::response::AnnotatedLlmResponse; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::{FlowError, Result}; #[cfg(target_arch = "wasm32")] use crate::convert::record_callback_error; @@ -57,13 +57,13 @@ fn js_error_message(e: &JsValue) -> String { } #[cfg(target_arch = "wasm32")] -fn flow_error_from_js(e: &JsValue) -> FlowError { +fn relay_error_from_js(e: &JsValue) -> FlowError { FlowError::Internal(js_error_message(e)) } #[cfg(target_arch = "wasm32")] -fn flow_json_from_js(val: &JsValue) -> Result { - js_callback_to_json(val).map_err(|e| flow_error_from_js(&e)) +fn relay_json_from_js(val: &JsValue) -> Result { + js_callback_to_json(val).map_err(|e| relay_error_from_js(&e)) } #[cfg(target_arch = "wasm32")] @@ -124,13 +124,13 @@ async fn resolve_js_value(result: std::result::Result) -> Resu if let Some(promise) = val.dyn_ref::() { let resolved = JsFuture::from(promise.clone()) .await - .map_err(|e| flow_error_from_js(&e))?; - flow_json_from_js(&resolved) + .map_err(|e| relay_error_from_js(&e))?; + relay_json_from_js(&resolved) } else { - flow_json_from_js(&val) + relay_json_from_js(&val) } } - Err(e) => Err(flow_error_from_js(&e)), + Err(e) => Err(relay_error_from_js(&e)), } } @@ -168,8 +168,8 @@ pub fn wrap_js_tool_fn(func: Function) -> ToolSanitizeFn { // errors through the type system. Log errors so failures are not silent. callback_json_or_fallback( func.call2(&JsValue::NULL, &js_name, &js_args), - "nemo_flow: JS tool callback result conversion failed", - "nemo_flow: JS tool callback threw", + "nemo_relay: JS tool callback result conversion failed", + "nemo_relay: JS tool callback threw", Json::Null, ) }) @@ -218,8 +218,8 @@ pub fn wrap_js_tool_request_intercept_fn(func: Function) -> ToolInterceptFn { let js_args = json_to_js(&args); let result = func .call2(&JsValue::NULL, &js_name, &js_args) - .map_err(|e| flow_error_from_js(&e))?; - flow_json_from_js(&result) + .map_err(|e| relay_error_from_js(&e))?; + relay_json_from_js(&result) }) } @@ -245,14 +245,14 @@ pub fn wrap_js_tool_exec_fn( // Check if it's a Promise if let Some(promise) = val.dyn_ref::() { match JsFuture::from(promise.clone()).await { - Ok(resolved) => flow_json_from_js(&resolved), - Err(e) => Err(flow_error_from_js(&e)), + Ok(resolved) => relay_json_from_js(&resolved), + Err(e) => Err(relay_error_from_js(&e)), } } else { - flow_json_from_js(&val) + relay_json_from_js(&val) } } - Err(e) => Err(flow_error_from_js(&e)), + Err(e) => Err(relay_error_from_js(&e)), } })) }) @@ -313,7 +313,7 @@ pub fn wrap_js_llm_request_intercept_fn(func: Function) -> LlmRequestInterceptFn )) })?; let new_req_json = - js_callback_to_json(&js_new_req).map_err(|e| flow_error_from_js(&e))?; + js_callback_to_json(&js_new_req).map_err(|e| relay_error_from_js(&e))?; let new_request: LlmRequest = serde_json::from_value(new_req_json).map_err(|e| { FlowError::Internal(format!("failed to deserialize LlmRequest: {e}")) })?; @@ -361,8 +361,8 @@ pub fn wrap_js_llm_sanitize_request_fn(func: Function) -> LlmSanitizeRequestFn { // errors through the type system. Log errors so failures are not silent. let result_json = callback_json_or_fallback( func.call1(&JsValue::NULL, &js_req), - "nemo_flow: JS LLM sanitize request result conversion failed", - "nemo_flow: JS LLM sanitize request callback threw", + "nemo_relay: JS LLM sanitize request result conversion failed", + "nemo_relay: JS LLM sanitize request callback threw", Json::Null, ); serde_json::from_value(result_json).unwrap_or(request) @@ -383,7 +383,7 @@ pub fn wrap_js_llm_conditional_fn(func: Function) -> LlmConditionalFn { let js_req = json_to_js(&req_json); let result = func .call1(&JsValue::NULL, &js_req) - .map_err(|e| flow_error_from_js(&e))?; + .map_err(|e| relay_error_from_js(&e))?; if result.is_null() || result.is_undefined() { Ok(None) @@ -422,14 +422,14 @@ pub fn wrap_js_llm_exec_fn( Ok(val) => { if let Some(promise) = val.dyn_ref::() { match JsFuture::from(promise.clone()).await { - Ok(resolved) => flow_json_from_js(&resolved), - Err(e) => Err(flow_error_from_js(&e)), + Ok(resolved) => relay_json_from_js(&resolved), + Err(e) => Err(relay_error_from_js(&e)), } } else { - flow_json_from_js(&val) + relay_json_from_js(&val) } } - Err(e) => Err(flow_error_from_js(&e)), + Err(e) => Err(relay_error_from_js(&e)), } })) }) @@ -457,7 +457,7 @@ pub fn wrap_js_collector_fn(func: Function) -> Box Result<()> let msg = e .as_string() .unwrap_or_else(|| "JS collector threw an exception".to_string()); - record_callback_error(format!("nemo_flow: {msg}")); + record_callback_error(format!("nemo_relay: {msg}")); Err(FlowError::Internal(msg)) } } @@ -482,8 +482,8 @@ pub fn wrap_js_finalizer_fn(func: Function) -> Box Json + Send> // errors through the type system. Log errors so failures are not silent. callback_json_or_fallback( func.call0(&JsValue::NULL), - "nemo_flow: JS finalizer result conversion failed", - "nemo_flow: JS finalizer callback threw", + "nemo_relay: JS finalizer result conversion failed", + "nemo_relay: JS finalizer callback threw", Json::Null, ) }) @@ -503,7 +503,7 @@ pub fn wrap_js_event_subscriber(func: Function) -> EventSubscriberFn { Ok(event) => event, Err(error) => { record_callback_error(format!( - "nemo_flow: failed to serialize JS event subscriber payload: {error}" + "nemo_relay: failed to serialize JS event subscriber payload: {error}" )); return; } @@ -513,11 +513,11 @@ pub fn wrap_js_event_subscriber(func: Function) -> EventSubscriberFn { .unwrap_or(JsValue::NULL); if let Err(e) = func.call1(&JsValue::NULL, &js_event) { record_callback_error(format!( - "nemo_flow: JS event subscriber callback threw: {}", + "nemo_relay: JS event subscriber callback threw: {}", js_error_message(&e) )); eprintln!( - "nemo_flow: JS event subscriber callback threw: {}", + "nemo_relay: JS event subscriber callback threw: {}", js_error_message(&e) ); } @@ -574,14 +574,14 @@ pub fn wrap_js_tool_exec_intercept_fn( Ok(val) => { if let Some(promise) = val.dyn_ref::() { match JsFuture::from(promise.clone()).await { - Ok(resolved) => flow_json_from_js(&resolved), - Err(e) => Err(flow_error_from_js(&e)), + Ok(resolved) => relay_json_from_js(&resolved), + Err(e) => Err(relay_error_from_js(&e)), } } else { - flow_json_from_js(&val) + relay_json_from_js(&val) } } - Err(e) => Err(flow_error_from_js(&e)), + Err(e) => Err(relay_error_from_js(&e)), } })) }) @@ -905,8 +905,8 @@ pub fn wrap_js_llm_response_fn(func: Function) -> LlmSanitizeResponseFn { // errors through the type system. Log errors and fall back to original response. callback_json_or_fallback( func.call1(&JsValue::NULL, &js_resp), - "nemo_flow: JS LLM response callback result conversion failed", - "nemo_flow: JS LLM response callback threw", + "nemo_relay: JS LLM response callback result conversion failed", + "nemo_relay: JS LLM response callback threw", response, ) }) diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index fb721348c..00fbcd1af 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! WebAssembly bindings for the NeMo Flow agent runtime framework. +//! WebAssembly bindings for the NeMo Relay agent runtime framework. //! -//! This crate exposes the core NeMo Flow API to JavaScript/TypeScript via +//! This crate exposes the core NeMo Relay API to JavaScript/TypeScript via //! `wasm-bindgen`. It provides scope management, tool and LLM lifecycle //! operations, guardrail/intercept registration, event subscriptions, and //! streaming LLM responses. diff --git a/crates/wasm/src/stream.rs b/crates/wasm/src/stream.rs index 8875db338..213e50e8c 100644 --- a/crates/wasm/src/stream.rs +++ b/crates/wasm/src/stream.rs @@ -11,8 +11,8 @@ use serde::Serialize; use wasm_bindgen::prelude::*; -use nemo_flow::error::Result as FlowResult; -use nemo_flow::json::Json; +use nemo_relay::error::Result as FlowResult; +use nemo_relay::json::Json; /// Wraps a streaming LLM response for consumption from JavaScript/TypeScript. /// diff --git a/crates/wasm/src/types/mod.rs b/crates/wasm/src/types/mod.rs index b196ae03b..0259ce4fd 100644 --- a/crates/wasm/src/types/mod.rs +++ b/crates/wasm/src/types/mod.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! WebAssembly-friendly wrapper types for the NeMo Flow runtime. +//! WebAssembly-friendly wrapper types for the NeMo Relay runtime. //! //! This module mirrors the Node binding pattern: exported Rust wrapper types //! use the canonical JS-facing names, while imported core runtime types are @@ -10,21 +10,21 @@ use serde::Serialize; use wasm_bindgen::prelude::*; -use nemo_flow::api::event::Event; +use nemo_relay::api::event::Event; #[cfg(test)] -use nemo_flow::api::llm::LlmAttributes; -use nemo_flow::api::llm::{LlmHandle as CoreLlmHandle, LlmRequest as CoreLlmRequest}; -use nemo_flow::api::runtime::{ScopeStackHandle, create_scope_stack}; +use nemo_relay::api::llm::LlmAttributes; +use nemo_relay::api::llm::{LlmHandle as CoreLlmHandle, LlmRequest as CoreLlmRequest}; +use nemo_relay::api::runtime::{ScopeStackHandle, create_scope_stack}; #[cfg(test)] -use nemo_flow::api::scope::ScopeAttributes; -use nemo_flow::api::scope::{ScopeHandle as CoreScopeHandle, ScopeType as CoreScopeType}; +use nemo_relay::api::scope::ScopeAttributes; +use nemo_relay::api::scope::{ScopeHandle as CoreScopeHandle, ScopeType as CoreScopeType}; #[cfg(test)] -use nemo_flow::api::tool::ToolAttributes; -use nemo_flow::api::tool::ToolHandle as CoreToolHandle; -use nemo_flow::codec::request::AnnotatedLlmRequest; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; -use nemo_flow::error::FlowError; -use nemo_flow::json::Json; +use nemo_relay::api::tool::ToolAttributes; +use nemo_relay::api::tool::ToolHandle as CoreToolHandle; +use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::error::FlowError; +use nemo_relay::json::Json; // --------------------------------------------------------------------------- // Enums and constants used by the WebAssembly bindings. @@ -457,9 +457,9 @@ impl OpenAIChatCodec { #[wasm_bindgen(constructor)] pub fn new() -> Self { Self { - inner_codec: std::sync::Arc::new(nemo_flow::codec::openai_chat::OpenAIChatCodec), + inner_codec: std::sync::Arc::new(nemo_relay::codec::openai_chat::OpenAIChatCodec), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::openai_chat::OpenAIChatCodec, + nemo_relay::codec::openai_chat::OpenAIChatCodec, ), } } @@ -544,10 +544,10 @@ impl OpenAIResponsesCodec { pub fn new() -> Self { Self { inner_codec: std::sync::Arc::new( - nemo_flow::codec::openai_responses::OpenAIResponsesCodec, + nemo_relay::codec::openai_responses::OpenAIResponsesCodec, ), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::openai_responses::OpenAIResponsesCodec, + nemo_relay::codec::openai_responses::OpenAIResponsesCodec, ), } } @@ -631,9 +631,9 @@ impl AnthropicMessagesCodec { #[wasm_bindgen(constructor)] pub fn new() -> Self { Self { - inner_codec: std::sync::Arc::new(nemo_flow::codec::anthropic::AnthropicMessagesCodec), + inner_codec: std::sync::Arc::new(nemo_relay::codec::anthropic::AnthropicMessagesCodec), inner_response_codec: std::sync::Arc::new( - nemo_flow::codec::anthropic::AnthropicMessagesCodec, + nemo_relay::codec::anthropic::AnthropicMessagesCodec, ), } } diff --git a/crates/wasm/tests-js/adaptive_tests.mjs b/crates/wasm/tests-js/adaptive_tests.mjs index 917f7fee4..ebe63aab3 100644 --- a/crates/wasm/tests-js/adaptive_tests.mjs +++ b/crates/wasm/tests-js/adaptive_tests.mjs @@ -33,7 +33,7 @@ test('WebAssembly adaptive wrappers expose backend and telemetry helpers', () => kind: 'redis', config: { url: 'redis://127.0.0.1:6379', - key_prefix: 'nemo_flow:', + key_prefix: 'nemo_relay:', }, }); assert.deepEqual( diff --git a/crates/wasm/tests-js/index_loader_tests.mjs b/crates/wasm/tests-js/index_loader_tests.mjs index db2e24c74..cf930a171 100644 --- a/crates/wasm/tests-js/index_loader_tests.mjs +++ b/crates/wasm/tests-js/index_loader_tests.mjs @@ -11,9 +11,9 @@ import { pkgDir, testsJsDir, wasm } from './test_support.mjs'; test('WebAssembly generated package exposes the expected package metadata', () => { const packageJson = JSON.parse(fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8')); - assert.equal(packageJson.name, 'nemo-flow-wasm'); - assert.equal(packageJson.types, 'nemo_flow_wasm.d.ts'); - assert.equal(packageJson.exports['.'].types, './nemo_flow_wasm.d.ts'); + assert.equal(packageJson.name, 'nemo-relay-wasm'); + assert.equal(packageJson.types, 'nemo_relay_wasm.d.ts'); + assert.equal(packageJson.exports['.'].types, './nemo_relay_wasm.d.ts'); assert.equal(packageJson.exports['./typed'].default, './typed.js'); assert.equal(packageJson.exports['./plugin'].default, './plugin.js'); assert.equal(packageJson.exports['./adaptive'].default, './adaptive.js'); @@ -25,7 +25,7 @@ test('WebAssembly generated package exposes the expected package metadata', () = test('WebAssembly generated package includes the expected wrapper files', () => { const expectedFiles = [ 'index.js', - 'nemo_flow_wasm.d.ts', + 'nemo_relay_wasm.d.ts', 'typed.js', 'typed.d.ts', 'plugin.js', @@ -41,21 +41,21 @@ test('WebAssembly generated package includes the expected wrapper files', () => test('WebAssembly package keeps the generated root declaration as the source of truth for exports metadata', () => { const packageJson = JSON.parse(fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8')); - assert.equal(packageJson.types, 'nemo_flow_wasm.d.ts'); - assert.equal(packageJson.exports['.'].types, './nemo_flow_wasm.d.ts'); + assert.equal(packageJson.types, 'nemo_relay_wasm.d.ts'); + assert.equal(packageJson.exports['.'].types, './nemo_relay_wasm.d.ts'); }); test('WebAssembly package root declaration contains the documented public types and exports', () => { const indexJs = fs.readFileSync(path.join(pkgDir, 'index.js'), 'utf8'); - const wasmDts = fs.readFileSync(path.join(pkgDir, 'nemo_flow_wasm.d.ts'), 'utf8'); + const wasmDts = fs.readFileSync(path.join(pkgDir, 'nemo_relay_wasm.d.ts'), 'utf8'); for (const typeName of ['Json', 'JsonObject', 'OpenTelemetryConfig', 'OpenInferenceConfig']) { assert.match(wasmDts, new RegExp(String.raw`export (type|interface) ${typeName}\b`)); } - assert.match(indexJs, /nemo_flow_wasm\.js/); + assert.match(indexJs, /nemo_relay_wasm\.js/); for (const name of Object.keys(wasm)) { - assert.match(wasmDts, new RegExp(String.raw`\b${name}\b`), `expected ${name} in nemo_flow_wasm.d.ts`); + assert.match(wasmDts, new RegExp(String.raw`\b${name}\b`), `expected ${name} in nemo_relay_wasm.d.ts`); } }); diff --git a/crates/wasm/tests-js/observability_tests.mjs b/crates/wasm/tests-js/observability_tests.mjs index 94a9351c9..4644d6e58 100644 --- a/crates/wasm/tests-js/observability_tests.mjs +++ b/crates/wasm/tests-js/observability_tests.mjs @@ -17,16 +17,16 @@ test('WebAssembly observability wrappers expose helper defaults', () => { }); assert.deepEqual(observability.atifConfig(), { enabled: false, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', }); assert.deepEqual(observability.otlpConfig(), { enabled: false, transport: 'http_binary', headers: {}, resource_attributes: {}, - service_name: 'nemo-flow', + service_name: 'nemo-relay', timeout_millis: 3000, }); }); @@ -51,9 +51,9 @@ test('WebAssembly observability wrappers build component specs and validate file }, atif: { enabled: true, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', }, }, }); @@ -62,11 +62,8 @@ test('WebAssembly observability wrappers build component specs and validate file version: 1, components: [component], }); - assert.deepEqual( - report.diagnostics.map((diagnostic) => [diagnostic.component, diagnostic.field]).sort(), - [ - ['atif', 'enabled'], - ['atof', 'enabled'], - ], - ); + assert.deepEqual(report.diagnostics.map((diagnostic) => [diagnostic.component, diagnostic.field]).sort(), [ + ['atif', 'enabled'], + ['atof', 'enabled'], + ]); }); diff --git a/crates/wasm/tests-js/openinference_tests.mjs b/crates/wasm/tests-js/openinference_tests.mjs index dc698c64a..658ada54e 100644 --- a/crates/wasm/tests-js/openinference_tests.mjs +++ b/crates/wasm/tests-js/openinference_tests.mjs @@ -11,8 +11,8 @@ test('WebAssembly package exposes OpenInference config defaults', () => { const config = wasm.defaultOpenInferenceConfig(); assert.equal(config.transport, 'http_binary'); assert.equal(config.endpoint, undefined); - assert.equal(config.serviceName, 'nemo-flow'); - assert.equal(config.instrumentationScope, 'nemo-flow-openinference'); + assert.equal(config.serviceName, 'nemo-relay'); + assert.equal(config.instrumentationScope, 'nemo-relay-openinference'); assert.equal(config.timeoutMillis, 3000); assert.equal(config.headers instanceof Map, true); assert.equal(config.headers.size, 0); diff --git a/crates/wasm/tests-js/otel_tests.mjs b/crates/wasm/tests-js/otel_tests.mjs index 662ecd753..16a34b8bb 100644 --- a/crates/wasm/tests-js/otel_tests.mjs +++ b/crates/wasm/tests-js/otel_tests.mjs @@ -11,8 +11,8 @@ test('WebAssembly package exposes OpenTelemetry config defaults', () => { const config = wasm.defaultOpenTelemetryConfig(); assert.equal(config.transport, 'http_binary'); assert.equal(config.endpoint, undefined); - assert.equal(config.serviceName, 'nemo-flow'); - assert.equal(config.instrumentationScope, 'nemo-flow-otel'); + assert.equal(config.serviceName, 'nemo-relay'); + assert.equal(config.instrumentationScope, 'nemo-relay-otel'); assert.equal(config.timeoutMillis, 3000); assert.equal(config.headers instanceof Map, true); assert.equal(config.headers.size, 0); diff --git a/crates/wasm/tests/coverage/callable_tests.rs b/crates/wasm/tests/coverage/callable_tests.rs index 297574672..fddbd1f8e 100644 --- a/crates/wasm/tests/coverage/callable_tests.rs +++ b/crates/wasm/tests/coverage/callable_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for callable in the NeMo Flow WebAssembly crate. +//! Coverage tests for callable in the NeMo Relay WebAssembly crate. use super::*; -use nemo_flow::codec::request::AnnotatedLlmRequest; +use nemo_relay::codec::request::AnnotatedLlmRequest; use serde_json::json; use tokio_stream::StreamExt; use wasm_bindgen::JsCast; @@ -86,8 +86,8 @@ async fn native_async_wrapper_fallbacks_return_errors_or_defaults() { assert_eq!(finalizer(), Json::Null); let subscriber = wrap_js_event_subscriber(dummy_function()); - subscriber(&Event::Mark(nemo_flow::api::event::MarkEvent::new( - nemo_flow::api::event::BaseEvent::builder() + subscriber(&Event::Mark(nemo_relay::api::event::MarkEvent::new( + nemo_relay::api::event::BaseEvent::builder() .name("native-mark") .build(), None, diff --git a/crates/wasm/tests/coverage/types_tests.rs b/crates/wasm/tests/coverage/types_tests.rs index a47ed83c2..931e2d296 100644 --- a/crates/wasm/tests/coverage/types_tests.rs +++ b/crates/wasm/tests/coverage/types_tests.rs @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Coverage tests for types in the NeMo Flow WebAssembly crate. +//! Coverage tests for types in the NeMo Relay WebAssembly crate. use super::*; -use nemo_flow::api::event::{BaseEvent, EventCategory, MarkEvent, ScopeCategory, ScopeEvent}; +use nemo_relay::api::event::{BaseEvent, EventCategory, MarkEvent, ScopeCategory, ScopeEvent}; use serde_json::json; use uuid::Uuid; diff --git a/crates/wasm/tests/integration/adaptive_tests.rs b/crates/wasm/tests/integration/adaptive_tests.rs index 28928b1db..fa56a8d4d 100644 --- a/crates/wasm/tests/integration/adaptive_tests.rs +++ b/crates/wasm/tests/integration/adaptive_tests.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for adaptive in the NeMo Flow WebAssembly crate. +//! Integration tests for adaptive in the NeMo Relay WebAssembly crate. use serde_json::json; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::{ +use nemo_relay_wasm::api::{ clear_plugin_configuration, deregister_plugin, initialize_plugins, register_plugin, validate_plugin_config, }; diff --git a/crates/wasm/tests/integration/codec_tests.rs b/crates/wasm/tests/integration/codec_tests.rs index 11cceafef..aa7cf1f52 100644 --- a/crates/wasm/tests/integration/codec_tests.rs +++ b/crates/wasm/tests/integration/codec_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for codec in the NeMo Flow WebAssembly crate. +//! Integration tests for codec in the NeMo Relay WebAssembly crate. use wasm_bindgen_test::*; diff --git a/crates/wasm/tests/integration/context_tests.rs b/crates/wasm/tests/integration/context_tests.rs index 87aff55db..363d27057 100644 --- a/crates/wasm/tests/integration/context_tests.rs +++ b/crates/wasm/tests/integration/context_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for context in the NeMo Flow WebAssembly crate. +//! Integration tests for context in the NeMo Relay WebAssembly crate. use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; -use nemo_flow_wasm::types::*; +use nemo_relay_wasm::api::*; +use nemo_relay_wasm::types::*; fn parent_handle(handle: Option) -> JsValue { handle.map(JsValue::from).unwrap_or(JsValue::NULL) @@ -21,7 +21,7 @@ fn push_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::push_scope( + nemo_relay_wasm::api::push_scope( name, scope_type, parent_handle(handle), @@ -34,7 +34,7 @@ fn push_scope( } fn pop_scope(handle: &ScopeHandle) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, JsValue::NULL, None) + nemo_relay_wasm::api::pop_scope(handle, JsValue::NULL, None) } // =========================================================================== diff --git a/crates/wasm/tests/integration/deregister_tests.rs b/crates/wasm/tests/integration/deregister_tests.rs index 9f2dfd436..9e69b3588 100644 --- a/crates/wasm/tests/integration/deregister_tests.rs +++ b/crates/wasm/tests/integration/deregister_tests.rs @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for deregister in the NeMo Flow WebAssembly crate. +//! Integration tests for deregister in the NeMo Relay WebAssembly crate. use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; +use nemo_relay_wasm::api::*; // =========================================================================== // Deregister nonexistent diff --git a/crates/wasm/tests/integration/llm_tests.rs b/crates/wasm/tests/integration/llm_tests.rs index bfbfb7168..ffbc9b17c 100644 --- a/crates/wasm/tests/integration/llm_tests.rs +++ b/crates/wasm/tests/integration/llm_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for llm in the NeMo Flow WebAssembly crate. +//! Integration tests for llm in the NeMo Relay WebAssembly crate. use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; -use nemo_flow_wasm::types::*; +use nemo_relay_wasm::api::*; +use nemo_relay_wasm::types::*; // --------------------------------------------------------------------------- // Helpers @@ -36,7 +36,7 @@ fn push_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::push_scope( + nemo_relay_wasm::api::push_scope( name, scope_type, parent_handle(handle), @@ -49,7 +49,7 @@ fn push_scope( } fn pop_scope(handle: &ScopeHandle) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, JsValue::NULL, None) + nemo_relay_wasm::api::pop_scope(handle, JsValue::NULL, None) } fn llm_call( @@ -61,7 +61,7 @@ fn llm_call( metadata: JsValue, model_name: Option, ) -> Result { - nemo_flow_wasm::api::llm_call( + nemo_relay_wasm::api::llm_call( name, request, parent_handle(handle), @@ -79,7 +79,7 @@ fn llm_call_end( data: JsValue, metadata: JsValue, ) -> Result<(), JsValue> { - nemo_flow_wasm::api::llm_call_end(handle, response, data, metadata, None) + nemo_relay_wasm::api::llm_call_end(handle, response, data, metadata, None) } #[allow(clippy::too_many_arguments)] @@ -96,7 +96,7 @@ async fn llm_call_execute( codec_encode: Option, response_codec_decode: Option, ) -> Result { - nemo_flow_wasm::api::llm_call_execute( + nemo_relay_wasm::api::llm_call_execute( name, request, func, diff --git a/crates/wasm/tests/integration/scope_local_tests.rs b/crates/wasm/tests/integration/scope_local_tests.rs index cee9d7b4e..3d1d5d2c9 100644 --- a/crates/wasm/tests/integration/scope_local_tests.rs +++ b/crates/wasm/tests/integration/scope_local_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for scope local in the NeMo Flow WebAssembly crate. +//! Integration tests for scope local in the NeMo Relay WebAssembly crate. use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; -use nemo_flow_wasm::types::*; +use nemo_relay_wasm::api::*; +use nemo_relay_wasm::types::*; // --------------------------------------------------------------------------- // Helpers @@ -36,7 +36,7 @@ fn push_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::push_scope( + nemo_relay_wasm::api::push_scope( name, scope_type, parent_handle(handle), @@ -49,7 +49,7 @@ fn push_scope( } fn pop_scope(handle: &ScopeHandle) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, JsValue::NULL, None) + nemo_relay_wasm::api::pop_scope(handle, JsValue::NULL, None) } async fn tool_call_execute( @@ -61,7 +61,7 @@ async fn tool_call_execute( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::tool_call_execute( + nemo_relay_wasm::api::tool_call_execute( name, args, func, diff --git a/crates/wasm/tests/integration/scope_tests.rs b/crates/wasm/tests/integration/scope_tests.rs index a35883f82..802b2ff08 100644 --- a/crates/wasm/tests/integration/scope_tests.rs +++ b/crates/wasm/tests/integration/scope_tests.rs @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for scope in the NeMo Flow WebAssembly crate. +//! Integration tests for scope in the NeMo Relay WebAssembly crate. use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; -use nemo_flow_wasm::types::*; +use nemo_relay_wasm::api::*; +use nemo_relay_wasm::types::*; // --------------------------------------------------------------------------- // Helpers @@ -33,7 +33,7 @@ fn push_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::push_scope( + nemo_relay_wasm::api::push_scope( name, scope_type, parent_handle(handle), @@ -54,7 +54,7 @@ fn with_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::with_scope( + nemo_relay_wasm::api::with_scope( name, scope_type, callback, @@ -67,11 +67,11 @@ fn with_scope( } fn pop_scope(handle: &ScopeHandle) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, JsValue::NULL, None) + nemo_relay_wasm::api::pop_scope(handle, JsValue::NULL, None) } fn pop_scope_with_output(handle: &ScopeHandle, output: JsValue) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, output, None) + nemo_relay_wasm::api::pop_scope(handle, output, None) } fn event( @@ -80,7 +80,7 @@ fn event( data: JsValue, metadata: JsValue, ) -> Result<(), JsValue> { - nemo_flow_wasm::api::event(name, parent_handle(handle), data, metadata, None) + nemo_relay_wasm::api::event(name, parent_handle(handle), data, metadata, None) } // =========================================================================== diff --git a/crates/wasm/tests/integration/tools_tests.rs b/crates/wasm/tests/integration/tools_tests.rs index add4bc7e9..9befbd22d 100644 --- a/crates/wasm/tests/integration/tools_tests.rs +++ b/crates/wasm/tests/integration/tools_tests.rs @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Integration tests for tools in the NeMo Flow WebAssembly crate. +//! Integration tests for tools in the NeMo Relay WebAssembly crate. use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; -use nemo_flow_wasm::api::*; -use nemo_flow_wasm::types::*; +use nemo_relay_wasm::api::*; +use nemo_relay_wasm::types::*; // --------------------------------------------------------------------------- // Helpers @@ -36,7 +36,7 @@ fn push_scope( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::push_scope( + nemo_relay_wasm::api::push_scope( name, scope_type, parent_handle(handle), @@ -49,7 +49,7 @@ fn push_scope( } fn pop_scope(handle: &ScopeHandle) -> Result<(), JsValue> { - nemo_flow_wasm::api::pop_scope(handle, JsValue::NULL, None) + nemo_relay_wasm::api::pop_scope(handle, JsValue::NULL, None) } fn tool_call( @@ -61,7 +61,7 @@ fn tool_call( metadata: JsValue, tool_call_id: Option, ) -> Result { - nemo_flow_wasm::api::tool_call( + nemo_relay_wasm::api::tool_call( name, args, parent_handle(handle), @@ -79,7 +79,7 @@ fn tool_call_end( data: JsValue, metadata: JsValue, ) -> Result<(), JsValue> { - nemo_flow_wasm::api::tool_call_end(handle, result, data, metadata, None) + nemo_relay_wasm::api::tool_call_end(handle, result, data, metadata, None) } async fn tool_call_execute( @@ -91,7 +91,7 @@ async fn tool_call_execute( data: JsValue, metadata: JsValue, ) -> Result { - nemo_flow_wasm::api::tool_call_execute( + nemo_relay_wasm::api::tool_call_execute( name, args, func, diff --git a/crates/wasm/tests/unit/api_tests.rs b/crates/wasm/tests/unit/api_tests.rs index a3343e894..23639fc93 100644 --- a/crates/wasm/tests/unit/api_tests.rs +++ b/crates/wasm/tests/unit/api_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for api in the NeMo Flow WebAssembly crate. +//! Unit tests for api in the NeMo Relay WebAssembly crate. use super::*; use std::sync::{Mutex, OnceLock}; @@ -21,10 +21,10 @@ fn test_mutex() -> &'static Mutex<()> { fn wasm_config_defaults_match_expected_values() { let otel_config = WasmOpenTelemetryConfig::default(); assert_eq!(otel_config.transport.as_deref(), Some("http_binary")); - assert_eq!(otel_config.service_name.as_deref(), Some("nemo-flow")); + assert_eq!(otel_config.service_name.as_deref(), Some("nemo-relay")); assert_eq!( otel_config.instrumentation_scope.as_deref(), - Some("nemo-flow-otel") + Some("nemo-relay-otel") ); assert_eq!(otel_config.timeout_millis, Some(3_000)); @@ -35,11 +35,11 @@ fn wasm_config_defaults_match_expected_values() { ); assert_eq!( openinference_config.service_name.as_deref(), - Some("nemo-flow") + Some("nemo-relay") ); assert_eq!( openinference_config.instrumentation_scope.as_deref(), - Some("nemo-flow-openinference") + Some("nemo-relay-openinference") ); assert_eq!(openinference_config.timeout_millis, Some(3_000)); } diff --git a/crates/wasm/tests/unit/convert_tests.rs b/crates/wasm/tests/unit/convert_tests.rs index 93ea572d2..eb8e6591d 100644 --- a/crates/wasm/tests/unit/convert_tests.rs +++ b/crates/wasm/tests/unit/convert_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for convert in the NeMo Flow WebAssembly crate. +//! Unit tests for convert in the NeMo Relay WebAssembly crate. use super::*; diff --git a/crates/wasm/tests/unit/stream_tests.rs b/crates/wasm/tests/unit/stream_tests.rs index c0b2bcfa5..e13563f9f 100644 --- a/crates/wasm/tests/unit/stream_tests.rs +++ b/crates/wasm/tests/unit/stream_tests.rs @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! Unit tests for stream in the NeMo Flow WebAssembly crate. +//! Unit tests for stream in the NeMo Relay WebAssembly crate. #[cfg(target_arch = "wasm32")] fn block_on(future: F) -> F::Output { @@ -43,7 +43,7 @@ fn next_returns_js_error_for_stream_errors() { block_on(async { let (tx, rx) = tokio::sync::mpsc::channel(1); - tx.send(Err(nemo_flow::error::FlowError::Internal( + tx.send(Err(nemo_relay::error::FlowError::Internal( "stream failed".to_string(), ))) .await diff --git a/crates/wasm/wrappers/esm/adaptive.d.ts b/crates/wasm/wrappers/esm/adaptive.d.ts index 8e6cb3315..770c81a0b 100644 --- a/crates/wasm/wrappers/esm/adaptive.d.ts +++ b/crates/wasm/wrappers/esm/adaptive.d.ts @@ -103,7 +103,7 @@ export declare function inMemoryBackend(): BackendSpec; * @param keyPrefix - Prefix applied to Redis keys. * @returns An adaptive backend spec using Redis storage. * @remarks The default key prefix namespaces runtime records under - * `nemo_flow:` unless a different prefix is supplied. + * `nemo_relay:` unless a different prefix is supplied. */ export declare function redisBackend(url: string, keyPrefix?: string): BackendSpec; /** diff --git a/crates/wasm/wrappers/esm/adaptive.js b/crates/wasm/wrappers/esm/adaptive.js index 3705be731..d6ce3071d 100644 --- a/crates/wasm/wrappers/esm/adaptive.js +++ b/crates/wasm/wrappers/esm/adaptive.js @@ -44,12 +44,12 @@ export function inMemoryBackend() { * should be shared or persisted through Redis. * * @param {string} url - Redis connection URL for the backend. - * @param {string} [keyPrefix='nemo_flow:'] - Prefix applied to Redis keys. + * @param {string} [keyPrefix='nemo_relay:'] - Prefix applied to Redis keys. * @returns {object} An adaptive backend spec using Redis storage. * @remarks The default key prefix namespaces runtime records under - * `nemo_flow:` unless a different prefix is supplied. + * `nemo_relay:` unless a different prefix is supplied. */ -export function redisBackend(url, keyPrefix = 'nemo_flow:') { +export function redisBackend(url, keyPrefix = 'nemo_relay:') { return { kind: 'redis', config: { diff --git a/crates/wasm/wrappers/esm/index.js b/crates/wasm/wrappers/esm/index.js index c532e06c1..ea932fb1c 100644 --- a/crates/wasm/wrappers/esm/index.js +++ b/crates/wasm/wrappers/esm/index.js @@ -94,4 +94,4 @@ export { toolRequestIntercepts, validatePluginConfig, withScope, -} from './pkg/nemo_flow_wasm.js'; +} from './pkg/nemo_relay_wasm.js'; diff --git a/crates/wasm/wrappers/esm/observability.js b/crates/wasm/wrappers/esm/observability.js index e1b56cd4c..642db627c 100644 --- a/crates/wasm/wrappers/esm/observability.js +++ b/crates/wasm/wrappers/esm/observability.js @@ -39,9 +39,9 @@ export function atofConfig(config = {}) { export function atifConfig(config = {}) { return { enabled: false, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', ...config, }; } @@ -58,7 +58,7 @@ export function otlpConfig(config = {}) { transport: 'http_binary', headers: {}, resource_attributes: {}, - service_name: 'nemo-flow', + service_name: 'nemo-relay', timeout_millis: 3000, ...config, }; diff --git a/crates/wasm/wrappers/esm/typed.d.ts b/crates/wasm/wrappers/esm/typed.d.ts index d49755edb..fbb5acc87 100644 --- a/crates/wasm/wrappers/esm/typed.d.ts +++ b/crates/wasm/wrappers/esm/typed.d.ts @@ -2,14 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Typed wrappers for NeMo Flow WebAssembly execute APIs. + * Typed wrappers for NeMo Relay WebAssembly execute APIs. * * Provides generic typed versions of `toolCallExecute`, `llmCallExecute`, * and `llmStreamCallExecute` that use explicit `Codec` objects to * serialize/deserialize at the API boundary. */ -import { ScopeHandle, LlmStream } from './nemo_flow_wasm.js'; +import { ScopeHandle, LlmStream } from './nemo_relay_wasm.js'; /** One JSON scalar value accepted by the typed wrapper APIs. */ export type JsonPrimitive = string | number | boolean | null; diff --git a/crates/wasm/wrappers/esm/typed.js b/crates/wasm/wrappers/esm/typed.js index 95f8351ce..f47dee0e3 100644 --- a/crates/wasm/wrappers/esm/typed.js +++ b/crates/wasm/wrappers/esm/typed.js @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Typed wrappers for NeMo Flow WebAssembly execute APIs. + * Typed wrappers for NeMo Relay WebAssembly execute APIs. * * Provides generic typed versions of `toolCallExecute`, `llmCallExecute`, * and `llmStreamCallExecute` that use explicit `Codec` objects to diff --git a/crates/wasm/wrappers/nodejs/adaptive.js b/crates/wasm/wrappers/nodejs/adaptive.js index f4fcfb7c4..1d1ddf52b 100644 --- a/crates/wasm/wrappers/nodejs/adaptive.js +++ b/crates/wasm/wrappers/nodejs/adaptive.js @@ -46,12 +46,12 @@ function inMemoryBackend() { * should be shared or persisted through Redis. * * @param {string} url - Redis connection URL for the backend. - * @param {string} [keyPrefix='nemo_flow:'] - Prefix applied to Redis keys. + * @param {string} [keyPrefix='nemo_relay:'] - Prefix applied to Redis keys. * @returns {object} An adaptive backend spec using Redis storage. * @remarks The default key prefix namespaces runtime records under - * `nemo_flow:` unless a different prefix is supplied. + * `nemo_relay:` unless a different prefix is supplied. */ -function redisBackend(url, keyPrefix = 'nemo_flow:') { +function redisBackend(url, keyPrefix = 'nemo_relay:') { return { kind: 'redis', config: { diff --git a/crates/wasm/wrappers/nodejs/index.js b/crates/wasm/wrappers/nodejs/index.js index 069e06b22..7091e87d4 100644 --- a/crates/wasm/wrappers/nodejs/index.js +++ b/crates/wasm/wrappers/nodejs/index.js @@ -3,6 +3,6 @@ 'use strict'; -const { PluginContext: _PluginContext, ...publicApi } = require('./nemo_flow_wasm.js'); +const { PluginContext: _PluginContext, ...publicApi } = require('./nemo_relay_wasm.js'); module.exports = publicApi; diff --git a/crates/wasm/wrappers/nodejs/observability.js b/crates/wasm/wrappers/nodejs/observability.js index 06a53811e..7ce69c935 100644 --- a/crates/wasm/wrappers/nodejs/observability.js +++ b/crates/wasm/wrappers/nodejs/observability.js @@ -41,9 +41,9 @@ function atofConfig(config = {}) { function atifConfig(config = {}) { return { enabled: false, - agent_name: 'NeMo Flow', + agent_name: 'NeMo Relay', model_name: 'unknown', - filename_template: 'nemo-flow-atif-{session_id}.json', + filename_template: 'nemo-relay-atif-{session_id}.json', ...config, }; } @@ -60,7 +60,7 @@ function otlpConfig(config = {}) { transport: 'http_binary', headers: {}, resource_attributes: {}, - service_name: 'nemo-flow', + service_name: 'nemo-relay', timeout_millis: 3000, ...config, }; diff --git a/crates/wasm/wrappers/nodejs/plugin.js b/crates/wasm/wrappers/nodejs/plugin.js index 48e0bb12e..0f5e54f0d 100644 --- a/crates/wasm/wrappers/nodejs/plugin.js +++ b/crates/wasm/wrappers/nodejs/plugin.js @@ -11,7 +11,7 @@ const { clearPluginConfiguration, activePluginReport, listPluginKinds, -} = require('./nemo_flow_wasm.js'); +} = require('./nemo_relay_wasm.js'); /** * Create an empty plugin configuration. diff --git a/crates/wasm/wrappers/nodejs/typed.js b/crates/wasm/wrappers/nodejs/typed.js index 0b07f7216..d194807a7 100644 --- a/crates/wasm/wrappers/nodejs/typed.js +++ b/crates/wasm/wrappers/nodejs/typed.js @@ -3,7 +3,7 @@ 'use strict'; -const { toolCallExecute, llmCallExecute, llmStreamCallExecute } = require('./nemo_flow_wasm.js'); +const { toolCallExecute, llmCallExecute, llmStreamCallExecute } = require('./nemo_relay_wasm.js'); /** * A passthrough codec that performs no conversion. diff --git a/docs/about/architecture.md b/docs/about/architecture.md index ff2e1f17d..e4c3b1591 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Architecture -This page explains how NeMo Flow connects scopes, middleware, plugins, events, +This page explains how NeMo Relay connects scopes, middleware, plugins, events, subscribers, and exporters. ## Architecture Diagram @@ -81,7 +81,7 @@ Adaptive appears here as a built-in plugin component rather than a separate runt ## Runtime Model -NeMo Flow combines a small number of runtime pieces into one shared execution model: +NeMo Relay combines a small number of runtime pieces into one shared execution model: - The **scope stack** answers where work belongs - The **middleware registries** answer what should happen around that work @@ -163,7 +163,7 @@ For the expanded request-to-response runtime path, including streaming and subsc ## Runtime Layers -From bottom to top, NeMo Flow is organized as: +From bottom to top, NeMo Relay is organized as: 1. The Rust core runtime 2. The plugin and adaptive layer @@ -175,7 +175,7 @@ The details of a binding can vary, but the conceptual model stays the same acros ## Design Goal -NeMo Flow is designed so that application developers, framework integrators, plugin authors, and observability consumers all reason about the same runtime semantics. One conceptual model should remain stable even when the binding or integration style changes. +NeMo Relay is designed so that application developers, framework integrators, plugin authors, and observability consumers all reason about the same runtime semantics. One conceptual model should remain stable even when the binding or integration style changes. ## Related Concepts diff --git a/docs/about/concepts/events.md b/docs/about/concepts/events.md index fc6ee2959..d0bdffa45 100644 --- a/docs/about/concepts/events.md +++ b/docs/about/concepts/events.md @@ -10,7 +10,7 @@ and subscribers. ## What Events Represent -Events are the runtime record of what happened. NeMo Flow uses Agent +Events are the runtime record of what happened. NeMo Relay uses Agent Trajectory Observability Format (ATOF) `0.1` as the canonical event format for scopes, managed execution helpers, manual lifecycle APIs, subscribers, and exporters. @@ -75,7 +75,7 @@ ATOF uses one `data` field. For scope events, `data` is the semantic input on ### Category Profiles -Category-specific fields live under `category_profile`. NeMo Flow uses +Category-specific fields live under `category_profile`. NeMo Relay uses `model_name` for LLM events, `tool_call_id` for tool events, and `subtype` for custom-category events. LLM codec annotations, when present, are serialized under `category_profile.annotated_request` on LLM start events and diff --git a/docs/about/concepts/framework-integrations.md b/docs/about/concepts/framework-integrations.md index 371e65c6e..df5ece503 100644 --- a/docs/about/concepts/framework-integrations.md +++ b/docs/about/concepts/framework-integrations.md @@ -6,11 +6,11 @@ SPDX-License-Identifier: Apache-2.0 # Framework Integrations This page explains how framework integrations should attach existing application work to -NeMo Flow runtime semantics. +NeMo Relay runtime semantics. ## Why Framework Integrations Are Different -Application code can usually call the managed NeMo Flow helpers directly. +Application code can usually call the managed NeMo Relay helpers directly. Framework integrations often cannot. A framework may already own: @@ -26,7 +26,7 @@ available rather than assuming direct runtime ownership. ## Preferred Integration Order -When integrating NeMo Flow into an existing framework, prefer these choices in +When integrating NeMo Relay into an existing framework, prefer these choices in order: 1. Execution wrappers through managed execute helpers @@ -43,7 +43,7 @@ real callback or handler. ### Managed Execute Helpers Use the managed execute helpers when the framework exposes a stable callable -boundary that NeMo Flow can wrap. +boundary that NeMo Relay can wrap. ### Why This Is Preferred @@ -55,14 +55,14 @@ This is the best integration shape because it preserves: - The cleanest wrapper point for retries, routing, and timing Execution wrappers are also the natural place to align framework semantics with -NeMo Flow execution intercepts. +NeMo Relay execution intercepts. ## Fallback: Explicit API Calls Use explicit API calls when the framework owns part of the invocation lifecycle -and cannot hand NeMo Flow a stable callback to wrap. Explicit calls let the +and cannot hand NeMo Relay a stable callback to wrap. Explicit calls let the framework keep its own scheduler, retry loop, callback signature, or provider -client while still using selected NeMo Flow runtime behavior. +client while still using selected NeMo Relay runtime behavior. ### What You Lose From Managed Execution Wrappers @@ -81,7 +81,7 @@ execution wrappers whenever the framework can expose the real callback. ### Explicit Start, End, and Mark Emission Use explicit start and end emission when the framework gives reliable lifecycle -hooks but does not let NeMo Flow wrap the real invocation. +hooks but does not let NeMo Relay wrap the real invocation. 1. Call the explicit start API as early as the framework can identify the work. 2. Retain the returned handle. @@ -97,14 +97,14 @@ and end calls correctly. Use standalone conditional-execution helpers when the framework only needs an allow-or-block decision before continuing its own invocation path. -This is the preferred explicit API when the framework can ask NeMo Flow for a +This is the preferred explicit API when the framework can ask NeMo Relay for a policy decision but must still execute the real tool or provider call itself. The helper returns the guardrail decision; it does not emit a full managed lifecycle span by itself. ### Request Intercepts -Use standalone request-intercept helpers when the framework needs NeMo Flow to +Use standalone request-intercept helpers when the framework needs NeMo Relay to rewrite the request before the framework continues execution on its own. This is the preferred explicit API when the framework owns execution but can @@ -128,7 +128,7 @@ instrumentation. ## Choosing the Right Integration Boundary -Use these rules to decide where NeMo Flow should wrap framework behavior. +Use these rules to decide where NeMo Relay should wrap framework behavior. - If you can wrap the real callback, use managed execute helpers. - If you cannot wrap the callback but you do have reliable start and end hooks, diff --git a/docs/about/concepts/index.md b/docs/about/concepts/index.md index 3378eb0b1..cc7d87858 100644 --- a/docs/about/concepts/index.md +++ b/docs/about/concepts/index.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Concepts -Use these pages to understand the NeMo Flow runtime model before applying it in a use-case workflow. +Use these pages to understand the NeMo Relay runtime model before applying it in a use-case workflow. ::::{grid} 1 1 2 2 :gutter: 3 diff --git a/docs/about/concepts/middleware.md b/docs/about/concepts/middleware.md index 741b1b276..755a5f297 100644 --- a/docs/about/concepts/middleware.md +++ b/docs/about/concepts/middleware.md @@ -10,7 +10,7 @@ This page explains the runtime behavior that runs around managed tool and LLM ca ## What Middleware Is Middleware is the runtime behavior that runs around tool and LLM execution. -NeMo Flow uses middleware to control, transform, or observe work at specific +NeMo Relay uses middleware to control, transform, or observe work at specific lifecycle points. Middleware is organized by lifecycle meaning rather than as one undifferentiated @@ -42,7 +42,7 @@ everything in application code. ## Middleware Families -NeMo Flow has two major middleware families: +NeMo Relay has two major middleware families: - **Intercepts** change the real execution path - **Guardrails** block work or rewrite emitted observability payloads @@ -108,14 +108,14 @@ arguments passed to the callback or the real value returned to the caller. ## Managed Execution Order -For managed execution, NeMo Flow applies middleware and emits lifecycle events +For managed execution, NeMo Relay applies middleware and emits lifecycle events in this order: ```{mermaid} sequenceDiagram autonumber actor Caller as Application / Framework - participant Runtime as NeMo Flow Runtime + participant Runtime as NeMo Relay Runtime participant Cond as Conditional Guardrails participant Req as Request Intercepts participant Exec as Execution Intercepts diff --git a/docs/about/concepts/plugins.md b/docs/about/concepts/plugins.md index 7eb0e6e09..b9110db12 100644 --- a/docs/about/concepts/plugins.md +++ b/docs/about/concepts/plugins.md @@ -9,7 +9,7 @@ This page explains how plugins package reusable runtime behavior behind configur ## Why Plugins Exist -Plugins let NeMo Flow install reusable runtime behavior from configuration +Plugins let NeMo Relay install reusable runtime behavior from configuration instead of requiring every application or framework integration to register the same middleware and subscribers by hand. diff --git a/docs/about/concepts/scopes.md b/docs/about/concepts/scopes.md index e76c24d72..7496fc39b 100644 --- a/docs/about/concepts/scopes.md +++ b/docs/about/concepts/scopes.md @@ -10,7 +10,7 @@ isolation. ## Why Scopes Exist -Scopes are the ownership backbone of NeMo Flow. Every tool call, LLM call, and +Scopes are the ownership backbone of NeMo Relay. Every tool call, LLM call, and mark event attaches to a scope hierarchy. That hierarchy lets the runtime: @@ -48,7 +48,7 @@ That hierarchy determines: ## Scope Types -NeMo Flow includes standard scope types for common runtime semantics, including: +NeMo Relay includes standard scope types for common runtime semantics, including: - `Agent` - `Function` diff --git a/docs/about/concepts/subscribers.md b/docs/about/concepts/subscribers.md index 69a6b8107..4f08f7dc0 100644 --- a/docs/about/concepts/subscribers.md +++ b/docs/about/concepts/subscribers.md @@ -10,7 +10,7 @@ execution. ## What Subscribers Are -Subscribers are consumers of the NeMo Flow event stream. They receive emitted +Subscribers are consumers of the NeMo Relay event stream. They receive emitted lifecycle events and use them for observation, forwarding, export, or analysis. ## How Subscribers Relate to Events @@ -69,9 +69,9 @@ attributes. Python subscribers can call `event.to_dict()` or `event.to_json()` from the callback while still using the normal subscriber registration API. This pattern is useful when an agent runtime, framework adapter, or plugin host -already has its own lifecycle hooks but wants NeMo Flow to be the shared -telemetry representation. The host integration maps those hooks into NeMo Flow -scopes, LLM calls, tool calls, or marks. NeMo Flow emits the canonical ATOF event +already has its own lifecycle hooks but wants NeMo Relay to be the shared +telemetry representation. The host integration maps those hooks into NeMo Relay +scopes, LLM calls, tool calls, or marks. NeMo Relay emits the canonical ATOF event stream, and each subscriber chooses whether to consume the native event object, the canonical JSON helper, or an exporter-specific translation. @@ -79,7 +79,7 @@ the canonical JSON helper, or an exporter-specific translation. flowchart Host[Host Integration] - subgraph NeMoFlow[NeMo Flow] + subgraph NeMoFlow[NeMo Relay] direction TB Binding[Binding API] Core[Rust Core Runtime] diff --git a/docs/about/ecosystem.md b/docs/about/ecosystem.md index bbaea3f51..81b390c94 100644 --- a/docs/about/ecosystem.md +++ b/docs/about/ecosystem.md @@ -5,36 +5,36 @@ SPDX-License-Identifier: Apache-2.0 # Ecosystem -NeMo Flow is the agent execution runtime layer in the NVIDIA NeMo ecosystem. It +NeMo Relay is the agent execution runtime layer in the NVIDIA NeMo ecosystem. It does not replace an agent framework, model provider, guardrail authoring system, or deployment platform. Instead, it gives those systems one shared way to model execution scopes, lifecycle events, middleware, plugins, adaptive behavior, and observability around tool and LLM calls. -Use this page to understand where NeMo Flow fits: +Use this page to understand where NeMo Relay fits: - Inside the NVIDIA NeMo software stack - Inside agent frameworks, harnesses, and provider adapters - Across the Rust, Python, Node.js, Go, WebAssembly, and C FFI surfaces in this repository -## How NeMo Flow Fits In The NVIDIA NeMo Ecosystem +## How NeMo Relay Fits In The NVIDIA NeMo Ecosystem The NVIDIA NeMo ecosystem spans model development, agent construction, -guardrailing, inference, optimization, and runtime operations. NeMo Flow has a +guardrailing, inference, optimization, and runtime operations. NeMo Relay has a narrower responsibility: it is the portable execution substrate that agent systems can call when actual work crosses a scope, tool, or model boundary. -| Layer | Typical Responsibility | NeMo Flow Relationship | +| Layer | Typical Responsibility | NeMo Relay Relationship | |---|---|---| -| NeMo model, inference, and deployment components | Provide or serve the models an agent uses. | NeMo Flow records and controls LLM execution boundaries, but it does not train, host, or route model inference by itself. | -| NeMo Agent Toolkit and agent application frameworks | Build, run, profile, and optimize agent workflows across tools, data sources, and framework choices. | NeMo Flow can sit below these systems as the shared runtime contract for scopes, middleware, lifecycle events, subscribers, and plugins. | -| NeMo Guardrails and policy systems | Define safety, control, and compliance behavior for LLM applications. | NeMo Flow can host runtime guardrails and intercepts around managed tool and LLM calls, while higher-level guardrail systems can still own policy authoring and orchestration. | -| Application harnesses and workflow code | Decide the agent pattern, planner, memory, retries, scheduling, and user-facing behavior. | NeMo Flow instruments the execution boundaries that the harness already owns. | -| Observability and evaluation backends | Store traces, trajectories, metrics, and analysis data. | NeMo Flow emits lifecycle events and exports them to in-process subscribers, Agent Trajectory Observability Format (ATOF), Agent Trajectory Interchange Format (ATIF), OpenTelemetry, OpenInference-compatible traces, or other backends. | - -In practical terms, NeMo Flow answers a different question than higher-level -agent products. A framework asks, "What should the agent do next?" NeMo Flow +| NeMo model, inference, and deployment components | Provide or serve the models an agent uses. | NeMo Relay records and controls LLM execution boundaries, but it does not train, host, or route model inference by itself. | +| NeMo Agent Toolkit and agent application frameworks | Build, run, profile, and optimize agent workflows across tools, data sources, and framework choices. | NeMo Relay can sit below these systems as the shared runtime contract for scopes, middleware, lifecycle events, subscribers, and plugins. | +| NeMo Guardrails and policy systems | Define safety, control, and compliance behavior for LLM applications. | NeMo Relay can host runtime guardrails and intercepts around managed tool and LLM calls, while higher-level guardrail systems can still own policy authoring and orchestration. | +| Application harnesses and workflow code | Decide the agent pattern, planner, memory, retries, scheduling, and user-facing behavior. | NeMo Relay instruments the execution boundaries that the harness already owns. | +| Observability and evaluation backends | Store traces, trajectories, metrics, and analysis data. | NeMo Relay emits lifecycle events and exports them to in-process subscribers, Agent Trajectory Observability Format (ATOF), Agent Trajectory Interchange Format (ATIF), OpenTelemetry, OpenInference-compatible traces, or other backends. | + +In practical terms, NeMo Relay answers a different question than higher-level +agent products. A framework asks, "What should the agent do next?" NeMo Relay asks, "When the agent does work, which scope owns it, which middleware applies, what events are emitted, and which subscribers can consume the result?" @@ -43,7 +43,7 @@ flowchart TB User[User / Application] Framework[Agent Framework or Harness] Toolkit[NeMo Agent Toolkit / Framework Integrations] - Flow[NeMo Flow Runtime] + Flow[NeMo Relay Runtime] Provider[Model, Tool, or Provider SDK] Obs[Subscribers and Observability Backends] Policy[Guardrails, Intercepts, and Plugins] @@ -64,19 +64,19 @@ flowchart TB class Policy green-lightest; ``` -The dotted path matters. An application or custom harness can call NeMo Flow +The dotted path matters. An application or custom harness can call NeMo Relay directly without adopting a higher-level framework. A framework integration can -also call NeMo Flow on behalf of application code when the framework owns the +also call NeMo Relay on behalf of application code when the framework owns the tool or provider boundary. -## How NeMo Flow Fits Agent Frameworks And Harnesses +## How NeMo Relay Fits Agent Frameworks And Harnesses The agent framework and harness landscape is intentionally mixed. A team might use NeMo Agent Toolkit, LangChain, LangGraph, an internal orchestration layer, a -provider SDK, or direct application code. NeMo Flow is designed to meet those +provider SDK, or direct application code. NeMo Relay is designed to meet those systems at stable execution boundaries instead of requiring one framework shape. -| Integration Point | Use NeMo Flow For | Keep In The Framework Or Harness | +| Integration Point | Use NeMo Relay For | Keep In The Framework Or Harness | |---|---|---| | Request, run, workflow, or agent lifecycle hooks | Create scopes, emit scope start and end events, and isolate concurrent work. | Scheduling, routing, retry policy, planner choice, memory, and user session state. | | Tool invocation callbacks | Run managed tool execution, apply tool middleware, emit tool lifecycle events, and preserve parent scope context. | Tool discovery, tool schema presentation, framework-specific callback signatures, and application-visible result handling. | @@ -85,17 +85,17 @@ systems at stable execution boundaries instead of requiring one framework shape. | Cross-cutting behavior | Package middleware, subscribers, adaptive behavior, and reusable policy as plugins. | Framework configuration, agent definitions, deployment topology, and business logic. | Prefer a managed execution wrapper when a framework exposes a stable callback -that NeMo Flow can own. Use explicit lifecycle calls or standalone helpers when +that NeMo Relay can own. Use explicit lifecycle calls or standalone helpers when the framework owns the callback internally but exposes reliable start, finish, or request transformation hooks. -This lets NeMo Flow provide consistent runtime semantics without forcing a +This lets NeMo Relay provide consistent runtime semantics without forcing a framework migration: - Applications keep their existing agent orchestration model - Framework adapters preserve public behavior and callback signatures - Non-serializable provider objects stay in framework-owned storage -- NeMo Flow receives JSON-compatible payloads for middleware and events +- NeMo Relay receives JSON-compatible payloads for middleware and events - Subscribers see a consistent scope, tool, and LLM event stream across integrations ## Related Topics diff --git a/docs/about/release-notes/highlights.md b/docs/about/release-notes/highlights.md index 119f4f8c4..584fbdd3c 100644 --- a/docs/about/release-notes/highlights.md +++ b/docs/about/release-notes/highlights.md @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 This page summarizes the notable capabilities in the current release documentation set. -## NeMo Flow 0.3 +## NeMo Relay 0.3 -This release of NeMo Flow release introduces several new components and capabilities. -The complete changelog and release notes can be viewed on [GitHub](https://github.com/NVIDIA/NeMo-Flow/releases). +This release of NeMo Relay release introduces several new components and capabilities. +The complete changelog and release notes can be viewed on [GitHub](https://github.com/NVIDIA/NeMo-Relay/releases). diff --git a/docs/about/release-notes/known-issues.md b/docs/about/release-notes/known-issues.md index 0ccc6c8be..961e0b94b 100644 --- a/docs/about/release-notes/known-issues.md +++ b/docs/about/release-notes/known-issues.md @@ -7,17 +7,17 @@ SPDX-License-Identifier: Apache-2.0 This page lists current limitations and support notes for the release documentation set. -## NeMo Flow 0.3 +## NeMo Relay 0.3 -These notes apply to the NeMo Flow 0.3 Release. +These notes apply to the NeMo Relay 0.3 Release. - Go, WebAssembly, and the raw C FFI surface are experimental and source-first. - Generated API pages cover Rust, Python, and Node.js. Experimental bindings do not yet have the same generated documentation depth. -- The NeMo Flow CLI is experimental. Coding agent observability support varies due to capabilities of hooks. Any encountered problems should be filed as bugs. +- The NeMo Relay CLI is experimental. Coding agent observability support varies due to capabilities of hooks. Any encountered problems should be filed as bugs. -### Fixed issues from NeMo Flow 0.2: +### Fixed issues from NeMo Relay 0.2: -### Fixed issues from NeMo Flow 0.1: +### Fixed issues from NeMo Relay 0.1: - Enabled TLS support for OTLP HTTP export. - Preserved Go scope stacks across OS threads. diff --git a/docs/build-plugins/about.md b/docs/build-plugins/about.md index bd66cfa8d..7b2438074 100644 --- a/docs/build-plugins/about.md +++ b/docs/build-plugins/about.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # About -Use this section when you want to package reusable NeMo Flow behavior as a plugin that can be activated from configuration. +Use this section when you want to package reusable NeMo Relay behavior as a plugin that can be activated from configuration. Plugins are the configuration-driven packaging layer for shared runtime behavior. A plugin can validate component-local config, register middleware and @@ -36,7 +36,7 @@ Use these guide links to move from the overview into task-specific instructions. - [Plugin Configuration Files](plugin-configuration-files.md) documents `plugins.toml` file discovery, precedence, merge behavior, and editor controls for the CLI gateway. - [Register Plugin Behavior](register-behavior.md) shows how to initialize config and install subscribers or middleware through `PluginContext`. - [Design Plugin Configuration](advanced-configuration.md) covers validation rules, advanced configuration patterns, rollout controls, and `PluginContext` usage. -- [NeMo Guardrails Example Plugin](nemoguardrails.md) shows an external Python plugin that applies NeMo Guardrails checks around NeMo Flow LLM and tool calls. +- [NeMo Guardrails Example Plugin](nemoguardrails.md) shows an external Python plugin that applies NeMo Guardrails checks around NeMo Relay LLM and tool calls. - [Code Examples](code-examples.md) provides patterns for dynamic header injection, subscriber-oriented export, multi-surface bundles, and framework-facing plugins. Start by deciding which runtime surfaces the plugin owns: middleware, diff --git a/docs/build-plugins/advanced-configuration.md b/docs/build-plugins/advanced-configuration.md index 08d223f0d..36f9c0b2f 100644 --- a/docs/build-plugins/advanced-configuration.md +++ b/docs/build-plugins/advanced-configuration.md @@ -13,7 +13,7 @@ You will define the plugin's configuration contract, validation rules, advanced ## Plugin Shape and Requirements -A NeMo Flow plugin has four practical parts: +A NeMo Relay plugin has four practical parts: | Part | Requirement | |---|---| @@ -88,7 +88,7 @@ These patterns help plugin authors keep configuration stable as components evolv ### Component-Local Versioning -Use a field such as `config.version` when the plugin's config schema needs independent compatibility handling. Keep the top-level `version` for the NeMo Flow plugin document itself. +Use a field such as `config.version` when the plugin's config schema needs independent compatibility handling. Keep the top-level `version` for the NeMo Relay plugin document itself. ### Multiple Component Instances @@ -105,7 +105,7 @@ When a plugin can be instantiated more than once, require explicit instance iden } ``` -Use the instance identity in logs, diagnostics, and downstream resource names. Let the NeMo Flow plugin system qualify runtime registration names; do not hand-build global names to avoid collisions. +Use the instance identity in logs, diagnostics, and downstream resource names. Let the NeMo Relay plugin system qualify runtime registration names; do not hand-build global names to avoid collisions. ### Presets and Overrides diff --git a/docs/build-plugins/basic-guide.md b/docs/build-plugins/basic-guide.md index a76828d2d..cccc92a0a 100644 --- a/docs/build-plugins/basic-guide.md +++ b/docs/build-plugins/basic-guide.md @@ -5,14 +5,14 @@ SPDX-License-Identifier: Apache-2.0 # Define a Plugin -Use this guide when you want to package reusable NeMo Flow behavior as a plugin that can be activated from configuration. +Use this guide when you want to package reusable NeMo Relay behavior as a plugin that can be activated from configuration. ## What You Build You will define the plugin's purpose, stable kind name, configuration boundary, runtime surfaces, and activation lifecycle. The result is a small plugin contract that can be validated and registered through the more focused follow-on guides. :::{note} -NeMo Flow plugin configuration keys use `snake_case` in every language and file +NeMo Relay plugin configuration keys use `snake_case` in every language and file format. Node.js helper function names are `camelCase`, but the objects passed to `plugin.initialize(...)` use the same canonical `snake_case` keys as Python, Rust, JSON, and TOML plugin configuration. diff --git a/docs/build-plugins/code-examples.md b/docs/build-plugins/code-examples.md index 5b64221ee..5debb6564 100644 --- a/docs/build-plugins/code-examples.md +++ b/docs/build-plugins/code-examples.md @@ -18,7 +18,7 @@ Use an LLM request intercept when a plugin needs to inject tenant or routing met :sync: python ```python -import nemo_flow +import nemo_relay class HeaderPlugin: @@ -39,7 +39,7 @@ class HeaderPlugin: context.register_llm_request_intercept("inject-header", 100, False, add_header) -nemo_flow.plugin.register("header-plugin", HeaderPlugin()) +nemo_relay.plugin.register("header-plugin", HeaderPlugin()) ``` ::: @@ -47,7 +47,7 @@ nemo_flow.plugin.register("header-plugin", HeaderPlugin()) :sync: node ```ts -import * as plugin from 'nemo-flow-node/plugin'; +import * as plugin from 'nemo-relay-node/plugin'; const headerPlugin: plugin.Plugin = { validate(pluginConfig) { @@ -98,7 +98,7 @@ Use a subscriber-oriented plugin when the component should watch the full lifecy :sync: python ```python -import nemo_flow +import nemo_relay class OpenInferencePlugin: @@ -120,7 +120,7 @@ class OpenInferencePlugin: context.register_subscriber("openinference-export", on_event) -nemo_flow.plugin.register("openinference-export", OpenInferencePlugin()) +nemo_relay.plugin.register("openinference-export", OpenInferencePlugin()) ``` ::: @@ -128,7 +128,7 @@ nemo_flow.plugin.register("openinference-export", OpenInferencePlugin()) :sync: node ```ts -import * as plugin from 'nemo-flow-node/plugin'; +import * as plugin from 'nemo-relay-node/plugin'; const openInferencePlugin: plugin.Plugin = { validate(pluginConfig) { diff --git a/docs/build-plugins/nemoguardrails.md b/docs/build-plugins/nemoguardrails.md index c77b5f1e2..8e0eceac1 100644 --- a/docs/build-plugins/nemoguardrails.md +++ b/docs/build-plugins/nemoguardrails.md @@ -5,20 +5,20 @@ SPDX-License-Identifier: Apache-2.0 # NeMo Guardrails Example Plugin -This example shows how to write a Python NeMo Flow plugin that calls the NeMo +This example shows how to write a Python NeMo Relay plugin that calls the NeMo Guardrails Python API. The example lives under `examples/nemoguardrails`. The single-file plugin implementation, runnable agent, and Guardrails config artifacts are under `example`. It is not part of the -`nemo_flow` Python package, and NeMo Flow does not depend on `nemoguardrails`. +`nemo_relay` Python package, and NeMo Relay does not depend on `nemoguardrails`. Applications that use the example install NeMo Guardrails in their own environment and import or vendor the example plugin. ## Install -Install NeMo Flow normally, then install NeMo Guardrails in the application or +Install NeMo Relay normally, then install NeMo Guardrails in the application or example environment that activates the plugin: ```bash @@ -41,16 +41,16 @@ Guardrails config directory, or pass inline YAML content. ```python import asyncio -import nemo_flow +import nemo_relay import plugin as nemoguardrails_plugin async def main() -> None: nemoguardrails_plugin.register() try: - config = nemo_flow.plugin.PluginConfig( + config = nemo_relay.plugin.PluginConfig( components=[ - nemo_flow.plugin.ComponentSpec( + nemo_relay.plugin.ComponentSpec( kind=nemoguardrails_plugin.DEFAULT_KIND, config={ "config_path": "./rails", @@ -59,9 +59,9 @@ async def main() -> None: ) ] ) - await nemo_flow.plugin.initialize(config) + await nemo_relay.plugin.initialize(config) finally: - nemo_flow.plugin.clear() + nemo_relay.plugin.clear() nemoguardrails_plugin.deregister() @@ -89,7 +89,7 @@ rails: prompts: - task: self_check_input content: |- - You are checking whether a NeMo Flow request should be allowed. + You are checking whether a NeMo Relay request should be allowed. The input may be plain user text or a JSON object with tool_name and arguments fields. User input: {{ user_input }} @@ -97,7 +97,7 @@ prompts: - task: self_check_output content: |- - You are checking whether a NeMo Flow response should be returned. + You are checking whether a NeMo Relay response should be returned. The output may be assistant text or a JSON object with tool_name, arguments, and result fields. Model output: {{ bot_response }} @@ -130,7 +130,7 @@ concrete example agent that initializes the plugin, checks a managed `tools.execute(...)` call, and checks a managed `llm.execute(...)` call against live NVIDIA-hosted inference. -Run it from a checkout where NeMo Flow and NeMo Guardrails are installed. The +Run it from a checkout where NeMo Relay and NeMo Guardrails are installed. The default lane uses a passthrough Guardrails config and the `current_time` tool. This is the fastest live validation path because it exercises the real plugin, real `nemoguardrails` initialization, tool execution, and LLM execution without @@ -178,7 +178,7 @@ python examples/nemoguardrails/example/agent_example.py \ For non-streaming `llm.execute(...)` calls, the plugin checks the user input before the model call and checks the assistant text after the model call. Guardrails can pass, block, or rewrite input. For output, this example supports -pass and block; modified output raises because NeMo Flow response codecs are +pass and block; modified output raises because NeMo Relay response codecs are decode-only and the example does not rewrite provider-shaped responses. For managed `tools.execute(...)` calls, the plugin can also check serialized @@ -196,20 +196,20 @@ sanitize guardrail. ## Supported Codecs -The example is intentionally limited to NeMo Flow's built-in LLM codec shapes: +The example is intentionally limited to NeMo Relay's built-in LLM codec shapes: - `openai_chat` for OpenAI Chat Completions-style requests and responses. - `openai_responses` for OpenAI Responses API-style requests and responses. - `anthropic_messages` for Anthropic Messages-style requests and responses. -Provider-specific payloads outside those codecs need a NeMo Flow codec and a +Provider-specific payloads outside those codecs need a NeMo Relay codec and a response text replacement strategy before a production plugin can apply modified output safely. ## Limitations This example calls NeMo Guardrails `check_async`, not `generate_async`. It -checks around NeMo Flow LLM and tool execution calls, but it does not let NeMo +checks around NeMo Relay LLM and tool execution calls, but it does not let NeMo Guardrails take over generation or agent orchestration. The example does not support: @@ -217,13 +217,13 @@ The example does not support: - Streaming LLM calls. - Dialog rails, retrieval rails, execution rails, or generation rails that require NeMo Guardrails to orchestrate the full generation flow. -- Arbitrary provider payloads beyond the three supported NeMo Flow codecs. +- Arbitrary provider payloads beyond the three supported NeMo Relay codecs. - Applying modified LLM output back into provider responses. - Rewriting tool-call arguments inside model responses before an application turns those model tool calls into managed `tools.execute(...)` calls. Tool checks use serialized JSON and NeMo Guardrails input/output checks. They -are NeMo Flow tool middleware checks powered by Guardrails, not a full +are NeMo Relay tool middleware checks powered by Guardrails, not a full `generate_async` agent-loop integration. `config_path` points at native NeMo Guardrails configuration. Guardrails config diff --git a/docs/build-plugins/plugin-configuration-files.md b/docs/build-plugins/plugin-configuration-files.md index 65a02c5c1..02866537f 100644 --- a/docs/build-plugins/plugin-configuration-files.md +++ b/docs/build-plugins/plugin-configuration-files.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Plugin Configuration Files -Use `plugins.toml` when the `nemo-flow` CLI gateway should activate plugins at +Use `plugins.toml` when the `nemo-relay` CLI gateway should activate plugins at startup. The file contains the same generic plugin configuration document used by the Rust, Python, and Node.js plugin APIs, but encoded as TOML at the file root. @@ -15,7 +15,7 @@ and conflict rules for the CLI gateway. Component-specific fields are documented in the guide for each plugin component. :::{note} -NeMo Flow plugin configuration keys use `snake_case` regardless of language or +NeMo Relay plugin configuration keys use `snake_case` regardless of language or file format. Node.js helper APIs can have `camelCase` function names, but the generic plugin document and component-local `config` objects use canonical `snake_case` keys. @@ -86,11 +86,11 @@ not loaded for that run. When no explicit `--config` path is supplied, the gateway checks these `plugins.toml` locations from lowest to highest precedence: -1. System: `/etc/nemo-flow/plugins.toml` -2. Project: the nearest `.nemo-flow/plugins.toml` found by walking upward from +1. System: `/etc/nemo-relay/plugins.toml` +2. Project: the nearest `.nemo-relay/plugins.toml` found by walking upward from the current directory -3. User: `$XDG_CONFIG_HOME/nemo-flow/plugins.toml`, or - `~/.config/nemo-flow/plugins.toml` when `XDG_CONFIG_HOME` is not set +3. User: `$XDG_CONFIG_HOME/nemo-relay/plugins.toml`, or + `~/.config/nemo-relay/plugins.toml` when `XDG_CONFIG_HOME` is not set Missing files are skipped. If no plugin config source exists, the gateway starts without process-level plugin activation. @@ -100,36 +100,36 @@ without process-level plugin activation. Use the interactive editor for Observability and Adaptive plugin configuration: ```bash -nemo-flow plugins edit +nemo-relay plugins edit ``` By default, the editor writes the user plugin file: ```text -$XDG_CONFIG_HOME/nemo-flow/plugins.toml +$XDG_CONFIG_HOME/nemo-relay/plugins.toml ``` or: ```text -~/.config/nemo-flow/plugins.toml +~/.config/nemo-relay/plugins.toml ``` Use a scope flag to edit another location: ```bash -nemo-flow plugins edit --project -nemo-flow plugins edit --global +nemo-relay plugins edit --project +nemo-relay plugins edit --global ``` Scope flags are mutually exclusive. -`--project` writes the nearest existing `.nemo-flow/plugins.toml`. If none -exists, it writes next to the nearest `.nemo-flow/config.toml`. If neither file -exists in the parent directories, it writes `./.nemo-flow/plugins.toml` from the +`--project` writes the nearest existing `.nemo-relay/plugins.toml`. If none +exists, it writes next to the nearest `.nemo-relay/config.toml`. If neither file +exists in the parent directories, it writes `./.nemo-relay/plugins.toml` from the current directory. -`--global` writes `/etc/nemo-flow/plugins.toml` and usually requires elevated +`--global` writes `/etc/nemo-relay/plugins.toml` and usually requires elevated filesystem permissions. The editor menus support these controls: @@ -163,7 +163,7 @@ kind = "observability" [components.config.atof] enabled = true -output_directory = "/var/log/nemo-flow" +output_directory = "/var/log/nemo-relay" mode = "append" ``` @@ -237,7 +237,7 @@ Common validation failures include: - Component-specific semantic failures, such as an Agent Trajectory Interchange Format (ATIF) filename template that does not contain `{session_id}`. -Use `nemo-flow doctor` to inspect the resolved gateway configuration and plugin +Use `nemo-relay doctor` to inspect the resolved gateway configuration and plugin diagnostics. For Observability, doctor also reports enabled exporter sections and checks writable file exporter directories or reachable OTLP endpoints when those settings are present. diff --git a/docs/build-plugins/register-behavior.md b/docs/build-plugins/register-behavior.md index 7c08471f2..6ae7ac941 100644 --- a/docs/build-plugins/register-behavior.md +++ b/docs/build-plugins/register-behavior.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Register Plugin Behavior -Use this guide when plugin config validation is in place and you need the plugin to install real NeMo Flow runtime behavior. +Use this guide when plugin config validation is in place and you need the plugin to install real NeMo Relay runtime behavior. ## What You Build @@ -41,20 +41,20 @@ Use the plugin APIs in this order: :sync: python ```python -import nemo_flow +import nemo_relay -config = nemo_flow.plugin.PluginConfig() +config = nemo_relay.plugin.PluginConfig() config.components = [ - nemo_flow.plugin.ComponentSpec( + nemo_relay.plugin.ComponentSpec( kind="header-plugin", config={"header_name": "x-tenant", "value": "tenant-a"}, ) ] -report = nemo_flow.plugin.validate(config) -active_report = await nemo_flow.plugin.initialize(config) -kinds = nemo_flow.plugin.list_kinds() -nemo_flow.plugin.clear() +report = nemo_relay.plugin.validate(config) +active_report = await nemo_relay.plugin.initialize(config) +kinds = nemo_relay.plugin.list_kinds() +nemo_relay.plugin.clear() ``` ::: @@ -63,7 +63,7 @@ nemo_flow.plugin.clear() :sync: node ```ts -import * as plugin from 'nemo-flow-node/plugin'; +import * as plugin from 'nemo-relay-node/plugin'; const config = plugin.defaultConfig(); config.components = [ @@ -86,7 +86,7 @@ plugin.clear(); :sync: rust ```rust -use nemo_flow::plugin::{ +use nemo_relay::plugin::{ clear_plugin_configuration, initialize_plugins, list_plugin_kinds, validate_plugin_config, PluginComponentSpec, PluginConfig, }; @@ -118,7 +118,7 @@ The same model applies in every binding: validate component-local config, then i :sync: python ```python -import nemo_flow +import nemo_relay class HeaderPlugin: @@ -139,7 +139,7 @@ class HeaderPlugin: context.register_llm_request_intercept("inject-header", 100, False, add_header) -nemo_flow.plugin.register("header-plugin", HeaderPlugin()) +nemo_relay.plugin.register("header-plugin", HeaderPlugin()) ``` ::: @@ -148,7 +148,7 @@ nemo_flow.plugin.register("header-plugin", HeaderPlugin()) :sync: node ```ts -import * as plugin from 'nemo-flow-node/plugin'; +import * as plugin from 'nemo-relay-node/plugin'; const headerPlugin: plugin.Plugin = { validate(pluginConfig) { @@ -184,7 +184,7 @@ plugin.register('header-plugin', headerPlugin); :sync: rust ```rust -use nemo_flow::plugin::{ +use nemo_relay::plugin::{ register_plugin, ConfigDiagnostic, DiagnosticLevel, Plugin, PluginRegistrationContext, Result as PluginResult, }; diff --git a/docs/build-plugins/validate-configuration.md b/docs/build-plugins/validate-configuration.md index 31b148ad2..fa13e9fa9 100644 --- a/docs/build-plugins/validate-configuration.md +++ b/docs/build-plugins/validate-configuration.md @@ -30,7 +30,7 @@ Disabled components are still validated. This lets operators detect config probl :sync: python ```python -from nemo_flow.plugin import ComponentSpec, ConfigPolicy, PluginConfig +from nemo_relay.plugin import ComponentSpec, ConfigPolicy, PluginConfig config = PluginConfig( version=1, @@ -54,7 +54,7 @@ config = PluginConfig( :sync: node ```ts -import type { PluginConfig } from 'nemo-flow-node/plugin'; +import type { PluginConfig } from 'nemo-relay-node/plugin'; const config: PluginConfig = { version: 1, @@ -78,7 +78,7 @@ const config: PluginConfig = { :sync: rust ```rust -use nemo_flow::plugin::{ConfigPolicy, PluginComponentSpec, PluginConfig}; +use nemo_relay::plugin::{ConfigPolicy, PluginComponentSpec, PluginConfig}; let mut component = PluginComponentSpec::new("header-plugin"); component.enabled = true; @@ -139,9 +139,9 @@ Use the validation API before initialization and fail deployment if the report c :sync: python ```python -import nemo_flow +import nemo_relay -report = nemo_flow.plugin.validate(config) +report = nemo_relay.plugin.validate(config) has_errors = any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"]) if has_errors: raise RuntimeError(report["diagnostics"]) @@ -152,7 +152,7 @@ if has_errors: :sync: node ```ts -import * as plugin from 'nemo-flow-node/plugin'; +import * as plugin from 'nemo-relay-node/plugin'; const report = plugin.validate(config); const hasErrors = report.diagnostics.some((diagnostic) => diagnostic.level === 'error'); @@ -166,7 +166,7 @@ if (hasErrors) { :sync: rust ```rust -use nemo_flow::plugin::validate_plugin_config; +use nemo_relay::plugin::validate_plugin_config; let report = validate_plugin_config(&config); if report.has_errors() { diff --git a/docs/conf.py b/docs/conf.py index b07bcdcee..9b16b7225 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ import sphinx_js from packaging.version import InvalidVersion, Version -project = "NVIDIA NeMo Flow" +project = "NVIDIA NeMo Relay" copyright = "Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved." author = "NVIDIA CORPORATION & AFFILIATES" @@ -77,7 +77,7 @@ myst_fence_as_directive = ["mermaid"] myst_heading_anchors = 3 -autoapi_dirs = ["../python/nemo_flow"] +autoapi_dirs = ["../python/nemo_relay"] autoapi_file_patterns = ["*.py", "*.pyi"] autoapi_root = "reference/api/python/_generated" autoapi_add_toctree_entry = False @@ -102,8 +102,8 @@ napoleon_attr_annotations = True rust_crates = { - "nemo-flow": str(RUST_API_SOURCE_DIR / "core"), - "nemo-flow-adaptive": str(RUST_API_SOURCE_DIR / "adaptive"), + "nemo-relay": str(RUST_API_SOURCE_DIR / "core"), + "nemo-relay-adaptive": str(RUST_API_SOURCE_DIR / "adaptive"), } rust_doc_dir = str(RUST_API_GENERATED_DIR) rust_rustdoc_fmt = "md" @@ -112,7 +112,7 @@ rust_generate_mode = "always" html_theme = "nvidia_sphinx_theme" -html_title = "NVIDIA NeMo Flow" +html_title = "NVIDIA NeMo Relay" html_static_path = ["_static"] html_css_files = ["extra.css"] html_js_files = ["version-switcher.js"] @@ -129,7 +129,7 @@ "icon_links": [ { "name": "GitHub", - "url": "https://github.com/NVIDIA/NeMo-Flow", + "url": "https://github.com/NVIDIA/NeMo-Relay", "icon": "fa-brands fa-github", } ], @@ -364,10 +364,10 @@ def _resolve_runtime_paths(source_docs_dir: Path) -> None: def _wire_runtime_config(config) -> None: - config.autoapi_dirs = [str(REPO_ROOT / "python" / "nemo_flow")] + config.autoapi_dirs = [str(REPO_ROOT / "python" / "nemo_relay")] config.rust_crates = { - "nemo-flow": str(RUST_API_SOURCE_DIR / "core"), - "nemo-flow-adaptive": str(RUST_API_SOURCE_DIR / "adaptive"), + "nemo-relay": str(RUST_API_SOURCE_DIR / "core"), + "nemo-relay-adaptive": str(RUST_API_SOURCE_DIR / "adaptive"), } config.rust_doc_dir = str(RUST_API_GENERATED_DIR) @@ -439,9 +439,9 @@ def _prepare_patched_sphinx_js_runtime() -> None: def _configure_sphinx_js_environment() -> None: # The Node artifact builder launches sphinx-js through `tsx`, so it reads # these paths from the environment instead of importing Python directly. - os.environ["NEMO_FLOW_SPHINX_JS_MAIN_TS"] = str(SPHINX_JS_WORK_DIR / "main.ts") - os.environ["NEMO_FLOW_SPHINX_JS_IMPORT_HOOK"] = str(SPHINX_JS_WORK_DIR / "registerImportHook.mjs") - os.environ["NEMO_FLOW_SPHINX_JS_TSX_TSCONFIG"] = str(SPHINX_JS_WORK_DIR / "tsconfig.json") + os.environ["NEMO_RELAY_SPHINX_JS_MAIN_TS"] = str(SPHINX_JS_WORK_DIR / "main.ts") + os.environ["NEMO_RELAY_SPHINX_JS_IMPORT_HOOK"] = str(SPHINX_JS_WORK_DIR / "registerImportHook.mjs") + os.environ["NEMO_RELAY_SPHINX_JS_TSX_TSCONFIG"] = str(SPHINX_JS_WORK_DIR / "tsconfig.json") def _patch_autoapi_summary_signature_normalization() -> None: @@ -453,19 +453,19 @@ def _patch_autoapi_summary_signature_normalization() -> None: return original_mangle_signature = autoapi_directives.mangle_signature - if getattr(original_mangle_signature, "_nemo_flow_normalizes_unicode_arrow", False): + if getattr(original_mangle_signature, "_nemo_relay_normalizes_unicode_arrow", False): return - def _nemo_flow_mangle_signature(sig: str, *args, **kwargs) -> str: + def _nemo_relay_mangle_signature(sig: str, *args, **kwargs) -> str: normalized = sig.replace(" \u2192 ", " -> ") return original_mangle_signature(normalized, *args, **kwargs) - _nemo_flow_mangle_signature._nemo_flow_normalizes_unicode_arrow = True - autoapi_directives.mangle_signature = _nemo_flow_mangle_signature + _nemo_relay_mangle_signature._nemo_relay_normalizes_unicode_arrow = True + autoapi_directives.mangle_signature = _nemo_relay_mangle_signature def _skip_imported_type_aliases(_app, what, _name, obj, skip, _options): - if what == "module" and getattr(obj, "id", None) == "nemo_flow._native": + if what == "module" and getattr(obj, "id", None) == "nemo_relay._native": return False if skip: @@ -485,8 +485,8 @@ def _run_node_docs_artifact_builder() -> None: cwd=CONFIG_REPO_ROOT, env={ **os.environ, - "NEMO_FLOW_DOCS_REPO_ROOT": str(REPO_ROOT), - "NEMO_FLOW_DOCS_DIR": str(DOCS_DIR), + "NEMO_RELAY_DOCS_REPO_ROOT": str(REPO_ROOT), + "NEMO_RELAY_DOCS_DIR": str(DOCS_DIR), }, ) diff --git a/docs/contribute/about.md b/docs/contribute/about.md index 8bafa6b4e..54785d359 100644 --- a/docs/contribute/about.md +++ b/docs/contribute/about.md @@ -5,10 +5,10 @@ SPDX-License-Identifier: Apache-2.0 # About -Use this section when you want to contribute to NeMo Flow source code, bindings, +Use this section when you want to contribute to NeMo Relay source code, bindings, documentation, examples, tests, or third-party integration patches. -Contributing to NeMo Flow often means working across the Rust core, generated and +Contributing to NeMo Relay often means working across the Rust core, generated and hand-written language bindings, plugin surfaces, adaptive components, observability exporters, and documentation. The contribution workflow keeps those surfaces aligned so public behavior does not drift between supported @@ -25,7 +25,7 @@ Use these signals to decide whether this documentation path matches your current - Preparing a pull request for review - Looking for contribution workflow details beyond user-facing product docs -If you are only consuming NeMo Flow packages, start with [Getting Started](../getting-started/quick-start.md) instead. +If you are only consuming NeMo Relay packages, start with [Getting Started](../getting-started/quick-start.md) instead. ## Guides diff --git a/docs/contribute/development-setup.md b/docs/contribute/development-setup.md index 9151b0298..efe4ce15f 100644 --- a/docs/contribute/development-setup.md +++ b/docs/contribute/development-setup.md @@ -10,7 +10,7 @@ changes. ## Package Installation -If you are consuming NeMo Flow rather than developing this repository, install +If you are consuming NeMo Relay rather than developing this repository, install the published package for your language. Use [Installation](../getting-started/installation.md) for package-manager commands covering the CLI, Python, Node.js, Rust, and supported integrations. @@ -37,7 +37,7 @@ bindings from source in the same branch. Clone the repository and build the workspace: ```bash -git clone && cd NeMo-Flow +git clone && cd NeMo-Relay uv sync cargo install just --locked uv run pre-commit install @@ -49,7 +49,7 @@ just build-node Validate the source builds for the experimental bindings when you touch them: ```bash -cd go/nemo_flow +cd go/nemo_relay CGO_LDFLAGS="-L../../target/release" LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}../../target/release" go test -v ./... cd ../.. diff --git a/docs/contribute/testing-and-docs.md b/docs/contribute/testing-and-docs.md index a094c8a0f..3982f1434 100644 --- a/docs/contribute/testing-and-docs.md +++ b/docs/contribute/testing-and-docs.md @@ -68,7 +68,7 @@ the OpenClaw plugin or when touching `integrations/openclaw`. ```bash npm install --ignore-scripts -npm test --workspace=nemo-flow-node +npm test --workspace=nemo-relay-node just test-openclaw ``` diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index ae770d6dc..3004c110b 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Configuration -NeMo Flow runtime behavior is configured through API objects and registration calls rather than a global configuration file. +NeMo Relay runtime behavior is configured through API objects and registration calls rather than a global configuration file. ## Core Runtime Setup -Most applications configure NeMo Flow by: +Most applications configure NeMo Relay by: 1. Creating or reusing a scope stack. 2. Registering guardrails, intercepts, or subscribers. @@ -28,7 +28,7 @@ Plugins use a structured plugin configuration with: Start with [Define a Plugin](../build-plugins/basic-guide.md) when you need reusable middleware, subscribers, or adaptive behavior. -The `nemo-flow` CLI gateway reads plugin files named `plugins.toml`. See +The `nemo-relay` CLI gateway reads plugin files named `plugins.toml`. See [Plugin Configuration Files](../build-plugins/plugin-configuration-files.md) for file locations, precedence, merge behavior, editor controls, and validation rules. @@ -44,7 +44,7 @@ plugin component to own standard exporter setup and teardown. See and [Observability](../plugins/observability/about.md) for the supported export paths. -NeMo Flow does not require application-level environment variables for normal +NeMo Relay does not require application-level environment variables for normal runtime use. Configure most behavior through API objects, registration calls, or plugin configuration. diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index c73132f01..d9479fee5 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Installation -Use this page when you are consuming a published NeMo Flow release from a +Use this page when you are consuming a published NeMo Relay release from a package manager. If you are working from a source checkout, validating unpublished changes, or @@ -14,48 +14,48 @@ contributing to the repository, use ## CLI -Install the NeMo Flow CLI when you want the `nemo-flow` executable for +Install the NeMo Relay CLI when you want the `nemo-relay` executable for coding-agent hook and LLM gateway observability. ```bash -cargo install nemo-flow-cli@0.3.0 +cargo install nemo-relay-cli@0.3.0 ``` ## Python -Install the Python package when your application uses NeMo Flow through the +Install the Python package when your application uses NeMo Relay through the Python wrapper. ```bash -uv add nemo-flow@0.3.0 +uv add nemo-relay@0.3.0 ``` Use `uv add` from an application project that has a `pyproject.toml`; it records -`nemo-flow` as a project dependency. If you are only installing into an active +`nemo-relay` as a project dependency. If you are only installing into an active virtual environment and do not have project metadata, use `uv pip install -nemo-flow` instead. You can also use `pip install nemo-flow` if you are not +nemo-relay` instead. You can also use `pip install nemo-relay` if you are not managing the environment with `uv`. ## Node.js -Install the Node.js package when your application uses NeMo Flow through the +Install the Node.js package when your application uses NeMo Relay through the JavaScript API. ```bash -npm install nemo-flow-node +npm install nemo-relay-node ``` ## Rust -Add the Rust crates when your application uses NeMo Flow directly from Rust. +Add the Rust crates when your application uses NeMo Relay directly from Rust. ```bash -cargo add nemo-flow@0.3.0 -cargo add nemo-flow-adaptive@0.3.0 +cargo add nemo-relay@0.3.0 +cargo add nemo-relay-adaptive@0.3.0 ``` -- `nemo-flow` provides the core runtime APIs for scopes, middleware, subscribers, plugins, tool calls, and LLM calls. -- `nemo-flow-adaptive` provides adaptive runtime primitives and Redis-backed learning components when you want adaptive tuning behavior in Rust. +- `nemo-relay` provides the core runtime APIs for scopes, middleware, subscribers, plugins, tool calls, and LLM calls. +- `nemo-relay-adaptive` provides adaptive runtime primitives and Redis-backed learning components when you want adaptive tuning behavior in Rust. ## Integrations @@ -68,12 +68,12 @@ Install the OpenClaw plugin through OpenClaw so OpenClaw can register and manage the package: ```bash -openclaw plugins install npm:nemo-flow-openclaw@0.3.0 +openclaw plugins install npm:nemo-relay-openclaw@0.3.0 openclaw gateway restart ``` -Use the package name `nemo-flow-openclaw` for installation. Use the plugin ID -`nemo-flow` in OpenClaw configuration, inspection, and gateway status commands. +Use the package name `nemo-relay-openclaw` for installation. Use the plugin ID +`nemo-relay` in OpenClaw configuration, inspection, and gateway status commands. See the [OpenClaw Plugin Guide](../integrations/openclaw-plugin.md) for configuration and verification steps. @@ -83,10 +83,10 @@ Install the Python package with the supported framework extras when your application uses LangChain, LangGraph, or Deep Agents. ```bash -uv add "nemo-flow[langchain,langgraph,deepagents]@0.3.0" +uv add "nemo-relay[langchain,langgraph,deepagents]@0.3.0" ``` -The extras install the NeMo Flow Python package plus the dependencies needed by +The extras install the NeMo Relay Python package plus the dependencies needed by the maintained public integrations. See [Supported Integrations](../integrations/about.md) for guide links and support levels. diff --git a/docs/getting-started/migration.md b/docs/getting-started/migration.md deleted file mode 100644 index 315c2ec0f..000000000 --- a/docs/getting-started/migration.md +++ /dev/null @@ -1,97 +0,0 @@ - - -# Migrate Existing Agent Instrumentation to NeMo Flow - -Use this page as a routing guide when your agent application already has -callbacks, traces, or custom logging and you want to adopt NeMo Flow without -rewriting the application first. - -This is an adoption on-ramp, not a drop-in migration contract. Start by adding -NeMo Flow at the execution boundaries you can observe, validate that application -behavior stays the same, then add policy, adaptive behavior, or production -exporters after the basic event stream is correct. - -## Who This Guide Is For - -Use this guide when you are starting from one of these systems: - -- LangChain, LangGraph, Deep Agents, or another framework callback surface. -- Existing OpenTelemetry or OpenInference traces. -- A custom agent harness that emits JSON traces, run records, or callback logs. - -If you are building a new application without existing instrumentation, start -with the [Quick Start](quick-start.md) instead. - -## Migration Decision Tree - -Use the table below to choose the first NeMo Flow path. Pick one path first, -validate it, then add additional exporters or middleware. - -| Starting Point | First NeMo Flow Path | -|---|---| -| You own the direct tool or LLM call site | Use [Instrument Applications](../instrument-applications/about.md). | -| A framework owns the tool or LLM call site | Use [Supported Integrations](../integrations/about.md) if one exists; otherwise use [Integrate into Frameworks](../integrate-frameworks/about.md). | -| Your backend expects generic OTLP traces | Use the [OpenTelemetry exporter](../plugins/observability/opentelemetry.md). | -| Your backend expects OpenInference agent or LLM spans | Use the [OpenInference exporter](../plugins/observability/openinference.md). | -| You need portable offline trajectories for replay, analysis, or evaluation | Use [ATIF export](../plugins/observability/atif.md). | -| You need raw lifecycle events for a custom pipeline | Use [ATOF export](../plugins/observability/atof.md) or a direct subscriber. | - -## Preserve Behavior First - -Adopt NeMo Flow in this order: - -1. Add scopes around the request, run, or agent boundary. -2. Add a lightweight subscriber or local exporter so you can inspect emitted - events. -3. Instrument one tool or LLM boundary at a time. -4. Compare application outputs, framework callbacks, and existing traces before - enabling guardrails, intercepts, adaptive tuning, or production exporters. - -The first milestone is not performance tuning or policy coverage. The first -milestone is the same application behavior with a correct NeMo Flow event -stream. - -## Map Existing Concepts - -Use this mapping to translate current instrumentation concepts into NeMo Flow -terms before changing code. - -| Existing Concept | NeMo Flow Concept | -|---|---| -| LangChain callback run | Scope plus lifecycle event stream. | -| OpenInference span | OpenInference subscriber output from NeMo Flow events. | -| OpenTelemetry span | OpenTelemetry subscriber output from NeMo Flow events. | -| Custom trace object | Subscriber output, ATOF JSONL, or ATIF trajectory export. | -| Request-local state | Scope stack and context isolation. | -| Callback middleware | NeMo Flow middleware around managed tool and LLM calls. | -| Trace correlation ID | Root scope UUID and parent-child event IDs. | - -## Common Starting Scenarios - -If you already use LangChain callbacks, keep the framework behavior in place and -start with the [LangChain integration](../integrations/langchain.md). Validate -that the agent result and existing callback behavior do not change before adding -new middleware. - -If you already export OpenInference spans to Phoenix or another compatible -backend, start with the [OpenInference exporter](../plugins/observability/openinference.md). -NeMo Flow becomes the event source for those spans; the backend setup can stay -backend-specific. - -If your custom harness emits JSON traces, decide whether you need raw lifecycle -events, portable trajectories, or direct in-process handling. Use [ATOF export](../plugins/observability/atof.md) -for raw events, [ATIF export](../plugins/observability/atif.md) for trajectories, -or a direct subscriber when your application should own the output shape. - -## Next Steps - -After you pick the first path, use these pages for implementation details: - -- [Quick Start](quick-start.md) -- [Instrument a Tool Call](../instrument-applications/instrument-tool-call.md) -- [Instrument an LLM Call](../instrument-applications/instrument-llm-call.md) -- [Integrate into Frameworks](../integrate-frameworks/about.md) -- [Observability Plugin](../plugins/observability/about.md) diff --git a/docs/getting-started/nodejs.md b/docs/getting-started/nodejs.md index 0279dc2f8..690aeaa49 100644 --- a/docs/getting-started/nodejs.md +++ b/docs/getting-started/nodejs.md @@ -18,7 +18,7 @@ local checkout. Use this path when you want the published package for application development. ```bash -npm install nemo-flow-node +npm install nemo-relay-node ``` ### Install from the Repository @@ -28,7 +28,7 @@ behavior. ```bash npm install --ignore-scripts -npm run build --workspace=nemo-flow-node +npm run build --workspace=nemo-relay-node ``` This path is for local source development when you need to build the binding from the repository checkout. @@ -47,7 +47,7 @@ const { event, toolCallExecute, llmCallExecute, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); async function main() { registerSubscriber("quickstart-printer", (runtimeEvent) => { @@ -108,9 +108,9 @@ These package entry points are the main Node.js APIs to use from applications an integrations. - Runtime lifecycle APIs are exported from the package root. -- Typed wrappers live in `nemo-flow-node/typed`. -- Plugin helpers live in `nemo-flow-node/plugin`. -- Adaptive helpers live in `nemo-flow-node/adaptive`. +- Typed wrappers live in `nemo-relay-node/typed`. +- Plugin helpers live in `nemo-relay-node/plugin`. +- Adaptive helpers live in `nemo-relay-node/adaptive`. ## What to Learn Next diff --git a/docs/getting-started/prerequisites.md b/docs/getting-started/prerequisites.md index 0b7076298..46fcb9dde 100644 --- a/docs/getting-started/prerequisites.md +++ b/docs/getting-started/prerequisites.md @@ -22,8 +22,8 @@ The primary documentation track covers Rust, Python, and Node.js. Go, WebAssembl Clone the repository when you need local source builds or contribution workflows: ```bash -git clone https://github.com/NVIDIA/NeMo-Flow.git -cd NeMo-Flow +git clone https://github.com/NVIDIA/NeMo-Relay.git +cd NeMo-Relay ``` Install development dependencies for Python and docs workflows: diff --git a/docs/getting-started/python/index.md b/docs/getting-started/python/index.md index 9145c0fbb..608bda4c8 100644 --- a/docs/getting-started/python/index.md +++ b/docs/getting-started/python/index.md @@ -19,13 +19,13 @@ local checkout. Use this path when you want the published package for application development. ```bash -uv add nemo-flow@0.3.0 +uv add nemo-relay@0.3.0 ``` Run `uv add` from an application project that has a `pyproject.toml`; it records -`nemo-flow` as a dependency. If you are only installing into an active virtual -environment, use `uv pip install nemo-flow`. If you are not using `uv`, install -the published package with `pip install nemo-flow`. +`nemo-relay` as a dependency. If you are only installing into an active virtual +environment, use `uv pip install nemo-relay`. If you are not using `uv`, install +the published package with `pip install nemo-relay`. ### Install from the Repository @@ -42,7 +42,7 @@ If you are consuming the local checkout from another `uv` project, add the sourc path from that application's directory instead: ```bash -uv add --editable ../NeMo-Flow +uv add --editable ../NeMo-Relay ``` This records the local source in the application's `pyproject.toml` through @@ -55,7 +55,7 @@ The example below runs one minimal instrumented workflow through the binding. ```python import asyncio -import nemo_flow +import nemo_relay def on_event(event) -> None: @@ -74,15 +74,15 @@ async def model(request): async def main(): - nemo_flow.subscribers.register("quickstart-printer", on_event) + nemo_relay.subscribers.register("quickstart-printer", on_event) - with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope.event("initialized", handle=handle, data={"binding": "python"}) + with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope.event("initialized", handle=handle, data={"binding": "python"}) - tool_result = await nemo_flow.tools.execute("search", {"query": "hello"}, search, handle=handle) - llm_result = await nemo_flow.llm.execute( + tool_result = await nemo_relay.tools.execute("search", {"query": "hello"}, search, handle=handle) + llm_result = await nemo_relay.llm.execute( "demo-provider", - nemo_flow.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), + nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), model, handle=handle, ) @@ -90,7 +90,7 @@ async def main(): print(tool_result) print(llm_result) - nemo_flow.subscribers.deregister("quickstart-printer") + nemo_relay.subscribers.deregister("quickstart-printer") asyncio.run(main()) @@ -106,22 +106,22 @@ You should see: If you only see the returned values and no event lines, the callbacks ran but you did not verify instrumentation. The subscriber output is the fast check that -NeMo Flow actually emitted lifecycle events. +NeMo Relay actually emitted lifecycle events. ## Where the Python Surface Lives These modules are the main Python APIs to use from applications and integrations. -- `nemo_flow.scope` -- `nemo_flow.tools` -- `nemo_flow.llm` -- `nemo_flow.guardrails` -- `nemo_flow.intercepts` -- `nemo_flow.subscribers` -- `nemo_flow.plugin` -- `nemo_flow.adaptive` -- `nemo_flow.typed` -- `nemo_flow.codecs` +- `nemo_relay.scope` +- `nemo_relay.tools` +- `nemo_relay.llm` +- `nemo_relay.guardrails` +- `nemo_relay.intercepts` +- `nemo_relay.subscribers` +- `nemo_relay.plugin` +- `nemo_relay.adaptive` +- `nemo_relay.typed` +- `nemo_relay.codecs` ## What to Learn Next diff --git a/docs/getting-started/rust.md b/docs/getting-started/rust.md index fcbbe355e..8d7e815f1 100644 --- a/docs/getting-started/rust.md +++ b/docs/getting-started/rust.md @@ -17,16 +17,16 @@ local checkout. Use the published crates when you are consuming a release: ```bash -cargo add nemo-flow@0.3.0 -cargo add nemo-flow-adaptive@0.3.0 +cargo add nemo-relay@0.3.0 +cargo add nemo-relay-adaptive@0.3.0 cargo add serde_json ``` -Install the published NeMo Flow CLI separately when you need coding-agent hook +Install the published NeMo Relay CLI separately when you need coding-agent hook and LLM gateway observability: ```bash -cargo install nemo-flow-cli@0.3.0 +cargo install nemo-relay-cli@0.3.0 ``` ### Install from the Repository @@ -35,25 +35,25 @@ Use a path dependency when your application is consuming a local checkout: ```toml [dependencies] -nemo-flow = { path = "../NeMo-Flow/crates/core" } -nemo-flow-adaptive = { path = "../NeMo-Flow/crates/adaptive" } +nemo-relay = { path = "../NeMo-Relay/crates/core" } +nemo-relay-adaptive = { path = "../NeMo-Relay/crates/adaptive" } serde_json = "1" ``` -- `nemo-flow` is the core Rust runtime surface. -- `nemo-flow-adaptive` is the companion crate for adaptive runtime primitives and Redis-backed learning components. -- `nemo-flow-cli` is a binary crate. Use `cargo install nemo-flow-cli@0.3.0` when - you need the NeMo Flow CLI. +- `nemo-relay` is the core Rust runtime surface. +- `nemo-relay-adaptive` is the companion crate for adaptive runtime primitives and Redis-backed learning components. +- `nemo-relay-cli` is a binary crate. Use `cargo install nemo-relay-cli@0.3.0` when + you need the NeMo Relay CLI. ## Push a Scope and Emit a Mark The example below creates a scope and records a mark event from Rust. ```rust -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ self, EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType, }; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; use serde_json::json; use std::sync::Arc; diff --git a/docs/index.md b/docs/index.md index 7afe8ee18..208b80788 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Overview -NeMo Flow is a portable execution runtime for agent systems that already have a +NeMo Relay is a portable execution runtime for agent systems that already have a framework, model provider, policy layer, or observability backend. It gives those systems one consistent way to describe what is happening when an agent crosses a request, tool, or LLM boundary. @@ -13,9 +13,9 @@ request, tool, or LLM boundary. That layer is useful because agent applications rarely live inside one clean abstraction. A production stack might combine NeMo Agent Toolkit, LangChain, LangGraph, provider SDKs, custom harness code, NeMo Guardrails, tracing systems, -and evaluation pipelines. NeMo Flow sits underneath those choices as the shared +and evaluation pipelines. NeMo Relay sits underneath those choices as the shared runtime contract for scopes, middleware, plugins, lifecycle events, adaptive -behavior, and observability. Under the NeMo Flow scope stack and middleware, the scoped execution path is referred to as work. +behavior, and observability. Under the NeMo Relay scope stack and middleware, the scoped execution path is referred to as work. The result is a framework-neutral substrate for agent execution. Applications keep their orchestration model, providers keep their native clients, and @@ -24,7 +24,7 @@ adaptive behavior across Rust, Python, and Node.js. ## Benefits -NeMo Flow is designed for teams that need agent runtime behavior to stay +NeMo Relay is designed for teams that need agent runtime behavior to stay consistent as applications grow across frameworks, languages, and deployment targets. @@ -42,7 +42,7 @@ targets. lifecycle stream in-process or translate it to Agent Trajectory Interchange Format (ATIF) trajectories, OpenTelemetry traces, and OpenInference-compatible traces for debugging, evaluation, and production observability. -- **Adopt without replacing the stack**: NeMo Flow can sit below NeMo ecosystem +- **Adopt without replacing the stack**: NeMo Relay can sit below NeMo ecosystem components, third-party agent frameworks, provider adapters, or direct application code, so teams can add shared runtime semantics without a framework migration. @@ -59,13 +59,12 @@ Use the reading path that matches your task: |---|---| | Run a minimal example | [Quick Start](getting-started/quick-start.md) | | Install packages | [Installation](getting-started/installation.md) | -| Adopt from existing callbacks, traces, or custom harnesses | [Migration Paths](getting-started/migration.md) | | Develop from source | [Development Setup](contribute/development-setup.md) | | Understand the runtime model | [Concepts](about/concepts/index.md) | | Instrument an application | [Instrument Applications](instrument-applications/about.md) | | Use a maintained integration | [Supported Integrations](integrations/about.md) | | Integrate a framework | [Integrate into Frameworks](integrate-frameworks/about.md) | -| Observe a local coding-agent CLI | [NeMo Flow CLI](nemo-flow-cli/about.md) | +| Observe a local coding-agent CLI | [NeMo Relay CLI](nemo-relay-cli/about.md) | | Package reusable behavior | [Build Plugins](build-plugins/about.md) | | Export traces or trajectories | [Observability](plugins/observability/about.md) | | Tune performance with adaptive behavior | [Adaptive](plugins/adaptive/about.md) | @@ -129,7 +128,7 @@ flowchart TB ```{toctree} :hidden: -:caption: About NeMo Flow +:caption: About NeMo Relay :maxdepth: 2 Overview @@ -147,21 +146,20 @@ about/release-notes/index getting-started/prerequisites getting-started/installation Configuration / Setup -Migration Paths Quick Start ``` ```{toctree} :hidden: -:caption: NeMo Flow CLI +:caption: NeMo Relay CLI :maxdepth: 2 -About -Basic Usage -Claude Code -Codex -Cursor -Hermes Agent +About +Basic Usage +Claude Code +Codex +Cursor +Hermes Agent ``` ```{toctree} diff --git a/docs/instrument-applications/about.md b/docs/instrument-applications/about.md index da65adcf5..6f1a6b00a 100644 --- a/docs/instrument-applications/about.md +++ b/docs/instrument-applications/about.md @@ -5,9 +5,9 @@ SPDX-License-Identifier: Apache-2.0 # About -Use this section when you own an application, agent harness, or workflow and can route tool and LLM calls through NeMo Flow directly. +Use this section when you own an application, agent harness, or workflow and can route tool and LLM calls through NeMo Relay directly. -Direct instrumentation puts NeMo Flow at the boundaries where work happens. +Direct instrumentation puts NeMo Relay at the boundaries where work happens. Scopes define request and agent ownership, managed execution helpers wrap tool and LLM calls, middleware applies policy and transformation, and subscribers receive lifecycle events. This path gives the runtime a complete view of agent diff --git a/docs/instrument-applications/adding-scopes-and-marks.md b/docs/instrument-applications/adding-scopes-and-marks.md index e0d964b05..d4196bad3 100644 --- a/docs/instrument-applications/adding-scopes-and-marks.md +++ b/docs/instrument-applications/adding-scopes-and-marks.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Adding Scopes and Marks -Use this guide when you want NeMo Flow to identify one agent run, request, workflow, or operation before you instrument individual tool and LLM calls. +Use this guide when you want NeMo Relay to identify one agent run, request, workflow, or operation before you instrument individual tool and LLM calls. ## What You Build @@ -51,25 +51,25 @@ The examples below create one `agent-run` scope and emit two marks. :sync: python ```python -import nemo_flow +import nemo_relay def log_event(event) -> None: print(f"{event.kind} {event.name}") -nemo_flow.subscribers.register("scope-check", log_event) +nemo_relay.subscribers.register("scope-check", log_event) try: - with nemo_flow.scope.scope( + with nemo_relay.scope.scope( "agent-run", - nemo_flow.ScopeType.Agent, + nemo_relay.ScopeType.Agent, input={"request_id": "req-123"}, ) as handle: - nemo_flow.scope.event("planning-started", handle=handle, data={"step": 1}) - nemo_flow.scope.event("planning-finished", handle=handle, data={"step": 2}) + nemo_relay.scope.event("planning-started", handle=handle, data={"step": 1}) + nemo_relay.scope.event("planning-finished", handle=handle, data={"step": 2}) finally: - nemo_flow.subscribers.deregister("scope-check") + nemo_relay.subscribers.deregister("scope-check") ``` ::: @@ -83,7 +83,7 @@ const { event, registerSubscriber, withScope, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); async function main() { registerSubscriber("scope-check", (runtimeEvent) => { @@ -120,10 +120,10 @@ main().catch((error) => { :sync: rust ```rust -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ self, EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType, }; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; use serde_json::json; use std::sync::Arc; diff --git a/docs/instrument-applications/advanced-guide.md b/docs/instrument-applications/advanced-guide.md index a2d447b96..e350e3f14 100644 --- a/docs/instrument-applications/advanced-guide.md +++ b/docs/instrument-applications/advanced-guide.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Add Middleware -Use this guide when instrumentation is working and you want NeMo Flow to enforce policy, transform requests, wrap execution, or sanitize observability payloads around tool and LLM calls. +Use this guide when instrumentation is working and you want NeMo Relay to enforce policy, transform requests, wrap execution, or sanitize observability payloads around tool and LLM calls. ## What You Build @@ -18,7 +18,7 @@ You will add middleware to an instrumented application and verify that it runs i ## Before You Start -Complete [Instrument a Tool Call](instrument-tool-call.md) or [Instrument an LLM Call](instrument-llm-call.md). Middleware only runs when the call goes through a NeMo Flow managed lifecycle API. +Complete [Instrument a Tool Call](instrument-tool-call.md) or [Instrument an LLM Call](instrument-llm-call.md). Middleware only runs when the call goes through a NeMo Relay managed lifecycle API. ## Choose the Middleware Type @@ -51,7 +51,7 @@ This example adds three behaviors around a `search` tool: ```python import time -import nemo_flow +import nemo_relay def redact_api_key(tool_name, args): @@ -76,9 +76,9 @@ async def measure_tool(tool_name, args, next_call): print(f"{tool_name} completed in {elapsed_ms} ms") -nemo_flow.guardrails.register_tool_sanitize_request("search.redact_api_key", 10, redact_api_key) -nemo_flow.guardrails.register_tool_conditional_execution("search.require_query", 20, require_query) -nemo_flow.intercepts.register_tool_execution("search.measure", 30, measure_tool) +nemo_relay.guardrails.register_tool_sanitize_request("search.redact_api_key", 10, redact_api_key) +nemo_relay.guardrails.register_tool_conditional_execution("search.require_query", 20, require_query) +nemo_relay.intercepts.register_tool_execution("search.measure", 30, measure_tool) ``` ::: @@ -90,7 +90,7 @@ const { registerToolConditionalExecutionGuardrail, registerToolExecutionIntercept, registerToolSanitizeRequestGuardrail, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); registerToolSanitizeRequestGuardrail("search.redact_api_key", 10, (_toolName, args) => { if (!args.api_key) { @@ -118,7 +118,7 @@ registerToolExecutionIntercept("search.measure", 30, async (args, next) => { :sync: rust ```rust -use nemo_flow::api::registry::{ +use nemo_relay::api::registry::{ register_tool_conditional_execution_guardrail, register_tool_execution_intercept, register_tool_sanitize_request_guardrail, @@ -181,7 +181,7 @@ Use global middleware for process-wide behavior, such as organization-wide redac ## Middleware Registration Families -NeMo Flow exposes the same core middleware families for tools and LLMs: +NeMo Relay exposes the same core middleware families for tools and LLMs: | Family | Tool Registration | LLM Registration | Changes Real Execution | |---|---|---|---| @@ -194,7 +194,7 @@ NeMo Flow exposes the same core middleware families for tools and LLMs: Sanitize guardrails affect only the payload recorded on emitted events. Request intercepts affect the real request that reaches the tool or provider. Execution intercepts wrap the callback itself and are only available when the invocation uses managed execution. -Scope-local variants are available through `nemo_flow.scope_local.register_*`, Node.js `scopeRegister*` helpers, and Rust `scope_register_*` functions. +Scope-local variants are available through `nemo_relay.scope_local.register_*`, Node.js `scopeRegister*` helpers, and Rust `scope_register_*` functions. ## Validate the Middleware diff --git a/docs/instrument-applications/code-examples.md b/docs/instrument-applications/code-examples.md index 7b138b59f..c1a2abb9e 100644 --- a/docs/instrument-applications/code-examples.md +++ b/docs/instrument-applications/code-examples.md @@ -33,13 +33,13 @@ Python accepts timezone-aware `datetime` values, Node.js and WebAssembly accept :sync: python ```python -import nemo_flow +import nemo_relay -handle = nemo_flow.tools.call("search", {"query": "weather"}, data={"attempt": 1}) +handle = nemo_relay.tools.call("search", {"query": "weather"}, data={"attempt": 1}) try: result = {"hits": 2} finally: - nemo_flow.tools.call_end(handle, result) + nemo_relay.tools.call_end(handle, result) ``` ::: @@ -47,7 +47,7 @@ finally: :sync: node ```ts -import { toolCall, toolCallEnd } from 'nemo-flow-node'; +import { toolCall, toolCallEnd } from 'nemo-relay-node'; const handle = toolCall('search', { query: 'weather' }, null, null, { attempt: 1 }, null, null); const result = { hits: 2 }; @@ -59,7 +59,7 @@ toolCallEnd(handle, result, null, null); :sync: rust ```rust -use nemo_flow::api::tool::{tool_call, tool_call_end, ToolCallEndParams, ToolCallParams}; +use nemo_relay::api::tool::{tool_call, tool_call_end, ToolCallEndParams, ToolCallParams}; use serde_json::json; let handle = tool_call( @@ -83,7 +83,7 @@ tool_call_end( ## Managed LLM Execution -Use managed execution when NeMo Flow should run the full middleware pipeline around the provider call. +Use managed execution when NeMo Relay should run the full middleware pipeline around the provider call. ::::{tab-set} :sync-group: language @@ -92,8 +92,8 @@ Use managed execution when NeMo Flow should run the full middleware pipeline aro :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest request = LLMRequest({}, {"messages": [{"role": "user", "content": "hello"}]}) @@ -102,7 +102,7 @@ async def invoke(req: LLMRequest): return {"text": "hi", "request": req.content} -response = await nemo_flow.llm.execute( +response = await nemo_relay.llm.execute( "demo-provider", request, invoke, @@ -115,7 +115,7 @@ response = await nemo_flow.llm.execute( :sync: node ```ts -import { LlmRequest, llmCallExecute } from 'nemo-flow-node'; +import { LlmRequest, llmCallExecute } from 'nemo-relay-node'; const request = new LlmRequest({}, { messages: [{ role: 'user', content: 'hello' }] }); @@ -136,7 +136,7 @@ const response = await llmCallExecute( :sync: rust ```rust -use nemo_flow::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; +use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; use serde_json::json; use std::sync::Arc; @@ -173,8 +173,8 @@ Use the streaming helper when subscribers need chunk collection plus one final r ```python from dataclasses import dataclass -from nemo_flow import LLMRequest -from nemo_flow.typed import DataclassCodec, llm_stream_execute +from nemo_relay import LLMRequest +from nemo_relay.typed import DataclassCodec, llm_stream_execute @dataclass @@ -211,8 +211,8 @@ stream = await llm_stream_execute( :sync: node ```ts -import { LlmRequest } from 'nemo-flow-node'; -import { typedLlmStreamExecute, type Codec } from 'nemo-flow-node/typed'; +import { LlmRequest } from 'nemo-relay-node'; +import { typedLlmStreamExecute, type Codec } from 'nemo-relay-node/typed'; type Chunk = { delta: string }; type FinalResponse = { text: string }; @@ -247,7 +247,7 @@ const stream = await typedLlmStreamExecute( :sync: rust ```rust -use nemo_flow::api::llm::{ +use nemo_relay::api::llm::{ llm_stream_call_execute, LlmAttributes, LlmRequest, LlmStreamCallExecuteParams, }; use serde_json::json; @@ -286,15 +286,15 @@ These helpers are useful when framework code cannot use managed execution but st :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest -tool_args = nemo_flow.tools.request_intercepts("search", {"query": "weather"}) -nemo_flow.tools.conditional_execution("search", tool_args) +tool_args = nemo_relay.tools.request_intercepts("search", {"query": "weather"}) +nemo_relay.tools.conditional_execution("search", tool_args) llm_request = LLMRequest({}, {"messages": [{"role": "user", "content": "hello"}]}) -llm_request = nemo_flow.llm.request_intercepts("demo-provider", llm_request) -nemo_flow.llm.conditional_execution(llm_request) +llm_request = nemo_relay.llm.request_intercepts("demo-provider", llm_request) +nemo_relay.llm.conditional_execution(llm_request) ``` ::: @@ -308,7 +308,7 @@ import { llmRequestIntercepts, toolConditionalExecution, toolRequestIntercepts, -} from 'nemo-flow-node'; +} from 'nemo-relay-node'; const toolArgs = await toolRequestIntercepts('search', { query: 'weather' }); await toolConditionalExecution('search', toolArgs); @@ -323,8 +323,8 @@ await llmConditionalExecution(rewritten); :sync: rust ```rust -use nemo_flow::api::llm::{llm_conditional_execution, llm_request_intercepts, LlmRequest}; -use nemo_flow::api::tool::{tool_conditional_execution, tool_request_intercepts}; +use nemo_relay::api::llm::{llm_conditional_execution, llm_request_intercepts, LlmRequest}; +use nemo_relay::api::tool::{tool_conditional_execution, tool_request_intercepts}; use serde_json::json; let tool_args = tool_request_intercepts("search", json!({"query": "weather"}))?; @@ -354,15 +354,15 @@ Use normal scope helpers first. Reach for explicit stack helpers only when work ```python from concurrent.futures import ThreadPoolExecutor -import nemo_flow +import nemo_relay -with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): - nemo_flow.scope.event("started", data={"ok": True}) - shared = nemo_flow.propagate_scope_to_thread() +with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): + nemo_relay.scope.event("started", data={"ok": True}) + shared = nemo_relay.propagate_scope_to_thread() def worker() -> None: - nemo_flow.set_thread_scope_stack(shared) - nemo_flow.scope.event("worker-ran") + nemo_relay.set_thread_scope_stack(shared) + nemo_relay.scope.event("worker-ran") with ThreadPoolExecutor() as pool: pool.submit(worker).result() @@ -373,7 +373,7 @@ with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): :sync: node ```ts -import { ScopeType, createScopeStack, event, setThreadScopeStack, withScope } from 'nemo-flow-node'; +import { ScopeType, createScopeStack, event, setThreadScopeStack, withScope } from 'nemo-relay-node'; const workerStack = createScopeStack(); setThreadScopeStack(workerStack); @@ -388,8 +388,8 @@ await withScope('request', ScopeType.Agent, async (handle) => { :sync: rust ```rust -use nemo_flow::api::runtime::{create_scope_stack, set_thread_scope_stack, TASK_SCOPE_STACK}; -use nemo_flow::api::scope::{event, EmitMarkEventParams}; +use nemo_relay::api::runtime::{create_scope_stack, set_thread_scope_stack, TASK_SCOPE_STACK}; +use nemo_relay::api::scope::{event, EmitMarkEventParams}; use serde_json::json; let stack = create_scope_stack(); @@ -401,7 +401,7 @@ TASK_SCOPE_STACK std::thread::spawn(move || { set_thread_scope_stack(stack); - // NeMo Flow calls in this thread attach to the same explicit stack. + // NeMo Relay calls in this thread attach to the same explicit stack. }) .join() .unwrap(); @@ -423,10 +423,10 @@ The runtime exposes the same registration families for tool and LLM calls: Every family also has a scope-local surface: -- Python: `nemo_flow.scope_local.register_*` +- Python: `nemo_relay.scope_local.register_*` - Node.js: `scopeRegister*` - Rust: middleware `scope_register_*` functions under - `nemo_flow::api::registry`; subscriber scope registration under - `nemo_flow::api::subscriber` + `nemo_relay::api::registry`; subscriber scope registration under + `nemo_relay::api::subscriber` Use [Add Middleware](advanced-guide.md) for an end-to-end policy example and [API Reference](../reference/api/index.md) for symbol-level details. diff --git a/docs/instrument-applications/instrument-llm-call.md b/docs/instrument-applications/instrument-llm-call.md index f3c4fc185..936296892 100644 --- a/docs/instrument-applications/instrument-llm-call.md +++ b/docs/instrument-applications/instrument-llm-call.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Instrument an LLM Call -Use this guide when you own the model-provider callback and want NeMo Flow to emit lifecycle events, apply LLM middleware, and preserve the active agent scope around the call. +Use this guide when you own the model-provider callback and want NeMo Relay to emit lifecycle events, apply LLM middleware, and preserve the active agent scope around the call. ## What You Build @@ -28,11 +28,11 @@ Complete one binding Quick Start guide first: Create a scope for the active request or agent run before adding LLM instrumentation. If you have not done that yet, start with [Adding Scopes and Marks](adding-scopes-and-marks.md). -The request and response payloads must be JSON-compatible. If your provider SDK uses clients, streams, callbacks, or other opaque objects, keep those objects in the provider callback and pass only a serializable request projection into NeMo Flow. +The request and response payloads must be JSON-compatible. If your provider SDK uses clients, streams, callbacks, or other opaque objects, keep those objects in the provider callback and pass only a serializable request projection into NeMo Relay. ## Integration Pattern -Follow these steps to route the provider invocation through NeMo Flow: +Follow these steps to route the provider invocation through NeMo Relay: 1. Identify the stable provider invocation boundary in your application. 2. Create or inherit a scope for the current agent run, request, or workflow. @@ -55,14 +55,14 @@ The examples below wrap a demo provider callback and print emitted events. ```python import asyncio -import nemo_flow +import nemo_relay def log_event(event) -> None: print(f"{event.kind} {event.name}") -async def call_provider(request: nemo_flow.LLMRequest): +async def call_provider(request: nemo_relay.LLMRequest): return { "text": "hello", "messages": request.content["messages"], @@ -70,15 +70,15 @@ async def call_provider(request: nemo_flow.LLMRequest): async def main() -> None: - nemo_flow.subscribers.register("llm-check", log_event) + nemo_relay.subscribers.register("llm-check", log_event) try: - with nemo_flow.scope.scope("agent-run", nemo_flow.ScopeType.Agent) as handle: - request = nemo_flow.LLMRequest( + with nemo_relay.scope.scope("agent-run", nemo_relay.ScopeType.Agent) as handle: + request = nemo_relay.LLMRequest( {}, {"messages": [{"role": "user", "content": "hello"}]}, ) - result = await nemo_flow.llm.execute( + result = await nemo_relay.llm.execute( "demo-provider", request, call_provider, @@ -87,7 +87,7 @@ async def main() -> None: ) print(result) finally: - nemo_flow.subscribers.deregister("llm-check") + nemo_relay.subscribers.deregister("llm-check") asyncio.run(main()) @@ -106,7 +106,7 @@ const { llmCallExecute, registerSubscriber, withScope, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); async function main() { registerSubscriber("llm-check", (event) => { @@ -152,11 +152,11 @@ main().catch((error) => { :sync: rust ```rust -use nemo_flow::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; -use nemo_flow::api::scope::{ +use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; +use nemo_relay::api::scope::{ self, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType, }; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; use serde_json::json; use std::sync::Arc; diff --git a/docs/instrument-applications/instrument-tool-call.md b/docs/instrument-applications/instrument-tool-call.md index dc8b0f3df..8c8a821a6 100644 --- a/docs/instrument-applications/instrument-tool-call.md +++ b/docs/instrument-applications/instrument-tool-call.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Instrument a Tool Call -Use this guide when you have an application tool callback and want NeMo Flow to emit lifecycle events, apply middleware, and preserve the active agent scope around the call. +Use this guide when you have an application tool callback and want NeMo Relay to emit lifecycle events, apply middleware, and preserve the active agent scope around the call. ## What You Build @@ -53,7 +53,7 @@ The examples below wrap a `search` callback and print emitted events. ```python import asyncio -import nemo_flow +import nemo_relay def log_event(event) -> None: @@ -63,16 +63,16 @@ def log_event(event) -> None: async def search(args): return { "query": args["query"], - "hits": [{"title": "NeMo Flow"}], + "hits": [{"title": "NeMo Relay"}], } async def main() -> None: - nemo_flow.subscribers.register("instrumentation-check", log_event) + nemo_relay.subscribers.register("instrumentation-check", log_event) try: - with nemo_flow.scope.scope("agent-run", nemo_flow.ScopeType.Agent) as handle: - result = await nemo_flow.tools.execute( + with nemo_relay.scope.scope("agent-run", nemo_relay.ScopeType.Agent) as handle: + result = await nemo_relay.tools.execute( "search", {"query": "runtime instrumentation"}, search, @@ -80,7 +80,7 @@ async def main() -> None: ) print(result) finally: - nemo_flow.subscribers.deregister("instrumentation-check") + nemo_relay.subscribers.deregister("instrumentation-check") asyncio.run(main()) @@ -97,7 +97,7 @@ const { registerSubscriber, toolCallExecute, withScope, -} = require("nemo-flow-node"); +} = require("nemo-relay-node"); async function main() { registerSubscriber("instrumentation-check", (event) => { @@ -111,7 +111,7 @@ async function main() { { query: "runtime instrumentation" }, async (args) => ({ query: args.query, - hits: [{ title: "NeMo Flow" }], + hits: [{ title: "NeMo Relay" }], }), handle, null, @@ -137,11 +137,11 @@ main().catch((error) => { :sync: rust ```rust -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ self, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType, }; -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::api::tool::{tool_call_execute, ToolCallExecuteParams}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::api::tool::{tool_call_execute, ToolCallExecuteParams}; use serde_json::json; use std::sync::Arc; @@ -171,7 +171,7 @@ async fn main() -> Result<(), Box> { Box::pin(async move { Ok(json!({ "query": args["query"], - "hits": [{"title": "NeMo Flow"}] + "hits": [{"title": "NeMo Relay"}] })) }) })) diff --git a/docs/integrate-frameworks/about.md b/docs/integrate-frameworks/about.md index c131928bc..b1bb816d0 100644 --- a/docs/integrate-frameworks/about.md +++ b/docs/integrate-frameworks/about.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 # About Use this section when an agent framework, orchestration layer, SDK, or provider -adapter owns the tool and LLM call sites that need NeMo Flow instrumentation. +adapter owns the tool and LLM call sites that need NeMo Relay instrumentation. Framework integrations differ from direct application instrumentation because the integration often does not own the full invocation. A framework may control @@ -22,10 +22,10 @@ intercept helpers, or mark events. Use these signals to decide whether this documentation path matches your current task. -- Maintain a framework integration for NeMo Flow +- Maintain a framework integration for NeMo Relay - Need to instrument calls without rewriting framework internals - Need to handle provider-specific request or response payloads -- Need to keep non-serializable framework objects outside NeMo Flow payloads +- Need to keep non-serializable framework objects outside NeMo Relay payloads - Are building or reviewing third-party integration patches If you own the application call sites directly, use [Instrument Applications](../instrument-applications/about.md) first. @@ -37,7 +37,7 @@ LangGraph, Deep Agents, or OpenClaw, start with Use these guide links to move from the overview into task-specific instructions. -- [Adding Scopes](adding-scopes.md) shows how framework request and run hooks become NeMo Flow ownership boundaries. +- [Adding Scopes](adding-scopes.md) shows how framework request and run hooks become NeMo Relay ownership boundaries. - [Wrap Tool Calls](wrap-tool-calls.md) explains where to place managed tool wrappers and tool lifecycle fallbacks. - [Wrap LLM Calls](wrap-llm-calls.md) explains where to place managed provider wrappers, model names, streaming behavior, and LLM lifecycle fallbacks. - [Handle Non-Serializable Data](non-serializable-data.md) shows how to keep clients, streams, callbacks, and SDK objects outside JSON payloads. @@ -47,7 +47,7 @@ Use these guide links to move from the overview into task-specific instructions. - [Code Examples](code-examples.md) collects fallback APIs, mark events, and repository patch workflow examples. For coding-agent hook and LLM gateway observability, use -[NeMo Flow CLI](../nemo-flow-cli/about.md). That section covers Claude Code, +[NeMo Relay CLI](../nemo-relay-cli/about.md). That section covers Claude Code, Codex, Cursor, and Hermes Agent support. Start by identifying the framework's stable tool and LLM boundaries. Prefer diff --git a/docs/integrate-frameworks/adding-scopes.md b/docs/integrate-frameworks/adding-scopes.md index 87525ef7c..ba015b361 100644 --- a/docs/integrate-frameworks/adding-scopes.md +++ b/docs/integrate-frameworks/adding-scopes.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Adding Scopes -Use this guide when a framework needs a durable NeMo Flow ownership boundary for one request, agent run, workflow, or framework task. +Use this guide when a framework needs a durable NeMo Relay ownership boundary for one request, agent run, workflow, or framework task. ## What You Build -You will map framework start and end hooks to NeMo Flow scope start and end events. Tool and LLM wrappers can then attach child calls to that active scope, subscribers can group events by root scope UUID, and adaptive components can reason about complete request trajectories instead of isolated calls. +You will map framework start and end hooks to NeMo Relay scope start and end events. Tool and LLM wrappers can then attach child calls to that active scope, subscribers can group events by root scope UUID, and adaptive components can reason about complete request trajectories instead of isolated calls. ## Why You Should Add Scopes @@ -29,7 +29,7 @@ Prefer a wrapper or context manager when the framework gives you control around The scope start hook should: -- Create one NeMo Flow scope for the framework request or agent run +- Create one NeMo Relay scope for the framework request or agent run - Store the returned handle in framework request state - Include only JSON-compatible request identifiers, tenant identifiers, or safe summary input @@ -47,23 +47,23 @@ The scope end hook should: :sync: python ```python -import nemo_flow +import nemo_relay def on_request_start(request_state, request_id: str) -> None: - request_state.nemo_flow_scope = nemo_flow.scope.push( + request_state.nemo_relay_scope = nemo_relay.scope.push( "framework-request", - nemo_flow.ScopeType.Agent, + nemo_relay.ScopeType.Agent, input={"request_id": request_id}, ) def on_request_end(request_state, status: str) -> None: - handle = request_state.nemo_flow_scope + handle = request_state.nemo_relay_scope try: - nemo_flow.scope.pop(handle, output={"status": status}) + nemo_relay.scope.pop(handle, output={"status": status}) finally: - request_state.nemo_flow_scope = None + request_state.nemo_relay_scope = None ``` ::: @@ -71,14 +71,14 @@ def on_request_end(request_state, status: str) -> None: :sync: node ```ts -import { popScope, pushScope, ScopeType, type ScopeHandle } from 'nemo-flow-node'; +import { popScope, pushScope, ScopeType, type ScopeHandle } from 'nemo-relay-node'; type RequestState = { - nemoFlowScope?: ScopeHandle; + nemoRelayScope?: ScopeHandle; }; export function onRequestStart(state: RequestState, requestId: string): void { - state.nemoFlowScope = pushScope( + state.nemoRelayScope = pushScope( 'framework-request', ScopeType.Agent, null, @@ -90,7 +90,7 @@ export function onRequestStart(state: RequestState, requestId: string): void { } export function onRequestEnd(state: RequestState, status: string): void { - const handle = state.nemoFlowScope; + const handle = state.nemoRelayScope; if (!handle) { return; } @@ -98,7 +98,7 @@ export function onRequestEnd(state: RequestState, status: string): void { try { popScope(handle, { status }); } finally { - state.nemoFlowScope = undefined; + state.nemoRelayScope = undefined; } } ``` @@ -108,13 +108,13 @@ export function onRequestEnd(state: RequestState, status: string): void { :sync: rust ```rust -use nemo_flow::api::scope::{ +use nemo_relay::api::scope::{ self, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeHandle, ScopeType, }; use serde_json::json; struct RequestState { - nemo_flow_scope: Option, + nemo_relay_scope: Option, } fn on_request_start(state: &mut RequestState, request_id: &str) -> anyhow::Result<()> { @@ -126,12 +126,12 @@ fn on_request_start(state: &mut RequestState, request_id: &str) -> anyhow::Resul .input(json!({"request_id": request_id})) .build(), )?; - state.nemo_flow_scope = Some(handle); + state.nemo_relay_scope = Some(handle); Ok(()) } fn on_request_end(state: &mut RequestState, status: &str) -> anyhow::Result<()> { - if let Some(handle) = state.nemo_flow_scope.take() { + if let Some(handle) = state.nemo_relay_scope.take() { scope::pop_scope( PopScopeParams::builder() .handle_uuid(&handle.uuid) diff --git a/docs/integrate-frameworks/code-examples.md b/docs/integrate-frameworks/code-examples.md index 9703c2085..a7d4d2a36 100644 --- a/docs/integrate-frameworks/code-examples.md +++ b/docs/integrate-frameworks/code-examples.md @@ -25,7 +25,7 @@ Choose the highest option your framework boundary supports: 4. Standalone request-intercept helpers. 5. Mark events for milestones that are not full tool or LLM calls. -Managed execution wrappers give NeMo Flow the most complete lifecycle: middleware order, parent-child scope relationships, request and response event payloads, execution intercepts, and subscriber visibility. Fallback helpers are useful when the framework owns the real callback internally. +Managed execution wrappers give NeMo Relay the most complete lifecycle: middleware order, parent-child scope relationships, request and response event payloads, execution intercepts, and subscriber visibility. Fallback helpers are useful when the framework owns the real callback internally. ## Managed Execution Wrappers @@ -33,9 +33,9 @@ Use managed wrappers when the framework exposes a stable callable boundary. | Surface | Python | Node.js | Rust | |---|---|---|---| -| Tool execute | `nemo_flow.tools.execute(...)` | `toolCallExecute(...)` | `nemo_flow::api::tool::tool_call_execute` | -| LLM execute | `nemo_flow.llm.execute(...)` | `llmCallExecute(...)` | `nemo_flow::api::llm::llm_call_execute` | -| LLM stream execute | `nemo_flow.typed.llm_stream_execute(...)` | `typedLlmStreamExecute(...)` | `nemo_flow::api::llm::llm_stream_call_execute` | +| Tool execute | `nemo_relay.tools.execute(...)` | `toolCallExecute(...)` | `nemo_relay::api::tool::tool_call_execute` | +| LLM execute | `nemo_relay.llm.execute(...)` | `llmCallExecute(...)` | `nemo_relay::api::llm::llm_call_execute` | +| LLM stream execute | `nemo_relay.typed.llm_stream_execute(...)` | `typedLlmStreamExecute(...)` | `nemo_relay::api::llm::llm_stream_call_execute` | ## Fallback: Explicit API Calls @@ -55,25 +55,25 @@ What you lose from managed execution wrappers: :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest def framework_tool_started(name: str, args: dict): - return nemo_flow.tools.call(name, args) + return nemo_relay.tools.call(name, args) def framework_tool_finished(handle, result: dict) -> None: - nemo_flow.tools.call_end(handle, result) + nemo_relay.tools.call_end(handle, result) def framework_llm_started(provider: str, payload: dict): request = LLMRequest({}, payload) - return nemo_flow.llm.call(provider, request, model_name=payload.get("model")) + return nemo_relay.llm.call(provider, request, model_name=payload.get("model")) def framework_llm_finished(handle, response: dict) -> None: - nemo_flow.llm.call_end(handle, response) + nemo_relay.llm.call_end(handle, response) ``` ::: @@ -81,7 +81,7 @@ def framework_llm_finished(handle, response: dict) -> None: :sync: node ```ts -import { LlmRequest, llmCall, llmCallEnd, toolCall, toolCallEnd } from 'nemo-flow-node'; +import { LlmRequest, llmCall, llmCallEnd, toolCall, toolCallEnd } from 'nemo-relay-node'; export function frameworkToolStarted(name: string, args: unknown) { return toolCall(name, args, null, null, null, null, null); @@ -106,8 +106,8 @@ export function frameworkLlmFinished(handle: unknown, response: unknown): void { :sync: rust ```rust -use nemo_flow::api::llm::{llm_call, llm_call_end, LlmCallEndParams, LlmCallParams, LlmRequest}; -use nemo_flow::api::tool::{tool_call, tool_call_end, ToolCallEndParams, ToolCallParams}; +use nemo_relay::api::llm::{llm_call, llm_call_end, LlmCallEndParams, LlmCallParams, LlmRequest}; +use nemo_relay::api::tool::{tool_call, tool_call_end, ToolCallEndParams, ToolCallParams}; use serde_json::{json, Value as Json}; let tool_handle = tool_call( @@ -156,11 +156,11 @@ Use conditional-execution helpers when the framework needs an allow-or-block dec :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest -nemo_flow.tools.conditional_execution("search", {"query": "weather"}) -nemo_flow.llm.conditional_execution(LLMRequest({}, {"messages": []})) +nemo_relay.tools.conditional_execution("search", {"query": "weather"}) +nemo_relay.llm.conditional_execution(LLMRequest({}, {"messages": []})) ``` ::: @@ -168,7 +168,7 @@ nemo_flow.llm.conditional_execution(LLMRequest({}, {"messages": []})) :sync: node ```ts -import { LlmRequest, llmConditionalExecution, toolConditionalExecution } from 'nemo-flow-node'; +import { LlmRequest, llmConditionalExecution, toolConditionalExecution } from 'nemo-relay-node'; await toolConditionalExecution('search', { query: 'weather' }); await llmConditionalExecution(new LlmRequest({}, { messages: [] })); @@ -179,8 +179,8 @@ await llmConditionalExecution(new LlmRequest({}, { messages: [] })); :sync: rust ```rust -use nemo_flow::api::llm::{llm_conditional_execution, LlmRequest}; -use nemo_flow::api::tool::tool_conditional_execution; +use nemo_relay::api::llm::{llm_conditional_execution, LlmRequest}; +use nemo_relay::api::tool::tool_conditional_execution; use serde_json::json; tool_conditional_execution("search", &json!({"query": "weather"}))?; @@ -193,7 +193,7 @@ llm_conditional_execution(&request)?; ## Request Intercepts -Use request-intercept helpers when the framework wants NeMo Flow to rewrite arguments or provider requests before the framework invokes its own downstream code. +Use request-intercept helpers when the framework wants NeMo Relay to rewrite arguments or provider requests before the framework invokes its own downstream code. ::::{tab-set} :sync-group: language @@ -202,11 +202,11 @@ Use request-intercept helpers when the framework wants NeMo Flow to rewrite argu :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest -rewritten_args = nemo_flow.tools.request_intercepts("search", {"query": "weather"}) -rewritten_request = nemo_flow.llm.request_intercepts( +rewritten_args = nemo_relay.tools.request_intercepts("search", {"query": "weather"}) +rewritten_request = nemo_relay.llm.request_intercepts( "demo-provider", LLMRequest({}, {"messages": []}), ) @@ -217,7 +217,7 @@ rewritten_request = nemo_flow.llm.request_intercepts( :sync: node ```ts -import { LlmRequest, llmRequestIntercepts, toolRequestIntercepts } from 'nemo-flow-node'; +import { LlmRequest, llmRequestIntercepts, toolRequestIntercepts } from 'nemo-relay-node'; const rewrittenArgs = await toolRequestIntercepts('search', { query: 'weather' }); const rewrittenRequest = await llmRequestIntercepts('demo-provider', new LlmRequest({}, { messages: [] })); @@ -228,8 +228,8 @@ const rewrittenRequest = await llmRequestIntercepts('demo-provider', new LlmRequ :sync: rust ```rust -use nemo_flow::api::llm::{llm_request_intercepts, LlmRequest}; -use nemo_flow::api::tool::tool_request_intercepts; +use nemo_relay::api::llm::{llm_request_intercepts, LlmRequest}; +use nemo_relay::api::tool::tool_request_intercepts; use serde_json::json; let rewritten_args = tool_request_intercepts("search", json!({"query": "weather"}))?; @@ -251,9 +251,9 @@ Use mark events when the framework exposes important milestones but not a full l :sync: python ```python -import nemo_flow +import nemo_relay -nemo_flow.scope.event("scheduler.retry", data={"attempt": 2}) +nemo_relay.scope.event("scheduler.retry", data={"attempt": 2}) ``` ::: @@ -261,7 +261,7 @@ nemo_flow.scope.event("scheduler.retry", data={"attempt": 2}) :sync: node ```ts -import { event } from 'nemo-flow-node'; +import { event } from 'nemo-relay-node'; event('scheduler.retry', null, { attempt: 2 }, null); ``` @@ -271,7 +271,7 @@ event('scheduler.retry', null, { attempt: 2 }, null); :sync: rust ```rust -use nemo_flow::api::scope::{event, EmitMarkEventParams}; +use nemo_relay::api::scope::{event, EmitMarkEventParams}; use serde_json::json; event( @@ -287,7 +287,7 @@ event( ## Sample Third-Party Patch Integrations -NeMo Flow keeps sample third-party integrations as patch sets under `patches/` +NeMo Relay keeps sample third-party integrations as patch sets under `patches/` and pinned upstream checkouts under `third_party/`. For the current OpenClaw end-user integration, use the [OpenClaw Plugin Guide](../integrations/openclaw-plugin.md). @@ -306,12 +306,12 @@ The following table lists maintained patch checkouts: ## Quickstart: Apply Maintained Patches From the repository root, use the wrapper scripts when you want the maintained -NeMo Flow patches applied to the pinned third-party checkouts: +NeMo Relay patches applied to the pinned third-party checkouts: | Script | Purpose | |---|---| | `./scripts/bootstrap-third-party.sh` | Clone pinned third-party upstream checkouts from `third_party/sources.lock`. | -| `./scripts/apply-patches.sh` | Apply NeMo Flow integration patches to third-party checkouts. | +| `./scripts/apply-patches.sh` | Apply NeMo Relay integration patches to third-party checkouts. | | `./scripts/apply-patches.sh --check` | Ensure the patches apply cleanly to all third-party checkouts. | | `./scripts/generate-patches.sh` | Regenerate patch files from local third-party checkout changes. | | `./scripts/build-docs.sh` | Build the documentation site after integration docs change. | diff --git a/docs/integrate-frameworks/non-serializable-data.md b/docs/integrate-frameworks/non-serializable-data.md index 76e745bff..6b4d80405 100644 --- a/docs/integrate-frameworks/non-serializable-data.md +++ b/docs/integrate-frameworks/non-serializable-data.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Handle Non-Serializable Data -Use this guide when a framework exposes SDK clients, streams, callbacks, file handles, or custom classes at the same boundary where you need NeMo Flow instrumentation. +Use this guide when a framework exposes SDK clients, streams, callbacks, file handles, or custom classes at the same boundary where you need NeMo Relay instrumentation. ## What You Build -You will keep non-serializable framework objects in framework-owned storage and pass only stable JSON projections through NeMo Flow middleware and event payloads. +You will keep non-serializable framework objects in framework-owned storage and pass only stable JSON projections through NeMo Relay middleware and event payloads. ## Before You Start @@ -21,21 +21,21 @@ You need: ## The Constraint -NeMo Flow middleware surfaces operate on JSON-compatible data. Frameworks do not always expose tool or model requests in that form. +NeMo Relay middleware surfaces operate on JSON-compatible data. Frameworks do not always expose tool or model requests in that form. ## Recommended Strategies These strategies keep provider and framework data JSON-compatible before it reaches NeMo Flow. -- Convert provider payloads into a stable request shape before NeMo Flow sees them. +- Convert provider payloads into a stable request shape before NeMo Relay sees them. - Preserve opaque framework objects outside the middleware path and pass only the serializable projection into the runtime. -- Store external object references in framework-owned maps keyed by request IDs, not inside NeMo Flow event payloads. +- Store external object references in framework-owned maps keyed by request IDs, not inside NeMo Relay event payloads. - Use typed wrappers for your application boundary, then serialize at the last responsible moment. ## Concrete Projection Pattern -Keep framework objects in your own map, but send only the JSON projection through NeMo Flow. +Keep framework objects in your own map, but send only the JSON projection through NeMo Relay. ::::{tab-set} :sync-group: language @@ -46,7 +46,7 @@ Keep framework objects in your own map, but send only the JSON projection throug ```python from typing import TypedDict -import nemo_flow +import nemo_relay class SearchArgs(TypedDict): @@ -64,11 +64,11 @@ framework_clients["client-1"] = object() async def invoke(args: SearchArgs) -> SearchResult: client = framework_clients[args["client_id"]] - _ = client # framework-owned object stays outside NeMo Flow payloads + _ = client # framework-owned object stays outside NeMo Relay payloads return {"hits": 2} -result = await nemo_flow.tools.execute( +result = await nemo_relay.tools.execute( "search", SearchArgs(client_id="client-1", query="weather"), invoke, @@ -80,7 +80,7 @@ result = await nemo_flow.tools.execute( :sync: node ```ts -import { toolCallExecute } from 'nemo-flow-node'; +import { toolCallExecute } from 'nemo-relay-node'; type SearchArgs = { clientId: string; query: string }; type SearchResult = { hits: number }; @@ -106,7 +106,7 @@ const result = await toolCallExecute( :sync: rust ```rust -use nemo_flow::api::tool::{ToolCallExecuteParams, tool_call_execute}; +use nemo_relay::api::tool::{ToolCallExecuteParams, tool_call_execute}; use serde_json::json; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -164,7 +164,7 @@ observe. ## Practical Workarounds -Use these workarounds when framework data cannot be passed directly through NeMo Flow. +Use these workarounds when framework data cannot be passed directly through NeMo Relay. - Replace large objects with IDs and look them up later. - Emit summarized metadata instead of full request bodies. diff --git a/docs/integrate-frameworks/provider-codecs.md b/docs/integrate-frameworks/provider-codecs.md index b1ebc31f5..1dbd8c417 100644 --- a/docs/integrate-frameworks/provider-codecs.md +++ b/docs/integrate-frameworks/provider-codecs.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Provider Codecs -Use this guide when a framework integration needs NeMo Flow middleware, intercepts, or subscribers to reason about provider-specific LLM payloads through a stable annotated shape. +Use this guide when a framework integration needs NeMo Relay middleware, intercepts, or subscribers to reason about provider-specific LLM payloads through a stable annotated shape. ## What You Build @@ -26,24 +26,24 @@ You need: ## What Provider Codecs Are -A provider codec is a pure data translator at the NeMo Flow LLM boundary. +A provider codec is a pure data translator at the NeMo Relay LLM boundary. - An LLM request codec converts a raw provider request into a normalized annotated request, then encodes any annotated edits back into the original provider request. - An LLM response codec converts a raw provider response into a normalized response annotation for lifecycle events. -Provider codecs let framework code keep using provider-native payloads while NeMo Flow middleware works against a shared annotated model. For application-facing type conversion, use [Using Codecs](using-codecs.md). +Provider codecs let framework code keep using provider-native payloads while NeMo Relay middleware works against a shared annotated model. For application-facing type conversion, use [Using Codecs](using-codecs.md). ## How Provider Codecs Work When a managed LLM call has a request codec: -1. NeMo Flow calls `decode` before LLM request intercepts run. +1. NeMo Relay calls `decode` before LLM request intercepts run. 2. Request intercepts receive both the raw request and the annotated request. 3. Intercepts may edit the raw request, the annotated request, or both. -4. NeMo Flow calls `encode` to merge the annotated request back into the original raw request. +4. NeMo Relay calls `encode` to merge the annotated request back into the original raw request. 5. Execution intercepts and the provider callback receive the encoded provider request. -When a managed LLM call has a response codec, NeMo Flow decodes the raw provider response for observability and attaches the result to the emitted LLM end event. The response codec does not rewrite the value returned to the application. Use [Provider Response Codecs](provider-response-codecs.md) for response-only behavior and custom response codec examples. +When a managed LLM call has a response codec, NeMo Relay decodes the raw provider response for observability and attaches the result to the emitted LLM end event. The response codec does not rewrite the value returned to the application. Use [Provider Response Codecs](provider-response-codecs.md) for response-only behavior and custom response codec examples. Codec implementations should preserve fields they do not understand. Treat `encode` as a merge operation over the original provider payload, not as a full replacement. @@ -66,9 +66,9 @@ The built-in provider codecs expose the same core methods: | Codec | Python Import | Node.js Import | Methods | |---|---|---|---| -| OpenAI Chat | `nemo_flow.codecs.OpenAIChatCodec` | `OpenAIChatCodec` from `nemo-flow-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | -| OpenAI Responses | `nemo_flow.codecs.OpenAIResponsesCodec` | `OpenAIResponsesCodec` from `nemo-flow-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | -| Anthropic Messages | `nemo_flow.codecs.AnthropicMessagesCodec` | `AnthropicMessagesCodec` from `nemo-flow-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | +| OpenAI Chat | `nemo_relay.codecs.OpenAIChatCodec` | `OpenAIChatCodec` from `nemo-relay-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | +| OpenAI Responses | `nemo_relay.codecs.OpenAIResponsesCodec` | `OpenAIResponsesCodec` from `nemo-relay-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | +| Anthropic Messages | `nemo_relay.codecs.AnthropicMessagesCodec` | `AnthropicMessagesCodec` from `nemo-relay-node` | `decode`, `encode`, `decode_response` / `decodeResponse` | Choose the provider codec that matches the payload shape the framework already sends to the provider. Do not translate to a different provider shape only to make the codec fit. @@ -83,9 +83,9 @@ This example uses a request intercept to edit the normalized request. The codec :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest -from nemo_flow.codecs import OpenAIChatCodec +import nemo_relay +from nemo_relay import LLMRequest +from nemo_relay.codecs import OpenAIChatCodec def add_system_message(_name, request, annotated): @@ -99,7 +99,7 @@ def add_system_message(_name, request, annotated): return request, annotated -nemo_flow.intercepts.register_llm_request( +nemo_relay.intercepts.register_llm_request( "framework.add_system_message", 10, False, @@ -127,7 +127,7 @@ request = LLMRequest( }, ) -response = await nemo_flow.llm.execute( +response = await nemo_relay.llm.execute( "openai-chat", request, invoke_provider, @@ -145,11 +145,11 @@ response = await nemo_flow.llm.execute( import { OpenAIChatCodec, registerLlmRequestIntercept, -} from 'nemo-flow-node'; +} from 'nemo-relay-node'; import { JsonPassthrough, typedLlmExecute, -} from 'nemo-flow-node/typed'; +} from 'nemo-relay-node/typed'; registerLlmRequestIntercept( 'framework.add_system_message', @@ -207,9 +207,9 @@ const response = await typedLlmExecute( :sync: rust ```rust -use nemo_flow::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; -use nemo_flow::codec::openai_chat::OpenAIChatCodec; -use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec}; +use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; +use nemo_relay::codec::openai_chat::OpenAIChatCodec; +use nemo_relay::codec::traits::{LlmCodec, LlmResponseCodec}; use serde_json::json; use std::sync::Arc; @@ -263,8 +263,8 @@ Use a custom codec when a framework uses a payload shape that does not directly :sync: python ```python -from nemo_flow import AnnotatedLLMRequest, LLMRequest -from nemo_flow.codecs import LlmCodec +from nemo_relay import AnnotatedLLMRequest, LLMRequest +from nemo_relay.codecs import LlmCodec class FrameworkChatCodec(LlmCodec): @@ -301,7 +301,7 @@ class FrameworkChatCodec(LlmCodec): :sync: node ```ts -import type { JsonValue, LlmCodec } from 'nemo-flow-node/typed'; +import type { JsonValue, LlmCodec } from 'nemo-relay-node/typed'; type FrameworkRequest = { headers: Record; diff --git a/docs/integrate-frameworks/provider-response-codecs.md b/docs/integrate-frameworks/provider-response-codecs.md index 8322e1cf6..c589bb79a 100644 --- a/docs/integrate-frameworks/provider-response-codecs.md +++ b/docs/integrate-frameworks/provider-response-codecs.md @@ -9,7 +9,7 @@ Use this guide when subscribers, exporters, or diagnostics need a provider-neutr ## What You Build -You will attach a response codec to a managed LLM wrapper so NeMo Flow can decode provider responses into `AnnotatedLLMResponse` data for LLM end events. +You will attach a response codec to a managed LLM wrapper so NeMo Relay can decode provider responses into `AnnotatedLLMResponse` data for LLM end events. Response codecs are observability-only: @@ -66,9 +66,9 @@ shapes. :sync: python ```python -import nemo_flow -from nemo_flow import LLMRequest -from nemo_flow.codecs import OpenAIChatCodec +import nemo_relay +from nemo_relay import LLMRequest +from nemo_relay.codecs import OpenAIChatCodec async def invoke_provider(request: LLMRequest): @@ -86,7 +86,7 @@ async def invoke_provider(request: LLMRequest): codec = OpenAIChatCodec() -response = await nemo_flow.llm.execute( +response = await nemo_relay.llm.execute( "openai-chat", LLMRequest({}, {"model": "gpt-4o-mini", "messages": []}), invoke_provider, @@ -100,8 +100,8 @@ response = await nemo_flow.llm.execute( :sync: node ```ts -import { OpenAIChatCodec } from 'nemo-flow-node'; -import { JsonPassthrough, typedLlmExecute } from 'nemo-flow-node/typed'; +import { OpenAIChatCodec } from 'nemo-relay-node'; +import { JsonPassthrough, typedLlmExecute } from 'nemo-relay-node/typed'; const codec = new OpenAIChatCodec(); @@ -132,9 +132,9 @@ const response = await typedLlmExecute( :sync: rust ```rust -use nemo_flow::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; -use nemo_flow::codec::openai_chat::OpenAIChatCodec; -use nemo_flow::codec::traits::LlmResponseCodec; +use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; +use nemo_relay::codec::openai_chat::OpenAIChatCodec; +use nemo_relay::codec::traits::LlmResponseCodec; use serde_json::json; use std::sync::Arc; @@ -187,7 +187,7 @@ Subscribers can inspect `annotated_response` on LLM end events. The exact event :sync: python ```python -import nemo_flow +import nemo_relay def on_event(event): @@ -200,7 +200,7 @@ def on_event(event): print("usage", annotated.usage) -nemo_flow.subscribers.register("response-debugger", on_event) +nemo_relay.subscribers.register("response-debugger", on_event) ``` ::: @@ -208,7 +208,7 @@ nemo_flow.subscribers.register("response-debugger", on_event) :sync: node ```ts -import { registerSubscriber } from 'nemo-flow-node'; +import { registerSubscriber } from 'nemo-relay-node'; registerSubscriber('response-debugger', (event) => { const annotated = event.category_profile?.annotated_response; @@ -232,7 +232,7 @@ Use a custom response codec when the provider or framework response does not mat In Python, a custom response codec can route to built-in codecs and return their native `AnnotatedLLMResponse` values: ```python -from nemo_flow.codecs import OpenAIChatCodec, OpenAIResponsesCodec +from nemo_relay.codecs import OpenAIChatCodec, OpenAIResponsesCodec class OpenAIRoutingResponseCodec: @@ -249,7 +249,7 @@ class OpenAIRoutingResponseCodec: In Node.js, implement `decodeResponse` and return the normalized response JSON shape: ```ts -import type { JsonValue, LlmResponseCodec } from 'nemo-flow-node/typed'; +import type { JsonValue, LlmResponseCodec } from 'nemo-relay-node/typed'; const frameworkResponseCodec: LlmResponseCodec = { decodeResponse(response: JsonValue): JsonValue { @@ -286,10 +286,10 @@ const frameworkResponseCodec: LlmResponseCodec = { In Rust, implement `LlmResponseCodec` directly: ```rust -use nemo_flow::codec::request::MessageContent; -use nemo_flow::codec::response::{AnnotatedLlmResponse, FinishReason, Usage}; -use nemo_flow::codec::traits::LlmResponseCodec; -use nemo_flow::error::{FlowError, Result}; +use nemo_relay::codec::request::MessageContent; +use nemo_relay::codec::response::{AnnotatedLlmResponse, FinishReason, Usage}; +use nemo_relay::codec::traits::LlmResponseCodec; +use nemo_relay::error::{FlowError, Result}; use serde::Deserialize; use serde_json::{Map, Value as Json}; diff --git a/docs/integrate-frameworks/using-codecs.md b/docs/integrate-frameworks/using-codecs.md index df30adb27..2c1fd76fc 100644 --- a/docs/integrate-frameworks/using-codecs.md +++ b/docs/integrate-frameworks/using-codecs.md @@ -5,14 +5,14 @@ SPDX-License-Identifier: Apache-2.0 # Using Codecs -Use this guide when a framework integration needs typed application values at its public boundary while NeMo Flow still records JSON-compatible payloads. +Use this guide when a framework integration needs typed application values at its public boundary while NeMo Relay still records JSON-compatible payloads. ## What You Build You will choose typed value codecs for framework-facing wrappers so that: - Application code can pass native objects to framework callbacks -- NeMo Flow can emit JSON-compatible lifecycle payloads +- NeMo Relay can emit JSON-compatible lifecycle payloads - Middleware and subscribers receive predictable serialized values - The framework callback still receives the application type it expects @@ -29,14 +29,14 @@ You need: ## What Codecs Are -A typed value codec is a pure data translator at the NeMo Flow boundary. It converts application-facing values to JSON before NeMo Flow emits events or runs JSON-based middleware, then converts JSON back into the type expected by the framework callback or caller. +A typed value codec is a pure data translator at the NeMo Relay boundary. It converts application-facing values to JSON before NeMo Relay emits events or runs JSON-based middleware, then converts JSON back into the type expected by the framework callback or caller. Typed value codecs are different from provider codecs: | Codec Type | Purpose | Common Use | |---|---|---| | Typed value codec | Converts application values to and from JSON. | Dataclasses, Pydantic models, TypeScript object shapes, custom framework types. | -| Provider codec | Converts provider-specific LLM requests and responses to annotated NeMo Flow request or response data. | OpenAI Chat, OpenAI Responses, Anthropic Messages, custom provider payloads. | +| Provider codec | Converts provider-specific LLM requests and responses to annotated NeMo Relay request or response data. | OpenAI Chat, OpenAI Responses, Anthropic Messages, custom provider payloads. | Use this page for typed value codecs. Use [Provider Codecs](provider-codecs.md) when middleware needs normalized LLM messages, tools, model names, generation parameters, or provider response annotations. @@ -44,8 +44,8 @@ Use this page for typed value codecs. Use [Provider Codecs](provider-codecs.md) When a managed typed wrapper receives a codec: -1. The wrapper converts the application input into JSON before entering the NeMo Flow runtime. -2. NeMo Flow emits lifecycle events and runs middleware against JSON-compatible payloads. +1. The wrapper converts the application input into JSON before entering the NeMo Relay runtime. +2. NeMo Relay emits lifecycle events and runs middleware against JSON-compatible payloads. 3. The wrapper converts JSON back into the callback type before invoking framework-owned code when needed. 4. The wrapper converts the callback result back through the result codec before returning to the caller. @@ -73,7 +73,7 @@ from dataclasses import dataclass from pydantic import BaseModel -from nemo_flow.typed import DataclassCodec, JsonPassthrough, PydanticCodec +from nemo_relay.typed import DataclassCodec, JsonPassthrough, PydanticCodec @dataclass @@ -95,7 +95,7 @@ passthrough = JsonPassthrough() :sync: node ```ts -import { JsonPassthrough, type Codec, type JsonValue } from 'nemo-flow-node/typed'; +import { JsonPassthrough, type Codec, type JsonValue } from 'nemo-relay-node/typed'; type SearchArgs = { query: string }; @@ -114,7 +114,7 @@ Use `BestEffortAnyCodec` only at boundary code where strict schemas are unavaila ## Example: Typed Tool Boundary -Use typed value codecs when the framework wants native objects but NeMo Flow should emit JSON payloads. +Use typed value codecs when the framework wants native objects but NeMo Relay should emit JSON payloads. ::::{tab-set} :sync-group: language @@ -125,8 +125,8 @@ Use typed value codecs when the framework wants native objects but NeMo Flow sho ```python from dataclasses import dataclass -import nemo_flow -from nemo_flow.typed import DataclassCodec, JsonPassthrough, tool_execute +import nemo_relay +from nemo_relay.typed import DataclassCodec, JsonPassthrough, tool_execute @dataclass @@ -152,7 +152,7 @@ result = await tool_execute( :sync: node ```ts -import { JsonPassthrough, typedToolExecute, type Codec, type JsonValue } from 'nemo-flow-node/typed'; +import { JsonPassthrough, typedToolExecute, type Codec, type JsonValue } from 'nemo-relay-node/typed'; type SearchArgs = { query: string }; type SearchResult = { echo: string }; diff --git a/docs/integrate-frameworks/wrap-llm-calls.md b/docs/integrate-frameworks/wrap-llm-calls.md index 86b327a49..69df48500 100644 --- a/docs/integrate-frameworks/wrap-llm-calls.md +++ b/docs/integrate-frameworks/wrap-llm-calls.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Wrap LLM Calls -Use this guide when a framework, SDK, or provider adapter owns model invocation and you need NeMo Flow to observe and control those provider calls. +Use this guide when a framework, SDK, or provider adapter owns model invocation and you need NeMo Relay to observe and control those provider calls. ## What You Build -You will place a managed NeMo Flow LLM execution wrapper at the provider boundary. The wrapper emits LLM lifecycle events, runs LLM middleware, attaches the call to the active scope, records the `model_name`, and returns the provider response to the framework. +You will place a managed NeMo Relay LLM execution wrapper at the provider boundary. The wrapper emits LLM lifecycle events, runs LLM middleware, attaches the call to the active scope, records the `model_name`, and returns the provider response to the framework. ## Before You Start @@ -45,8 +45,8 @@ The examples below wrap one provider call and attach it to the active parent sco ```python from typing import TypedDict -import nemo_flow -from nemo_flow import LLMRequest +import nemo_relay +from nemo_relay import LLMRequest class LlmResponse(TypedDict): @@ -55,13 +55,13 @@ class LlmResponse(TypedDict): async def framework_llm(provider_name: str, payload: object) -> LlmResponse: - parent = nemo_flow.scope.get_handle() + parent = nemo_relay.scope.get_handle() request = LLMRequest({}, payload) async def invoke(req: LLMRequest) -> LlmResponse: return {"text": "hi", "request": req.content} - return await nemo_flow.llm.execute( + return await nemo_relay.llm.execute( provider_name, request, invoke, @@ -75,7 +75,7 @@ async def framework_llm(provider_name: str, payload: object) -> LlmResponse: :sync: node ```ts -import { getHandle, LlmRequest, llmCallExecute, type ScopeHandle } from 'nemo-flow-node'; +import { getHandle, LlmRequest, llmCallExecute, type ScopeHandle } from 'nemo-relay-node'; type LlmResponse = { text: string; request: unknown }; @@ -101,8 +101,8 @@ export async function frameworkLlm(providerName: string, payload: unknown): Prom :sync: rust ```rust -use nemo_flow::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; -use nemo_flow::api::scope::get_handle; +use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest}; +use nemo_relay::api::scope::get_handle; use serde_json::json; use std::sync::Arc; @@ -135,7 +135,7 @@ async fn run_provider_call() -> anyhow::Result { ## Streaming Providers -Use the LLM stream execute helper when the framework exposes a stream boundary that NeMo Flow can own. Stream wrappers preserve the same scope and middleware model while letting subscribers observe the completed response after chunks are collected. +Use the LLM stream execute helper when the framework exposes a stream boundary that NeMo Relay can own. Stream wrappers preserve the same scope and middleware model while letting subscribers observe the completed response after chunks are collected. If the framework owns the stream internally, emit explicit start and end lifecycle events around the provider stream and use mark events for retry, queue, and partial-output milestones. @@ -155,8 +155,8 @@ Check these symptoms first when the workflow does not behave as expected. - **The LLM appears outside the request trace**: Pass the active scope handle or run the provider call inside the framework request scope. - **The model name is missing**: Pass `model_name` from the provider payload, model client, or framework run configuration. -- **Request middleware receives provider objects**: Convert provider payloads into `LLMRequest` with JSON-compatible content before calling NeMo Flow. -- **Stream output is incomplete**: Use the stream execute helper when NeMo Flow owns the stream boundary, or emit explicit lifecycle events when it does not. +- **Request middleware receives provider objects**: Convert provider payloads into `LLMRequest` with JSON-compatible content before calling NeMo Relay. +- **Stream output is incomplete**: Use the stream execute helper when NeMo Relay owns the stream boundary, or emit explicit lifecycle events when it does not. ## Next Steps diff --git a/docs/integrate-frameworks/wrap-tool-calls.md b/docs/integrate-frameworks/wrap-tool-calls.md index a12640775..cf2378e9f 100644 --- a/docs/integrate-frameworks/wrap-tool-calls.md +++ b/docs/integrate-frameworks/wrap-tool-calls.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Wrap Tool Calls -Use this guide when a framework, SDK, or orchestration layer owns tool invocation and you need NeMo Flow to observe and control those calls without changing the framework's public behavior. +Use this guide when a framework, SDK, or orchestration layer owns tool invocation and you need NeMo Relay to observe and control those calls without changing the framework's public behavior. ## What You Build -You will place a managed NeMo Flow tool execution wrapper at the framework's stable tool boundary. The wrapper emits tool lifecycle events, runs tool middleware, keeps the tool attached to the active scope, and returns the original tool result to the framework. +You will place a managed NeMo Relay tool execution wrapper at the framework's stable tool boundary. The wrapper emits tool lifecycle events, runs tool middleware, keeps the tool attached to the active scope, and returns the original tool result to the framework. ## Before You Start @@ -30,7 +30,7 @@ Follow this sequence to keep framework work attached to the expected runtime con 4. Keep framework-owned clients, callbacks, streams, and handles outside the emitted JSON payload. 5. Return the tool result exactly as the framework expects. -Managed wrappers are the first choice because NeMo Flow owns the full call boundary. That gives subscribers complete start and end events, lets execution intercepts wrap the real callback, and keeps guardrails and request intercepts in the normal middleware order. +Managed wrappers are the first choice because NeMo Relay owns the full call boundary. That gives subscribers complete start and end events, lets execution intercepts wrap the real callback, and keeps guardrails and request intercepts in the normal middleware order. ## Concrete Tool Example @@ -45,7 +45,7 @@ The examples below wrap one framework tool callback and attach it to the active ```python from typing import TypedDict -import nemo_flow +import nemo_relay class SearchArgs(TypedDict): @@ -58,12 +58,12 @@ class SearchResult(TypedDict): async def framework_tool(tool_name: str, raw_args: SearchArgs) -> SearchResult: - parent = nemo_flow.scope.get_handle() + parent = nemo_relay.scope.get_handle() async def invoke(args: SearchArgs) -> SearchResult: return {"hits": 2, "echo": args} - return await nemo_flow.tools.execute( + return await nemo_relay.tools.execute( tool_name, raw_args, invoke, @@ -76,7 +76,7 @@ async def framework_tool(tool_name: str, raw_args: SearchArgs) -> SearchResult: :sync: node ```ts -import { getHandle, toolCallExecute, type ScopeHandle } from 'nemo-flow-node'; +import { getHandle, toolCallExecute, type ScopeHandle } from 'nemo-relay-node'; type SearchArgs = { query: string }; type SearchResult = { hits: number; echo: SearchArgs }; @@ -101,8 +101,8 @@ export async function frameworkTool(toolName: string, rawArgs: SearchArgs): Prom :sync: rust ```rust -use nemo_flow::api::scope::get_handle; -use nemo_flow::api::tool::{tool_call_execute, ToolCallExecuteParams}; +use nemo_relay::api::scope::get_handle; +use nemo_relay::api::tool::{tool_call_execute, ToolCallExecuteParams}; use serde_json::json; use std::sync::Arc; @@ -149,9 +149,9 @@ Run one framework tool path and check: Check these symptoms first when the workflow does not behave as expected. -- **Tool events appear without parentage**: Pass the active scope handle or ensure the framework tool runs inside a NeMo Flow scope. +- **Tool events appear without parentage**: Pass the active scope handle or ensure the framework tool runs inside a NeMo Relay scope. - **Middleware does not run**: The framework still calls the real tool callback directly. -- **Payload serialization fails**: Project framework objects into JSON-compatible tool arguments and results before NeMo Flow sees them. +- **Payload serialization fails**: Project framework objects into JSON-compatible tool arguments and results before NeMo Relay sees them. - **A fallback emits incomplete spans**: Manual start and end lifecycle calls must use the same handle. ## Next Steps diff --git a/docs/integrations/about.md b/docs/integrations/about.md index 5e43b7b8b..c030b2a0a 100644 --- a/docs/integrations/about.md +++ b/docs/integrations/about.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 # About Use this section when your application already uses a supported framework or -agent harness and you want the maintained NeMo Flow integration path for that +agent harness and you want the maintained NeMo Relay integration path for that surface. Supported integrations are end-user entry points. They use public framework or @@ -28,12 +28,12 @@ Use these guide links to move from the support matrix into setup and usage instructions. - [OpenClaw Plugin Guide](openclaw-plugin.md) covers configuring the OpenClaw - plugin, mapping OpenClaw hooks to NeMo Flow telemetry, and understanding + plugin, mapping OpenClaw hooks to NeMo Relay telemetry, and understanding current LLM replay fidelity boundaries. - [LangChain Integration Guide](langchain.md) covers installing the LangChain - extra and adding NeMo Flow middleware and callbacks to LangChain agents. + extra and adding NeMo Relay middleware and callbacks to LangChain agents. - [LangGraph Integration Guide](langgraph.md) covers installing the LangGraph - extra and adding NeMo Flow callbacks to LangGraph workflows. + extra and adding NeMo Relay callbacks to LangGraph workflows. - [Deep Agents Integration Guide](deepagents.md) covers installing the Deep Agents extra and capturing Deep Agents-specific marks, skills, subagents, and human-in-the-loop lifecycle events. diff --git a/docs/integrations/deepagents.md b/docs/integrations/deepagents.md index 9fd34f754..c56adaaee 100644 --- a/docs/integrations/deepagents.md +++ b/docs/integrations/deepagents.md @@ -3,9 +3,9 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow Deep Agents Integration +# NeMo Relay Deep Agents Integration -Use the `nemo_flow.integrations.deepagents` package to add NeMo Flow +Use the `nemo_relay.integrations.deepagents` package to add NeMo Relay observability to Deep Agents applications through the LangChain and LangGraph integration surfaces that Deep Agents builds on. @@ -21,7 +21,7 @@ Install the Deep Agents integration extra in your application environment. :sync: uv ```bash -uv add "nemo-flow[deepagents]" +uv add "nemo-relay[deepagents]" ``` ::: @@ -29,7 +29,7 @@ uv add "nemo-flow[deepagents]" :sync: pip ```bash -pip install "nemo-flow[deepagents]" +pip install "nemo-relay[deepagents]" ``` ::: @@ -46,7 +46,7 @@ extra too if you want to run the example as written: :sync: uv ```bash -uv add "nemo-flow[deepagents,langchain-nvidia]" +uv add "nemo-relay[deepagents,langchain-nvidia]" ``` ::: @@ -54,7 +54,7 @@ uv add "nemo-flow[deepagents,langchain-nvidia]" :sync: pip ```bash -pip install "nemo-flow[deepagents,langchain-nvidia]" +pip install "nemo-relay[deepagents,langchain-nvidia]" ``` ::: @@ -63,15 +63,15 @@ pip install "nemo-flow[deepagents,langchain-nvidia]" ## Usage Example ```python -import nemo_flow +import nemo_relay from deepagents import create_deep_agent -from nemo_flow.integrations.deepagents import ( - NemoFlowDeepAgentsCallbackHandler, - add_nemo_flow_integration, +from nemo_relay.integrations.deepagents import ( + NemoRelayDeepAgentsCallbackHandler, + add_nemo_relay_integration, ) agent = create_deep_agent( - **add_nemo_flow_integration( + **add_nemo_relay_integration( model="nvidia:nvidia/nemotron-3-nano-30b-a3b", tools=[], skills=["/skills/research/"], @@ -88,10 +88,10 @@ input_payload = { ] } -with nemo_flow.scope.scope("deepagents-request", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("deepagents-request", nemo_relay.ScopeType.Agent): result = agent.invoke( input_payload, - config={"callbacks": [NemoFlowDeepAgentsCallbackHandler()]}, + config={"callbacks": [NemoRelayDeepAgentsCallbackHandler()]}, ) final_message = result["messages"][-1] @@ -100,21 +100,21 @@ print(f"Final response: {final_message.content}") ## Observability -The integration composes the existing NeMo Flow LangChain and LangGraph hooks, +The integration composes the existing NeMo Relay LangChain and LangGraph hooks, then emits Deep Agents-specific marks for configured skills, subagents, and human-in-the-loop lifecycle events. It captures: -- LangChain model and tool calls through NeMo Flow managed execution. +- LangChain model and tool calls through NeMo Relay managed execution. - LangGraph run scopes through callbacks. - Human-in-the-loop interrupt and resume marks. - Configured skills and subagent summaries at agent-run start. -- In-process dictionary-style subagents with the same NeMo Flow middleware, so +- In-process dictionary-style subagents with the same NeMo Relay middleware, so their model and tool calls are captured when Deep Agents invokes them. -Remote graphs or processes still need NeMo Flow instrumentation in that graph +Remote graphs or processes still need NeMo Relay instrumentation in that graph or process to capture their internal model and tool calls. Refer to [Observability](../plugins/observability/about.md) -for details on exporting NeMo Flow observability data to third-party systems. +for details on exporting NeMo Relay observability data to third-party systems. diff --git a/docs/integrations/langchain.md b/docs/integrations/langchain.md index b8437ed27..adeabad0d 100644 --- a/docs/integrations/langchain.md +++ b/docs/integrations/langchain.md @@ -3,9 +3,9 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow LangChain Integration +# NeMo Relay LangChain Integration -Use the `nemo_flow.integrations.langchain` package to add NeMo Flow +Use the `nemo_relay.integrations.langchain` package to add NeMo Relay observability to [LangChain](https://www.langchain.com/langchain) agents. ## Setup @@ -20,7 +20,7 @@ Install the LangChain integration extra in your application environment. :sync: uv ```bash -uv add "nemo-flow[langchain]" +uv add "nemo-relay[langchain]" ``` ::: @@ -28,7 +28,7 @@ uv add "nemo-flow[langchain]" :sync: pip ```bash -pip install "nemo-flow[langchain]" +pip install "nemo-relay[langchain]" ``` ::: @@ -45,7 +45,7 @@ extra too if you want to run the example as written: :sync: uv ```bash -uv add "nemo-flow[langchain,langchain-nvidia]" +uv add "nemo-relay[langchain,langchain-nvidia]" ``` ::: @@ -53,7 +53,7 @@ uv add "nemo-flow[langchain,langchain-nvidia]" :sync: pip ```bash -pip install "nemo-flow[langchain,langchain-nvidia]" +pip install "nemo-relay[langchain,langchain-nvidia]" ``` ::: @@ -64,10 +64,10 @@ pip install "nemo-flow[langchain,langchain-nvidia]" ```python import asyncio -import nemo_flow +import nemo_relay from langchain.agents import create_agent from langchain_core.tools import tool -from nemo_flow.integrations.langchain import NemoFlowCallbackHandler, NemoFlowMiddleware +from nemo_relay.integrations.langchain import NemoRelayCallbackHandler, NemoRelayMiddleware @tool @@ -79,7 +79,7 @@ def get_weather(location: str) -> str: agent = create_agent( model="nvidia:nvidia/nemotron-3-nano-30b-a3b", tools=[get_weather], - middleware=[NemoFlowMiddleware()], + middleware=[NemoRelayMiddleware()], system_prompt="Use tools when they are relevant. Keep the final answer brief.", ) @@ -92,9 +92,9 @@ input_payload = { ] } -with nemo_flow.scope.scope("langchain-request", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("langchain-request", nemo_relay.ScopeType.Agent): result = asyncio.run( - agent.ainvoke(input_payload, config={"callbacks": [NemoFlowCallbackHandler()]}) + agent.ainvoke(input_payload, config={"callbacks": [NemoRelayCallbackHandler()]}) ) final_message = result["messages"][-1] @@ -103,4 +103,4 @@ print(f"Final response: {final_message.content}") ## Observability -Refer to [Observability](../plugins/observability/about.md) for details on exporting NeMo Flow observability data to third-party systems. +Refer to [Observability](../plugins/observability/about.md) for details on exporting NeMo Relay observability data to third-party systems. diff --git a/docs/integrations/langgraph.md b/docs/integrations/langgraph.md index f68834ec6..43c8a338f 100644 --- a/docs/integrations/langgraph.md +++ b/docs/integrations/langgraph.md @@ -3,9 +3,9 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow LangGraph Integration +# NeMo Relay LangGraph Integration -Use the `nemo_flow.integrations.langgraph` package to add NeMo Flow +Use the `nemo_relay.integrations.langgraph` package to add NeMo Relay observability to [LangGraph](https://www.langchain.com/langgraph) workflows through public LangGraph APIs. ## Setup @@ -20,7 +20,7 @@ Install the LangGraph integration extra in your application environment. :sync: uv ```bash -uv add "nemo-flow[langgraph]" +uv add "nemo-relay[langgraph]" ``` ::: @@ -28,7 +28,7 @@ uv add "nemo-flow[langgraph]" :sync: pip ```bash -pip install "nemo-flow[langgraph]" +pip install "nemo-relay[langgraph]" ``` ::: @@ -42,9 +42,9 @@ dependencies. ```python from typing_extensions import TypedDict -import nemo_flow +import nemo_relay from langgraph.graph import END, START, StateGraph -from nemo_flow.integrations.langgraph import NemoFlowCallbackHandler +from nemo_relay.integrations.langgraph import NemoRelayCallbackHandler class State(TypedDict): @@ -62,28 +62,28 @@ builder.add_edge("increment", END) graph = builder.compile() -with nemo_flow.scope.scope("langgraph-request", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("langgraph-request", nemo_relay.ScopeType.Agent): result = graph.invoke( {"value": 1}, - config={"callbacks": [NemoFlowCallbackHandler()]}, + config={"callbacks": [NemoRelayCallbackHandler()]}, ) print(result) ``` -For LangChain agents inside a LangGraph workflow, use `NemoFlowMiddleware` from +For LangChain agents inside a LangGraph workflow, use `NemoRelayMiddleware` from this package the same way as the LangChain integration and pass the LangGraph `config` into the nested agent call: ```python from langchain.agents import create_agent from langchain_core.runnables import RunnableConfig -from nemo_flow.integrations.langgraph import NemoFlowMiddleware +from nemo_relay.integrations.langgraph import NemoRelayMiddleware agent = create_agent( model="nvidia:nvidia/nemotron-3-nano-30b-a3b", tools=[], - middleware=[NemoFlowMiddleware()], + middleware=[NemoRelayMiddleware()], ) @@ -102,7 +102,7 @@ example as written: :sync: uv ```bash -uv add "nemo-flow[langgraph,langchain-nvidia]" +uv add "nemo-relay[langgraph,langchain-nvidia]" ``` ::: @@ -110,7 +110,7 @@ uv add "nemo-flow[langgraph,langchain-nvidia]" :sync: pip ```bash -pip install "nemo-flow[langgraph,langchain-nvidia]" +pip install "nemo-relay[langgraph,langchain-nvidia]" ``` ::: @@ -118,4 +118,4 @@ pip install "nemo-flow[langgraph,langchain-nvidia]" ## Observability -Refer to [Observability](../plugins/observability/about.md) for details on exporting NeMo Flow observability data to third-party systems. +Refer to [Observability](../plugins/observability/about.md) for details on exporting NeMo Relay observability data to third-party systems. diff --git a/docs/integrations/openclaw-plugin.md b/docs/integrations/openclaw-plugin.md index 32de9a484..5db26df1a 100644 --- a/docs/integrations/openclaw-plugin.md +++ b/docs/integrations/openclaw-plugin.md @@ -6,17 +6,17 @@ SPDX-License-Identifier: Apache-2.0 # OpenClaw Plugin Guide Use the OpenClaw plugin when OpenClaw owns the agent, tool, and LLM lifecycle -that needs NeMo Flow observability. The plugin observes supported OpenClaw -plugin hooks and converts them into NeMo Flow sessions, LLM spans, tool spans, -and marks that the generic NeMo Flow observability component can export as +that needs NeMo Relay observability. The plugin observes supported OpenClaw +plugin hooks and converts them into NeMo Relay sessions, LLM spans, tool spans, +and marks that the generic NeMo Relay observability component can export as Agent Trajectory Interchange Format (ATIF) JSON, OpenTelemetry spans, OpenInference/Phoenix spans, and adaptive telemetry inputs. This public OpenClaw plugin uses OpenClaw public hooks. It can initialize -generic NeMo Flow plugin components such as `observability` and `adaptive`, but +generic NeMo Relay plugin components such as `observability` and `adaptive`, but hook-backed mode does not rewrite OpenClaw tool execution, provider routing, or model requests. For middleware-backed behavior that changes execution, use the -patch-based OpenClaw integration from the NeMo Flow repository. +patch-based OpenClaw integration from the NeMo Relay repository. Use this guide to install the plugin, enable it in OpenClaw, configure telemetry outputs, verify exported traces, and understand current LLM replay fidelity. @@ -39,12 +39,12 @@ Optional: Install the plugin with OpenClaw so OpenClaw can register and manage it: ```bash -openclaw plugins install npm:nemo-flow-openclaw@0.3.0 +openclaw plugins install npm:nemo-relay-openclaw@0.3.0 openclaw gateway restart ``` -OpenClaw uses the package `nemo-flow-openclaw` for installation and the plugin -manifest ID `nemo-flow` for configuration. Use `nemo-flow` in +OpenClaw uses the package `nemo-relay-openclaw` for installation and the plugin +manifest ID `nemo-relay` for configuration. Use `nemo-relay` in `plugins.allow`, `plugins.entries`, `plugins inspect`, and gateway status commands. @@ -52,7 +52,7 @@ If you manage OpenClaw plugin dependencies directly in a Node.js project, install the package with npm: ```bash -npm install nemo-flow-openclaw@0.3.0 +npm install nemo-relay-openclaw@0.3.0 ``` Installing with npm makes the package available to that project. Use @@ -61,16 +61,16 @@ plugin. ## Enable and Configure the Plugin -Add the `nemo-flow` plugin ID to `plugins.allow`, grant conversation hook +Add the `nemo-relay` plugin ID to `plugins.allow`, grant conversation hook access, and place the OpenClaw plugin configuration under -`plugins.entries["nemo-flow"].config`: +`plugins.entries["nemo-relay"].config`: ```json { "plugins": { - "allow": ["nemo-flow"], + "allow": ["nemo-relay"], "entries": { - "nemo-flow": { + "nemo-relay": { "enabled": true, "hooks": { "allowConversationAccess": true @@ -89,19 +89,19 @@ access, and place the OpenClaw plugin configuration under "atif": { "enabled": true, "agent_name": "openclaw", - "output_directory": "./nemo-flow-atif" + "output_directory": "./nemo-relay-atif" }, "opentelemetry": { "enabled": false, "transport": "http_binary", "endpoint": "http://localhost:4318/v1/traces", - "service_name": "openclaw-nemo-flow" + "service_name": "openclaw-nemo-relay" }, "openinference": { "enabled": false, "transport": "http_binary", "endpoint": "http://localhost:6006/v1/traces", - "service_name": "openclaw-nemo-flow" + "service_name": "openclaw-nemo-relay" } } }, @@ -147,15 +147,15 @@ you point them at a collector or Phoenix endpoint. Remove exporter sections you do not use, or set their `enabled` fields to `false`. - `plugins.allow` controls OpenClaw plugin trust and loading. Include - `nemo-flow` when OpenClaw runs with restrictive plugin settings. -- `plugins.entries["nemo-flow"].enabled` controls whether OpenClaw starts this + `nemo-relay` when OpenClaw runs with restrictive plugin settings. +- `plugins.entries["nemo-relay"].enabled` controls whether OpenClaw starts this plugin entry. - `hooks.allowConversationAccess` lets trusted non-bundled plugins receive conversation-sensitive hook payloads such as LLM prompts, LLM responses, agent finalization messages, and tool payloads. -- `config.enabled` disables or enables the NeMo Flow OpenClaw wrapper without +- `config.enabled` disables or enables the NeMo Relay OpenClaw wrapper without removing the plugin entry. `config.backend` currently supports only `hooks`. -- `config.plugins` is the generic NeMo Flow plugin configuration document. Use +- `config.plugins` is the generic NeMo Relay plugin configuration document. Use this object to configure built-in components such as `observability` and `adaptive`. - `config.plugins.components[].config.atif` writes ATIF trajectory JSON files. @@ -167,7 +167,7 @@ do not use, or set their `enabled` fields to `false`. is `true`. - `config.plugins.components[]` entries with `kind: "adaptive"` initialize the Adaptive plugin. In hook-backed OpenClaw mode, adaptive telemetry can consume - replayed NeMo Flow events, while request-rewrite features such as adaptive + replayed NeMo Relay events, while request-rewrite features such as adaptive hints require a managed execution path. - `config.capture` controls prompt, response, tool argument, and tool result capture. Tool arguments and tool results are stripped by default because they @@ -186,17 +186,17 @@ openclaw gateway restart ## Configuration Key Names The OpenClaw wrapper owns `enabled`, `backend`, `capture`, and `correlation`. -The top-level `plugins` object inside the wrapper is the generic NeMo Flow +The top-level `plugins` object inside the wrapper is the generic NeMo Relay plugin configuration document. :::{note} OpenClaw wrapper fields such as `includePrompts` and `llmOutputGraceMs` follow -the OpenClaw plugin schema. Fields inside `config.plugins` are NeMo Flow generic +the OpenClaw plugin schema. Fields inside `config.plugins` are NeMo Relay generic plugin configuration, so they use `snake_case` regardless of language. ::: Missing observability sections are disabled. Plugin-host validation or -initialization errors degrade the NeMo Flow runtime as a whole, and the status +initialization errors degrade the NeMo Relay runtime as a whole, and the status method reports configured output health from the generic observability component. See [Observability Configuration](../plugins/observability/configuration.md) @@ -207,7 +207,7 @@ for the complete `observability` component schema and exporter-specific fields. Inspect the plugin runtime: ```bash -openclaw plugins inspect nemo-flow --runtime --json +openclaw plugins inspect nemo-relay --runtime --json ``` This verifies that the plugin package is installed, enabled, importable, and @@ -224,17 +224,17 @@ sink: endpoint. The plugin also registers the `operator.admin` scoped gateway method -`nemoFlow.status`. If your CLI is already paired with admin-capable gateway +`nemoRelay.status`. If your CLI is already paired with admin-capable gateway access, run: ```bash -openclaw gateway call nemoFlow.status --json +openclaw gateway call nemoRelay.status --json ``` Otherwise, pass your normal admin-capable gateway auth options: ```bash -openclaw gateway call nemoFlow.status --token "$OPENCLAW_GATEWAY_TOKEN" --json +openclaw gateway call nemoRelay.status --token "$OPENCLAW_GATEWAY_TOKEN" --json ``` If OpenClaw requests a device scope upgrade for `operator.admin`, approve it @@ -246,17 +246,17 @@ reason when present. ## Runtime Mapping -The plugin maps supported OpenClaw hook events into NeMo Flow telemetry and +The plugin maps supported OpenClaw hook events into NeMo Relay telemetry and adaptive inputs without changing OpenClaw execution behavior. It does not change OpenClaw tool execution, provider routing, policy decisions, or provider request payloads. -| OpenClaw hook | NeMo Flow behavior | +| OpenClaw hook | NeMo Relay behavior | | --- | --- | | `gateway_start` | Touches the replay backend early; session roots still open lazily from session-scoped hooks. | -| `gateway_stop` | Drains open sessions, shuts down subscribers, and clears the NeMo Flow plugin host. | -| `session_start` | Opens or aliases a NeMo Flow session scope. | +| `gateway_stop` | Drains open sessions, shuts down subscribers, and clears the NeMo Relay plugin host. | +| `session_start` | Opens or aliases a NeMo Relay session scope. | | `session_end` | Closes the session and flushes pending replay state; the generic observability component exports ATIF when enabled. | | `model_call_started` / `model_call_ended` | Records provider timing for later LLM span correlation. | | `llm_input` / `llm_output` | Replays direct LLM spans when request and response hooks can be paired safely. | @@ -284,8 +284,8 @@ read, cache write, and cost fields into OpenInference-friendly usage fields. If the plugin does not load: - verify the package was installed with `openclaw plugins install` -- verify `plugins.allow` includes `nemo-flow` -- verify `plugins.entries["nemo-flow"].enabled` is not disabled +- verify `plugins.allow` includes `nemo-relay` +- verify `plugins.entries["nemo-relay"].enabled` is not disabled - restart the gateway after config changes If conversation payloads are missing: diff --git a/docs/nemo-flow-cli/about.md b/docs/nemo-relay-cli/about.md similarity index 84% rename from docs/nemo-flow-cli/about.md rename to docs/nemo-relay-cli/about.md index c2e4d30fa..0ae6997d2 100644 --- a/docs/nemo-flow-cli/about.md +++ b/docs/nemo-relay-cli/about.md @@ -5,13 +5,13 @@ SPDX-License-Identifier: Apache-2.0 # About -Use this section when you want the `nemo-flow` binary to observe local coding -agent sessions through hooks, a passthrough LLM gateway, and NeMo Flow +Use this section when you want the `nemo-relay` binary to observe local coding +agent sessions through hooks, a passthrough LLM gateway, and NeMo Relay observability exporters. -The NeMo Flow CLI is installed by the `nemo-flow-cli` Cargo package. It can run +The NeMo Relay CLI is installed by the `nemo-relay-cli` Cargo package. It can run supported coding agents through a managed local gateway, forward agent hook -payloads into NeMo Flow lifecycle events, route OpenAI-compatible or +payloads into NeMo Relay lifecycle events, route OpenAI-compatible or Anthropic-compatible model traffic through the gateway, and diagnose local configuration. @@ -20,8 +20,8 @@ configuration. Use these guides when you need to: - Observe Claude Code, Codex, Cursor, or Hermes Agent sessions locally. -- Configure coding-agent hooks for NeMo Flow lifecycle events. -- Route model-provider traffic through the local NeMo Flow gateway. +- Configure coding-agent hooks for NeMo Relay lifecycle events. +- Route model-provider traffic through the local NeMo Relay gateway. - Export local sessions to Agent Trajectory Interchange Format (ATIF), Agent Trajectory Observability Format (ATOF) JSONL, OpenTelemetry, or OpenInference. @@ -33,7 +33,7 @@ If you are instrumenting an application or framework directly, use ## Agent Harness Support -NeMo Flow CLI support is experimental and observability-focused. +NeMo Relay CLI support is experimental and observability-focused. | Agent | Observability | Security | Optimization | Notes | | --- | --- | --- | --- | --- | diff --git a/docs/nemo-flow-cli/basic-usage.md b/docs/nemo-relay-cli/basic-usage.md similarity index 81% rename from docs/nemo-flow-cli/basic-usage.md rename to docs/nemo-relay-cli/basic-usage.md index da95f8e43..941811857 100644 --- a/docs/nemo-flow-cli/basic-usage.md +++ b/docs/nemo-relay-cli/basic-usage.md @@ -5,9 +5,9 @@ SPDX-License-Identifier: Apache-2.0 # Basic Usage -The `nemo-flow` binary observes coding agents that do not expose every +The `nemo-relay` binary observes coding agents that do not expose every LLM call site directly. It combines agent-specific hook endpoints with a -passthrough LLM gateway so NeMo Flow owns both the agent lifecycle and the model +passthrough LLM gateway so NeMo Relay owns both the agent lifecycle and the model request lifecycle. Use the gateway when you need one observability boundary for OpenAI Codex, @@ -32,7 +32,7 @@ the payload in a shared gateway envelope. The adapters preserve vendor fields such as session IDs, working directories, transcript paths, model names, tool payloads, shell payloads, MCP payloads, file -payloads, user identity, and subagent metadata in NeMo Flow event metadata. +payloads, user identity, and subagent metadata in NeMo Relay event metadata. ## Gateway Routes @@ -47,7 +47,7 @@ observability is required. The gateway forwards raw provider JSON without rewriting OpenAI or Anthropic payload schemas. It removes only hop-by-hop transport headers, forwards -streaming responses as streams, and emits NeMo Flow LLM start and end events +streaming responses as streams, and emits NeMo Relay LLM start and end events under the active session scope. ## Transparent Run @@ -58,17 +58,17 @@ configuration into the launched coding agent, and stops the gateway when the agent exits. ```bash -nemo-flow codex -nemo-flow claude -nemo-flow cursor -nemo-flow hermes +nemo-relay codex +nemo-relay claude +nemo-relay cursor +nemo-relay hermes ``` -Use `nemo-flow run -- ` when you want to launch an explicit command +Use `nemo-relay run -- ` when you want to launch an explicit command instead of the built-in shortcut: ```bash -nemo-flow run -- codex +nemo-relay run -- codex ``` If a launcher or wrapper hides the real agent name, set that wrapper as the @@ -81,11 +81,11 @@ command = "my-codex-wrapper" ``` ```bash -nemo-flow run --agent codex +nemo-relay run --agent codex ``` Hermes is different from the other transparent modes: `run --agent hermes` -starts the gateway and exports the dynamic `NEMO_FLOW_GATEWAY_URL`, but Hermes +starts the gateway and exports the dynamic `NEMO_RELAY_GATEWAY_URL`, but Hermes shell hooks still need to be installed or otherwise approved in Hermes config. Use `--dry-run --print` to inspect the generated hook config, gateway @@ -99,10 +99,10 @@ and project config. CLI flags and environment variables override file config. Config file locations are: -- `/etc/nemo-flow/config.toml` -- `.nemo-flow/config.toml` -- `$XDG_CONFIG_HOME/nemo-flow/config.toml` -- `~/.config/nemo-flow/config.toml` +- `/etc/nemo-relay/config.toml` +- `.nemo-relay/config.toml` +- `$XDG_CONFIG_HOME/nemo-relay/config.toml` +- `~/.config/nemo-relay/config.toml` Example: @@ -126,8 +126,8 @@ command = "hermes" ``` Observability exporters are configured in `plugins.toml`. Use -`nemo-flow plugins edit` for the user file, `nemo-flow plugins edit --project` -for `.nemo-flow/plugins.toml`, or write the plugin config directly: +`nemo-relay plugins edit` for the user file, `nemo-relay plugins edit --project` +for `.nemo-relay/plugins.toml`, or write the plugin config directly: ```toml version = 1 @@ -138,7 +138,7 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" [components.config.openinference] enabled = true @@ -147,13 +147,13 @@ endpoint = "http://127.0.0.1:4318/v1/traces" Transparent runs always bind the managed gateway to `127.0.0.1:0`. The selected port is discovered by the wrapper and exposed to hooks through -`NEMO_FLOW_GATEWAY_URL`. +`NEMO_RELAY_GATEWAY_URL`. Common environment variables for direct gateway server use are: -- `NEMO_FLOW_GATEWAY_BIND` -- `NEMO_FLOW_OPENAI_BASE_URL` -- `NEMO_FLOW_ANTHROPIC_BASE_URL` +- `NEMO_RELAY_GATEWAY_BIND` +- `NEMO_RELAY_OPENAI_BASE_URL` +- `NEMO_RELAY_ANTHROPIC_BASE_URL` Plugin configuration controls process-level Observability exporters. Per-session configuration controls structured metadata on the top-level agent begin event @@ -161,10 +161,10 @@ and the plugin configuration metadata associated with the session. `hook-forward` can also pass per-session configuration through headers: -- `x-nemo-flow-config-profile` -- `x-nemo-flow-session-metadata` -- `x-nemo-flow-plugin-config` -- `x-nemo-flow-gateway-mode` +- `x-nemo-relay-config-profile` +- `x-nemo-relay-session-metadata` +- `x-nemo-relay-plugin-config` +- `x-nemo-relay-gateway-mode` The accepted gateway mode values are `hook-only`, `passthrough`, and `required`. The gateway records this value as session metadata so downstream @@ -174,19 +174,19 @@ where provider traffic was expected to pass through the gateway. ## Runtime Mapping The gateway normalizes vendor hook payloads into private internal events before -calling NeMo Flow APIs. +calling NeMo Relay APIs. - Agent start opens a top-level `ScopeType::Agent` scope on a dedicated `ScopeStackHandle`. - Subagent start opens a child `ScopeType::Agent` scope. Subagent stop closes that scope when it is still active. -- Tool pre-use starts a NeMo Flow tool span. Tool post-use, denial, or failure +- Tool pre-use starts a NeMo Relay tool span. Tool post-use, denial, or failure closes it. - Prompt, response, agent-thought, and Hermes LLM hooks are retained as - private correlation hints. They are not emitted as NeMo Flow events. + private correlation hints. They are not emitted as NeMo Relay events. - Compaction, notification, and unknown hook events become mark events under the active session scope. -- Gateway requests emit NeMo Flow LLM start and end events under the active +- Gateway requests emit NeMo Relay LLM start and end events under the active session scope. Before each LLM start, the gateway uses explicit subagent headers, pending hints, shared conversation/generation/request identifiers, and the previous correlated owner to choose the parent scope. @@ -198,11 +198,11 @@ calling NeMo Flow APIs. Gateway requests can provide explicit correlation identifiers with these headers: -- `x-nemo-flow-session-id` -- `x-nemo-flow-subagent-id` -- `x-nemo-flow-conversation-id` -- `x-nemo-flow-generation-id` -- `x-nemo-flow-request-id` +- `x-nemo-relay-session-id` +- `x-nemo-relay-subagent-id` +- `x-nemo-relay-conversation-id` +- `x-nemo-relay-generation-id` +- `x-nemo-relay-request-id` When those headers are absent, the gateway also looks for `conversation_id`/`conversationId`/`conversation.id`, @@ -235,8 +235,8 @@ gateway. ## Hook Forwarding Hooks generated by the wrapper (Claude/Codex/Cursor ephemeral, Hermes via -setup) invoke `nemo-flow hook-forward ` from stdin. Inside the wrapper -the gateway URL comes from `NEMO_FLOW_GATEWAY_URL` injected on every run; +setup) invoke `nemo-relay hook-forward ` from stdin. Inside the wrapper +the gateway URL comes from `NEMO_RELAY_GATEWAY_URL` injected on every run; outside the wrapper (Hermes standalone, IDE-launched Claude/Codex) the hook command falls back to its embedded `--gateway-url`. @@ -247,10 +247,10 @@ default so observability outages do not block the coding agent. Add Optional flags map to gateway headers: -- `--session-metadata` sets `x-nemo-flow-session-metadata`. -- `--plugin-config` sets `x-nemo-flow-plugin-config`. -- `--profile` sets `x-nemo-flow-config-profile`. -- `--gateway-mode` sets `x-nemo-flow-gateway-mode`. +- `--session-metadata` sets `x-nemo-relay-session-metadata`. +- `--plugin-config` sets `x-nemo-relay-plugin-config`. +- `--profile` sets `x-nemo-relay-config-profile`. +- `--gateway-mode` sets `x-nemo-relay-gateway-mode`. ## Agent Guides diff --git a/docs/nemo-flow-cli/claude-code.md b/docs/nemo-relay-cli/claude-code.md similarity index 75% rename from docs/nemo-flow-cli/claude-code.md rename to docs/nemo-relay-cli/claude-code.md index 8789e6f2a..fd9d9fd96 100644 --- a/docs/nemo-flow-cli/claude-code.md +++ b/docs/nemo-relay-cli/claude-code.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Claude Code -Use this guide to observe Claude Code sessions with NeMo Flow. Claude Code is +Use this guide to observe Claude Code sessions with NeMo Relay. Claude Code is the supported integration target. The Claude application, Claude web, and Claude desktop sessions are unsupported unless they expose the same local hook and gateway controls as Claude Code. @@ -15,24 +15,24 @@ gateway controls as Claude Code. Use the wrapper for no-install local observability: ```bash -nemo-flow claude +nemo-relay claude ``` Pass Claude Code arguments after `--`: ```bash -nemo-flow claude -- "summarize this repository" +nemo-relay claude -- "summarize this repository" ``` -This shortcut is equivalent to `nemo-flow run -- claude`. The wrapper starts a +This shortcut is equivalent to `nemo-relay run -- claude`. The wrapper starts a gateway on a dynamic `127.0.0.1` port, creates a temporary Claude plugin -directory with NeMo Flow hooks, passes that plugin with `--plugin-dir`, and +directory with NeMo Relay hooks, passes that plugin with `--plugin-dir`, and sets `ANTHROPIC_BASE_URL` to the gateway URL for the launched process. Inspect what would be launched without starting Claude Code: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- claude @@ -40,16 +40,16 @@ nemo-flow run \ ## Shared Config -Create `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Create `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.claude] command = "claude" ``` -Then configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Then configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -60,14 +60,14 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" [components.config.openinference] enabled = true endpoint = "http://127.0.0.1:4318/v1/traces" ``` -Run `nemo-flow run --agent claude` to use the configured command and plugin +Run `nemo-relay run --agent claude` to use the configured command and plugin config. User config takes priority over project and system config. ## Standalone Gateway @@ -76,7 +76,7 @@ Use the long-running gateway only when you want Claude Code running outside the wrapper (e.g., already configured by an IDE): ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Launch Claude Code from another terminal with the gateway environment: @@ -88,8 +88,8 @@ claude The gateway forwards Anthropic `/v1/messages`, `/v1/messages/count_tokens`, and model routes without rewriting provider JSON. Hook events (tool calls, session -markers) are only captured when running through `nemo-flow claude` or -`nemo-flow run --agent claude`, which inject ephemeral hooks into the launched +markers) are only captured when running through `nemo-relay claude` or +`nemo-relay run --agent claude`, which inject ephemeral hooks into the launched process. ## Captured Events @@ -99,7 +99,7 @@ Generated Claude Code hooks include `SessionStart`, `SessionEnd`, `PostToolUseFailure`, `Notification`, and `PreCompact` for scope, tool, and mark events. `UserPromptSubmit`, `AfterAgentResponse`, `AfterAgentThought`, and `Stop` are retained as private LLM correlation hints and are not emitted as -standalone NeMo Flow events. +standalone NeMo Relay events. Tool hooks preserve canonical fields such as `tool_use_id`, `tool_name`, `tool_input`, `error`, `duration_ms`, and `is_interrupt`. Subagent hooks use @@ -113,7 +113,7 @@ Then check that hook forwarding reaches the gateway: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-claude","hook_event_name":"SessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward claude --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward claude --fail-closed ``` The response should be valid Claude Code hook JSON. For most lifecycle events it @@ -121,11 +121,11 @@ is an allow/continue response. ## Verify Export -End the Claude Code session and confirm that session-end closed the NeMo Flow +End the Claude Code session and confirm that session-end closed the NeMo Relay agent scope and wrote Agent Trajectory Interchange Format (ATIF): ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` The gateway exports `.atif.json` on session end. If no file appears, @@ -135,13 +135,13 @@ and the gateway process can write to the configured directory. ## Troubleshoot LLM Lifecycle Missing hooks usually means Claude Code did not load the local hook config or -the `nemo-flow` binary is not on `PATH`. +the `nemo-relay` binary is not on `PATH`. Missing LLM spans with present hook spans means Anthropic traffic is not routed through the gateway. Verify `ANTHROPIC_BASE_URL` in the Claude Code process environment and confirm that requests hit `/v1/messages`. If LLM spans exist but attach to the session instead of a subagent, pass -`x-nemo-flow-subagent-id` on gateway requests or include shared +`x-nemo-relay-subagent-id` on gateway requests or include shared `conversation_id`, `generation_id`, or `request_id` values in both hook payloads and provider requests. diff --git a/docs/nemo-flow-cli/codex.md b/docs/nemo-relay-cli/codex.md similarity index 78% rename from docs/nemo-flow-cli/codex.md rename to docs/nemo-relay-cli/codex.md index 462d9f8e7..d116bec1c 100644 --- a/docs/nemo-flow-cli/codex.md +++ b/docs/nemo-relay-cli/codex.md @@ -13,15 +13,15 @@ local gateway cannot observe provider traffic that never reaches the machine. ## Requirements `codex-cli >= 0.129.0`. The gateway uses the `features.hooks` flag and the -`nemo-flow-openai` provider alias, both of which require this version. Earlier +`nemo-relay-openai` provider alias, both of which require this version. Earlier versions either reject the provider override or do not recognize the hooks feature flag. ```{warning} As of Codex 0.129, Codex requires hooks to be manually reviewed and activated -before they run. Generated NeMo Flow hook configuration is not enough on its own +before they run. Generated NeMo Relay hook configuration is not enough on its own if Codex leaves those hooks inactive. Review and activate the installed or -injected hooks in Codex before expecting NeMo Flow events. This is being tracked +injected hooks in Codex before expecting NeMo Relay events. This is being tracked upstream as [openai/codex#21639](https://github.com/openai/codex/issues/21639). ``` @@ -30,25 +30,25 @@ upstream as [openai/codex#21639](https://github.com/openai/codex/issues/21639). Use the wrapper for no-install local observability: ```bash -nemo-flow codex +nemo-relay codex ``` Pass Codex arguments after `--`: ```bash -nemo-flow codex -- exec "Summarize this repository." +nemo-relay codex -- exec "Summarize this repository." ``` -This shortcut is equivalent to `nemo-flow run -- codex`. The wrapper starts a +This shortcut is equivalent to `nemo-relay run -- codex`. The wrapper starts a gateway on a dynamic `127.0.0.1` port, enables Codex hooks with CLI config -overrides, injects hook commands that use `NEMO_FLOW_GATEWAY_URL`, and points -Codex at a temporary `nemo-flow-openai` provider alias that uses the gateway +overrides, injects hook commands that use `NEMO_RELAY_GATEWAY_URL`, and points +Codex at a temporary `nemo-relay-openai` provider alias that uses the gateway URL while preserving Codex's OpenAI auth path. Inspect what would be launched without starting Codex: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- codex @@ -56,8 +56,8 @@ nemo-flow run \ ## Shared Config -Create `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Create `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [upstream] @@ -67,8 +67,8 @@ openai_base_url = "https://api.openai.com/v1" command = "codex" ``` -Then configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Then configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -79,10 +79,10 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" ``` -Run `nemo-flow run --agent codex` to use the configured command and plugin +Run `nemo-relay run --agent codex` to use the configured command and plugin config. User config takes priority over project and system config. ## Standalone Gateway @@ -91,17 +91,17 @@ Use the long-running gateway only when you want Codex running outside the wrapper: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Then configure local Codex to use a gateway provider alias instead of overriding the reserved built-in `openai` provider: ```toml -model_provider = "nemo-flow-openai" +model_provider = "nemo-relay-openai" -[model_providers.nemo-flow-openai] -name = "NeMo Flow OpenAI" +[model_providers.nemo-relay-openai] +name = "NeMo Relay OpenAI" base_url = "http://127.0.0.1:4040" wire_api = "responses" requires_openai_auth = true @@ -120,7 +120,7 @@ Generated Codex hooks include `SessionStart`, `SessionEnd`, `SubagentStart`, `Notification`, and `PreCompact` for scope, tool, and mark events. `UserPromptSubmit`, `AfterAgentResponse`, `AfterAgentThought`, and `Stop` are retained as private LLM correlation hints and are not emitted as standalone -NeMo Flow events. +NeMo Relay events. The transparent wrapper passes hook entries as Codex CLI config overrides and sets `features.hooks=true` for that launched process. Persistent install writes @@ -135,7 +135,7 @@ check hook forwarding directly: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-codex","hook_event_name":"sessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward codex --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward codex --fail-closed ``` The response should match Codex hook semantics. For most lifecycle events it is @@ -147,7 +147,7 @@ End the Codex session and confirm Agent Trajectory Interchange Format (ATIF) exists: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` The gateway writes `.atif.json` after every conversation turn for @@ -167,6 +167,6 @@ sessions are missing spans, confirm the GUI is using local provider configuration rather than a remote execution path. If LLM spans exist but attach to the session instead of a subagent, pass -`x-nemo-flow-subagent-id` on gateway requests or include shared +`x-nemo-relay-subagent-id` on gateway requests or include shared `conversation_id`, `generation_id`, or `request_id` values in both hook payloads and provider requests. diff --git a/docs/nemo-flow-cli/cursor.md b/docs/nemo-relay-cli/cursor.md similarity index 80% rename from docs/nemo-flow-cli/cursor.md rename to docs/nemo-relay-cli/cursor.md index d5fe3d5fd..2f0acfe9d 100644 --- a/docs/nemo-flow-cli/cursor.md +++ b/docs/nemo-relay-cli/cursor.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Cursor -Use this guide to observe Cursor hook lifecycle events with NeMo Flow. The +Use this guide to observe Cursor hook lifecycle events with NeMo Relay. The repository ships a Cursor hook bundle under `integrations/coding-agents/cursor/` because this integration does not assume an official Cursor plugin package format. @@ -18,7 +18,7 @@ through the gateway if your Cursor build exposes that configuration. Cursor CLI support must be verified separately with `cursor-agent`. Current Cursor CLI builds require `.cursor/hooks.json` to set top-level `"version": 1` and use direct command entries such as -`{"command": "nemo-flow hook-forward cursor", "timeout": 30}`. The nested +`{"command": "nemo-relay hook-forward cursor", "timeout": 30}`. The nested `{"matcher": "*", "hooks": [...]}` group shape used by Claude Code and Codex does not fire in Cursor CLI. If CLI hooks still do not fire with direct versioned entries, treat that Cursor CLI version as hook-limited and @@ -27,7 +27,7 @@ gateway-only where model routing is configurable. ```{warning} Cursor CLI hook coverage is not the same as Cursor IDE hook coverage. Current headless CLI builds can emit fewer hook events than Cursor IDE sessions. Treat -missing CLI hook events as a Cursor CLI limitation after `nemo-flow doctor +missing CLI hook events as a Cursor CLI limitation after `nemo-relay doctor cursor` confirms the hook file uses the direct versioned shape. ``` @@ -36,17 +36,17 @@ cursor` confirms the hook file uses the direct versioned shape. Use the wrapper for no-install local observability: ```bash -nemo-flow cursor +nemo-relay cursor ``` Pass Cursor arguments after `--`: ```bash -nemo-flow cursor -- agent --resume +nemo-relay cursor -- agent --resume ``` -This shortcut is equivalent to `nemo-flow run -- cursor-agent`. The wrapper -starts a gateway on a dynamic `127.0.0.1` port, temporarily merges NeMo Flow +This shortcut is equivalent to `nemo-relay run -- cursor-agent`. The wrapper +starts a gateway on a dynamic `127.0.0.1` port, temporarily merges NeMo Relay hook entries into the project `.cursor/hooks.json`, launches Cursor, and restores the original hook file after the agent exits. The temporary Cursor hook file is written with top-level `"version": 1` and direct command entries. @@ -54,7 +54,7 @@ file is written with top-level `"version": 1` and direct command entries. Inspect what would be launched without starting Cursor: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- cursor-agent @@ -62,8 +62,8 @@ nemo-flow run \ ## Shared Config -Create `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Create `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.cursor] @@ -71,8 +71,8 @@ command = "cursor-agent" patch_restore_hooks = true ``` -Then configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Then configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -83,10 +83,10 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" ``` -Run `nemo-flow run --agent cursor` to use the configured command and plugin +Run `nemo-relay run --agent cursor` to use the configured command and plugin config. User config takes priority over project and system config. ## Standalone Gateway @@ -95,7 +95,7 @@ Use the long-running gateway only when you want Cursor running outside the wrapper (e.g., the Cursor GUI). Start the gateway manually: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Then point Cursor provider traffic at `http://127.0.0.1:4040` wherever Cursor @@ -111,11 +111,11 @@ Generated Cursor hooks include `sessionStart`, `sessionEnd`, `subagentStart`, `afterShellExecution`, `beforeMCPExecution`, `afterMCPExecution`, `preCompact`, and `stop` for scope, tool, and mark events. `beforeSubmitPrompt`, `afterAgentResponse`, and `afterAgentThought` are retained as private LLM -correlation hints and are not emitted as standalone NeMo Flow events. +correlation hints and are not emitted as standalone NeMo Relay events. Tool events preserve Cursor shell and MCP payloads in metadata and use the -active `subagent.id`, `subagent_id`, or `x-nemo-flow-subagent-id` when present. -The transparent wrapper backs up the project hook file, merges NeMo Flow hook +active `subagent.id`, `subagent_id`, or `x-nemo-relay-subagent-id` when present. +The transparent wrapper backs up the project hook file, merges NeMo Relay hook entries for the run, and restores or removes the temporary file when the agent exits. @@ -127,7 +127,7 @@ Then check hook forwarding directly: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-cursor","hook_event_name":"sessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward cursor --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward cursor --fail-closed ``` For Cursor CLI, run an equivalent `cursor-agent` session and verify the gateway @@ -142,14 +142,14 @@ End the Cursor session and confirm Agent Trajectory Interchange Format (ATIF) exists: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` The gateway writes `.atif.json` on session end. If the file is missing, confirm Cursor loaded `.cursor/hooks.json`, the gateway binary is on -`PATH`, `--atif-dir` or `NEMO_FLOW_ATIF_DIR` is configured, `plugins.toml` +`PATH`, `--atif-dir` or `NEMO_RELAY_ATIF_DIR` is configured, `plugins.toml` enables the ATIF exporter with a writable `output_directory`, and user-managed -Cursor hooks pass `nemo-flow doctor cursor`. +Cursor hooks pass `nemo-relay doctor cursor`. ## Troubleshoot LLM Lifecycle @@ -158,6 +158,6 @@ routed through the gateway. Confirm the active Cursor GUI or CLI mode supports provider base URL configuration for the model path being used. If LLM spans exist but attach to the session instead of a subagent, pass -`x-nemo-flow-subagent-id` on gateway requests or include shared +`x-nemo-relay-subagent-id` on gateway requests or include shared `conversation_id`, `generation_id`, or `request_id` values in both hook payloads and provider requests. diff --git a/docs/nemo-flow-cli/hermes.md b/docs/nemo-relay-cli/hermes.md similarity index 71% rename from docs/nemo-flow-cli/hermes.md rename to docs/nemo-relay-cli/hermes.md index b0edf3318..334432d7d 100644 --- a/docs/nemo-flow-cli/hermes.md +++ b/docs/nemo-relay-cli/hermes.md @@ -5,8 +5,8 @@ SPDX-License-Identifier: Apache-2.0 # Hermes Agent -Use this guide to observe local Hermes Agent sessions with NeMo Flow through -Hermes shell hooks and the `nemo-flow` gateway. This gateway path is +Use this guide to observe local Hermes Agent sessions with NeMo Relay through +Hermes shell hooks and the `nemo-relay` gateway. This gateway path is separate from the Hermes third-party patch set under `patches/hermes-agent/`; use the gateway when you want hook forwarding without rebuilding a patched Hermes checkout. @@ -21,17 +21,17 @@ Use the wrapper when you want the gateway lifetime managed for a local Hermes process: ```bash -nemo-flow hermes +nemo-relay hermes ``` Pass Hermes arguments after `--`: ```bash -nemo-flow hermes -- chat --provider custom +nemo-relay hermes -- chat --provider custom ``` -This shortcut is equivalent to `nemo-flow run -- hermes`. The wrapper starts a -gateway on a dynamic `127.0.0.1` port and exports `NEMO_FLOW_GATEWAY_URL` for +This shortcut is equivalent to `nemo-relay run -- hermes`. The wrapper starts a +gateway on a dynamic `127.0.0.1` port and exports `NEMO_RELAY_GATEWAY_URL` for the launched process. Hermes hook configuration is not temporary in this mode. Install hooks first, or configure equivalent Hermes shell hooks, so approved hook commands can discover the dynamic gateway URL. @@ -39,7 +39,7 @@ hook commands can discover the dynamic gateway URL. Inspect what would be launched without starting Hermes: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- hermes @@ -47,16 +47,16 @@ nemo-flow run \ ## Shared Config -Create `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Create `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.hermes] command = "hermes" ``` -Then configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Then configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -67,37 +67,37 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" [components.config.openinference] enabled = true endpoint = "http://127.0.0.1:4318/v1/traces" ``` -Run `nemo-flow run --agent hermes` to use the configured command and plugin +Run `nemo-relay run --agent hermes` to use the configured command and plugin config. User config takes priority over project and system config. ## Hermes Hook Setup Unlike the other agents, Hermes reads hooks from `.hermes/config.yaml`. The setup wizard writes that file for you when you select hermes — running -`nemo-flow config` (or `nemo-flow config hermes` to scope to one agent) merges -NeMo Flow hook commands into the YAML, preserving any existing config, and -records the path under `[agents.hermes].hooks_path` in `.nemo-flow/config.toml`. +`nemo-relay config` (or `nemo-relay config hermes` to scope to one agent) merges +NeMo Relay hook commands into the YAML, preserving any existing config, and +records the path under `[agents.hermes].hooks_path` in `.nemo-relay/config.toml`. The generated Hermes hooks cover `on_session_start`, `on_session_end`, `on_session_finalize`, `on_session_reset`, `pre_llm_call`, `post_llm_call`, `pre_tool_call`, `post_tool_call`, `subagent_start`, and `subagent_stop`. -Hermes hook forwarding prefers `NEMO_FLOW_GATEWAY_URL` when set (this is what -`nemo-flow hermes` injects on every run). When launched outside the wrapper — +Hermes hook forwarding prefers `NEMO_RELAY_GATEWAY_URL` when set (this is what +`nemo-relay hermes` injects on every run). When launched outside the wrapper — e.g., bare `hermes` against a long-running gateway — the hook command falls back to `--gateway-url http://127.0.0.1:4040`. For standalone gateway mode, start the daemon manually: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Then point Hermes provider traffic at `http://127.0.0.1:4040` for any provider @@ -111,11 +111,11 @@ hook forwarding directly: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-hermes","hook_event_name":"on_session_start"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward hermes --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward hermes --fail-closed ``` The response should be `{}`. If Hermes prompts for hook consent, approve the -NeMo Flow hook command interactively or through Hermes configuration before +NeMo Relay hook command interactively or through Hermes configuration before relying on unattended capture. ## Verify Export @@ -124,7 +124,7 @@ End a Hermes turn or finalize the session and confirm Agent Trajectory Interchange Format (ATIF) exists: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` The gateway writes or updates an ATIF snapshot when it receives @@ -139,4 +139,4 @@ If hook events appear but LLM spans are missing, Hermes model traffic is not routed through the gateway. If LLM spans exist but attach to the top-level agent instead of a subagent, include shared identifiers in Hermes hook payloads and gateway requests, such as `conversation_id`, `generation_id`, `request_id`, or -`x-nemo-flow-subagent-id`. +`x-nemo-relay-subagent-id`. diff --git a/docs/plugins/adaptive/about.md b/docs/plugins/adaptive/about.md index d6e23f008..9d7d1f1b7 100644 --- a/docs/plugins/adaptive/about.md +++ b/docs/plugins/adaptive/about.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Adaptive -Use the Adaptive plugin when you want NeMo Flow to collect runtime signals and +Use the Adaptive plugin when you want NeMo Relay to collect runtime signals and activate measured adaptive behavior through the shared plugin system. Adaptive is a first-party plugin component with kind `adaptive`. It uses the -same runtime model as the rest of NeMo Flow: scopes and managed calls emit +same runtime model as the rest of NeMo Relay: scopes and managed calls emit lifecycle events, subscribers and learners observe those events, intercepts can add guidance, and plugin configuration controls what is active. diff --git a/docs/plugins/adaptive/acg.md b/docs/plugins/adaptive/acg.md index 558ebd0f7..9d511519a 100644 --- a/docs/plugins/adaptive/acg.md +++ b/docs/plugins/adaptive/acg.md @@ -49,7 +49,7 @@ prompt samples. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the +Use plugin configuration when the application should let NeMo Relay own the Adaptive Cache Governor (ACG) runtime lifecycle. ::::{tab-set} @@ -59,31 +59,31 @@ Adaptive Cache Governor (ACG) runtime lifecycle. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig(learners=["acg"]), - acg=nemo_flow.adaptive.AcgConfig(provider="anthropic"), + telemetry=nemo_relay.adaptive.TelemetryConfig(learners=["acg"]), + acg=nemo_relay.adaptive.AcgConfig(provider="anthropic"), ) -plugin_config = nemo_flow.plugin.PluginConfig( - components=[nemo_flow.adaptive.ComponentSpec(adaptive_config)] +plugin_config = nemo_relay.plugin.PluginConfig( + components=[nemo_relay.adaptive.ComponentSpec(adaptive_config)] ) -report = nemo_flow.plugin.validate(plugin_config) +report = nemo_relay.plugin.validate(plugin_config) if any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"]): raise RuntimeError(report["diagnostics"]) -await nemo_flow.plugin.initialize(plugin_config) +await nemo_relay.plugin.initialize(plugin_config) try: # Run instrumented application work here. pass finally: - nemo_flow.plugin.clear() + nemo_relay.plugin.clear() ``` ::: @@ -91,8 +91,8 @@ finally: :sync: node ```js -const adaptive = require("nemo-flow-node/adaptive"); -const plugin = require("nemo-flow-node/plugin"); +const adaptive = require("nemo-relay-node/adaptive"); +const plugin = require("nemo-relay-node/plugin"); const adaptiveConfig = adaptive.defaultConfig(); adaptiveConfig.agent_id = "planner"; @@ -121,9 +121,9 @@ try { :sync: rust ```rust -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; -use nemo_flow_adaptive::plugin_component::ComponentSpec; -use nemo_flow_adaptive::{ +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay_adaptive::plugin_component::ComponentSpec; +use nemo_relay_adaptive::{ AcgComponentConfig, AdaptiveConfig, BackendSpec, StateConfig, TelemetryComponentConfig, }; @@ -165,18 +165,18 @@ directly instead of activating the top-level plugin component. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig(learners=["acg"]), - acg=nemo_flow.adaptive.AcgConfig(provider="anthropic"), + telemetry=nemo_relay.adaptive.TelemetryConfig(learners=["acg"]), + acg=nemo_relay.adaptive.AcgConfig(provider="anthropic"), ) -runtime = nemo_flow.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) +runtime = nemo_relay.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) await runtime.register() try: # Run instrumented application work here. @@ -197,7 +197,7 @@ Use the Plugin Configuration example above when activating ACG from Node.js. :sync: rust ```rust -use nemo_flow_adaptive::{ +use nemo_relay_adaptive::{ AcgComponentConfig, AdaptiveConfig, AdaptiveRuntime, BackendSpec, StateConfig, TelemetryComponentConfig, }; diff --git a/docs/plugins/adaptive/adaptive-hints.md b/docs/plugins/adaptive/adaptive-hints.md index 64fe90445..791b0289c 100644 --- a/docs/plugins/adaptive/adaptive-hints.md +++ b/docs/plugins/adaptive/adaptive-hints.md @@ -44,7 +44,7 @@ allowing later request intercepts to continue running. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the +Use plugin configuration when the application should let NeMo Relay own the Adaptive Hints request-intercept lifecycle. ::::{tab-set} @@ -54,33 +54,33 @@ Adaptive Hints request-intercept lifecycle. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig(learners=["tool_parallelism"]), - adaptive_hints=nemo_flow.adaptive.AdaptiveHintsConfig( + telemetry=nemo_relay.adaptive.TelemetryConfig(learners=["tool_parallelism"]), + adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig( inject_body_path="nvext.agent_hints", ), ) -plugin_config = nemo_flow.plugin.PluginConfig( - components=[nemo_flow.adaptive.ComponentSpec(adaptive_config)] +plugin_config = nemo_relay.plugin.PluginConfig( + components=[nemo_relay.adaptive.ComponentSpec(adaptive_config)] ) -report = nemo_flow.plugin.validate(plugin_config) +report = nemo_relay.plugin.validate(plugin_config) if any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"]): raise RuntimeError(report["diagnostics"]) -await nemo_flow.plugin.initialize(plugin_config) +await nemo_relay.plugin.initialize(plugin_config) try: # Run instrumented application work here. pass finally: - nemo_flow.plugin.clear() + nemo_relay.plugin.clear() ``` ::: @@ -88,8 +88,8 @@ finally: :sync: node ```js -const adaptive = require("nemo-flow-node/adaptive"); -const plugin = require("nemo-flow-node/plugin"); +const adaptive = require("nemo-relay-node/adaptive"); +const plugin = require("nemo-relay-node/plugin"); const adaptiveConfig = adaptive.defaultConfig(); adaptiveConfig.agent_id = "planner"; @@ -120,9 +120,9 @@ try { :sync: rust ```rust -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; -use nemo_flow_adaptive::plugin_component::ComponentSpec; -use nemo_flow_adaptive::{ +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay_adaptive::plugin_component::ComponentSpec; +use nemo_relay_adaptive::{ AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, StateConfig, TelemetryComponentConfig, }; @@ -164,24 +164,24 @@ directly instead of activating the top-level plugin component. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig(learners=["tool_parallelism"]), - adaptive_hints=nemo_flow.adaptive.AdaptiveHintsConfig( + telemetry=nemo_relay.adaptive.TelemetryConfig(learners=["tool_parallelism"]), + adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig( inject_body_path="nvext.agent_hints", ), ) -runtime = nemo_flow.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) +runtime = nemo_relay.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) await runtime.register() try: # Run instrumented application work here. - nemo_flow.adaptive.set_latency_sensitivity(8) + nemo_relay.adaptive.set_latency_sensitivity(8) finally: await runtime.shutdown() ``` @@ -199,7 +199,7 @@ Hints from Node.js. :sync: rust ```rust -use nemo_flow_adaptive::{ +use nemo_relay_adaptive::{ set_latency_sensitivity, AdaptiveConfig, AdaptiveHintsComponentConfig, AdaptiveRuntime, BackendSpec, StateConfig, TelemetryComponentConfig, }; diff --git a/docs/plugins/adaptive/configuration.md b/docs/plugins/adaptive/configuration.md index 7e7aa8e40..109ef251a 100644 --- a/docs/plugins/adaptive/configuration.md +++ b/docs/plugins/adaptive/configuration.md @@ -8,7 +8,7 @@ SPDX-License-Identifier: Apache-2.0 Use this page when you want to configure the built-in Adaptive plugin component as a whole. The component kind is `adaptive`. -Adaptive plugin configuration uses the generic NeMo Flow plugin document shape. +Adaptive plugin configuration uses the generic NeMo Relay plugin document shape. Field names stay `snake_case` in every binding and in `plugins.toml`, even when language helper functions use language-native naming conventions. @@ -102,33 +102,33 @@ requests can be observed without provider-specific cache translation. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig( + telemetry=nemo_relay.adaptive.TelemetryConfig( subscriber_name="adaptive.telemetry", learners=["tool_parallelism"], ), - tool_parallelism=nemo_flow.adaptive.ToolParallelismConfig(mode="observe_only"), - adaptive_hints=nemo_flow.adaptive.AdaptiveHintsConfig( + tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig(mode="observe_only"), + adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig( inject_body_path="nvext.agent_hints", ), - acg=nemo_flow.adaptive.AcgConfig(provider="passthrough"), + acg=nemo_relay.adaptive.AcgConfig(provider="passthrough"), ) -plugin_config = nemo_flow.plugin.PluginConfig( - components=[nemo_flow.adaptive.ComponentSpec(adaptive_config)] +plugin_config = nemo_relay.plugin.PluginConfig( + components=[nemo_relay.adaptive.ComponentSpec(adaptive_config)] ) -report = nemo_flow.plugin.validate(plugin_config) +report = nemo_relay.plugin.validate(plugin_config) if any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"]): raise RuntimeError(report["diagnostics"]) -active = await nemo_flow.plugin.initialize(plugin_config) +active = await nemo_relay.plugin.initialize(plugin_config) ``` ::: @@ -136,8 +136,8 @@ active = await nemo_flow.plugin.initialize(plugin_config) :sync: node ```js -const adaptive = require("nemo-flow-node/adaptive"); -const plugin = require("nemo-flow-node/plugin"); +const adaptive = require("nemo-relay-node/adaptive"); +const plugin = require("nemo-relay-node/plugin"); const adaptiveConfig = adaptive.defaultConfig(); adaptiveConfig.agent_id = "planner"; @@ -168,9 +168,9 @@ const active = await plugin.initialize(pluginConfig); :sync: rust ```rust -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; -use nemo_flow_adaptive::plugin_component::ComponentSpec; -use nemo_flow_adaptive::{ +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay_adaptive::plugin_component::ComponentSpec; +use nemo_relay_adaptive::{ AdaptiveConfig, BackendSpec, StateConfig, @@ -223,25 +223,25 @@ directly instead of activating the top-level plugin component. :sync: python ```python -import nemo_flow +import nemo_relay -adaptive_config = nemo_flow.adaptive.AdaptiveConfig( +adaptive_config = nemo_relay.adaptive.AdaptiveConfig( agent_id="planner", - state=nemo_flow.adaptive.StateConfig( - backend=nemo_flow.adaptive.BackendSpec.in_memory(), + state=nemo_relay.adaptive.StateConfig( + backend=nemo_relay.adaptive.BackendSpec.in_memory(), ), - telemetry=nemo_flow.adaptive.TelemetryConfig( + telemetry=nemo_relay.adaptive.TelemetryConfig( subscriber_name="adaptive.telemetry", learners=["tool_parallelism"], ), - tool_parallelism=nemo_flow.adaptive.ToolParallelismConfig(mode="observe_only"), - adaptive_hints=nemo_flow.adaptive.AdaptiveHintsConfig( + tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig(mode="observe_only"), + adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig( inject_body_path="nvext.agent_hints", ), - acg=nemo_flow.adaptive.AcgConfig(provider="passthrough"), + acg=nemo_relay.adaptive.AcgConfig(provider="passthrough"), ) -runtime = nemo_flow.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) +runtime = nemo_relay.adaptive.AdaptiveRuntime(adaptive_config.to_dict()) await runtime.register() try: # Run instrumented application work here. @@ -263,7 +263,7 @@ activating adaptive behavior from Node.js. :sync: rust ```rust -use nemo_flow_adaptive::{ +use nemo_relay_adaptive::{ AcgComponentConfig, AdaptiveConfig, AdaptiveHintsComponentConfig, AdaptiveRuntime, BackendSpec, StateConfig, TelemetryComponentConfig, ToolParallelismComponentConfig, }; diff --git a/docs/plugins/observability/about.md b/docs/plugins/observability/about.md index 8215c22ae..81b8741d9 100644 --- a/docs/plugins/observability/about.md +++ b/docs/plugins/observability/about.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # Observability -Use the Observability plugin when you need to inspect NeMo Flow lifecycle events +Use the Observability plugin when you need to inspect NeMo Relay lifecycle events in process or export agent activity to tracing, trajectory, or analysis systems from one plugin configuration document. -Observability in NeMo Flow starts with events. Scopes, marks, managed tool +Observability in NeMo Relay starts with events. Scopes, marks, managed tool calls, managed LLM calls, middleware, and manual lifecycle APIs emit the canonical Agent Trajectory Observability Format (ATOF) event stream. Subscribers consume that stream in process, and exporter-oriented subscribers @@ -62,15 +62,15 @@ guardrails before exporters receive sensitive payloads. ## Correlating Trajectories And Traces -When ATIF and trace exporters observe the same NeMo Flow events, they share -NeMo Flow UUIDs for cross-format joins. Plugin-managed ATIF uses the top-level +When ATIF and trace exporters observe the same NeMo Relay events, they share +NeMo Relay UUIDs for cross-format joins. Plugin-managed ATIF uses the top-level agent scope UUID as the trajectory `session_id`. ATIF step lineage stores the event UUID as `step.extra.ancestry.function_id` and the parent UUID as `step.extra.ancestry.parent_id`. OpenTelemetry and OpenInference spans carry the same values as -`nemo_flow.uuid` and `nemo_flow.parent_uuid` span attributes. Mark events use -`nemo_flow.mark.uuid` and `nemo_flow.mark.parent_uuid`. Native backend +`nemo_relay.uuid` and `nemo_relay.parent_uuid` span attributes. Mark events use +`nemo_relay.mark.uuid` and `nemo_relay.mark.parent_uuid`. Native backend `trace_id` and `span_id` values are still generated by the tracing backend and are not written into ATIF. diff --git a/docs/plugins/observability/atif.md b/docs/plugins/observability/atif.md index fba2e0b22..df0d48d3c 100644 --- a/docs/plugins/observability/atif.md +++ b/docs/plugins/observability/atif.md @@ -42,17 +42,17 @@ This configuration writes a trajectory file such as | Field | Default | Notes | |---|---|---| | `enabled` | `false` | Must be `true` to write trajectories. | -| `agent_name` | `NeMo Flow` | Agent metadata written into the trajectory. | -| `agent_version` | NeMo Flow crate version | Agent version metadata. | +| `agent_name` | `NeMo Relay` | Agent metadata written into the trajectory. | +| `agent_version` | NeMo Relay crate version | Agent version metadata. | | `model_name` | `unknown` | Default model metadata when no call-level model is present. | | `tool_definitions` | Omitted | Optional ATIF tool metadata. | | `extra` | Omitted | Optional ATIF agent metadata. | | `output_directory` | Current working directory | Directory containing trajectory files. | -| `filename_template` | `nemo-flow-atif-{session_id}.json` | Must contain `{session_id}`. | +| `filename_template` | `nemo-relay-atif-{session_id}.json` | Must contain `{session_id}`. | ## Expected Output -The exporter translates NeMo Flow lifecycle events into ATIF v1.6 trajectory +The exporter translates NeMo Relay lifecycle events into ATIF v1.6 trajectory data. LLM start and end events become model steps, tool events become tool calls and observations, and scope nesting contributes lineage metadata. @@ -61,14 +61,14 @@ plugin is cleared while an agent is still open, teardown flushes the partial trajectory. To correlate ATIF with OpenTelemetry or OpenInference traces from the same run, -join on NeMo Flow UUIDs. The plugin-managed ATIF `session_id` is the top-level +join on NeMo Relay UUIDs. The plugin-managed ATIF `session_id` is the top-level agent scope UUID. Each step's `extra.ancestry.function_id` is the event UUID, and `extra.ancestry.parent_id` is the parent event UUID. Trace spans expose the -same values as `nemo_flow.uuid` and `nemo_flow.parent_uuid` attributes. +same values as `nemo_relay.uuid` and `nemo_relay.parent_uuid` attributes. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the ATIF +Use plugin configuration when the application should let NeMo Relay own the ATIF dispatcher lifecycle. :::::{tab-set} @@ -78,8 +78,8 @@ dispatcher lifecycle. :sync: python ```python -from nemo_flow import plugin -from nemo_flow.observability import AtifConfig, ComponentSpec, ObservabilityConfig +from nemo_relay import plugin +from nemo_relay.observability import AtifConfig, ComponentSpec, ObservabilityConfig config = plugin.PluginConfig( components=[ @@ -116,8 +116,8 @@ finally: :sync: node ```js -const plugin = require("nemo-flow-node/plugin"); -const observability = require("nemo-flow-node/observability"); +const plugin = require("nemo-relay-node/plugin"); +const observability = require("nemo-relay-node/observability"); await plugin.initialize({ version: 1, @@ -149,10 +149,10 @@ try { :sync: rust ```rust -use nemo_flow::observability::plugin_component::{ +use nemo_relay::observability::plugin_component::{ AtifSectionConfig, ComponentSpec, ObservabilityConfig, }; -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; let component = ComponentSpec::new(ObservabilityConfig { atif: Some(AtifSectionConfig { @@ -195,7 +195,7 @@ or one exporter object per run. :sync: python ```python -from nemo_flow import AtifExporter +from nemo_relay import AtifExporter exporter = AtifExporter("session-1", "agent", "1.0.0", model_name="demo-model") exporter.register("atif-exporter") @@ -213,7 +213,7 @@ exporter.clear() :sync: node ```js -const { AtifExporter } = require("nemo-flow-node"); +const { AtifExporter } = require("nemo-relay-node"); const exporter = new AtifExporter("session-1", "agent", "1.0.0", "demo-model"); exporter.register("atif-exporter"); @@ -235,8 +235,8 @@ try { :sync: rust ```rust -use nemo_flow::api::subscriber::{deregister_subscriber, register_subscriber}; -use nemo_flow::observability::atif::{AtifAgentInfo, AtifExporter}; +use nemo_relay::api::subscriber::{deregister_subscriber, register_subscriber}; +use nemo_relay::observability::atif::{AtifAgentInfo, AtifExporter}; let exporter = AtifExporter::new( "session-1".to_string(), diff --git a/docs/plugins/observability/atof.md b/docs/plugins/observability/atof.md index 9e9f8c18c..d03a63a91 100644 --- a/docs/plugins/observability/atof.md +++ b/docs/plugins/observability/atof.md @@ -40,7 +40,7 @@ JSON object per lifecycle event to `logs/events.jsonl`. |---|---|---| | `enabled` | `false` | Must be `true` to write events. | | `output_directory` | Current working directory | Directory containing the JSONL file. | -| `filename` | Timestamped `nemo-flow-events-*.jsonl` | Explicit output filename. | +| `filename` | Timestamped `nemo-relay-events-*.jsonl` | Explicit output filename. | | `mode` | `append` | `append` or `overwrite`. | ## Expected Output @@ -54,7 +54,7 @@ shutdown so file handles flush. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the ATOF +Use plugin configuration when the application should let NeMo Relay own the ATOF exporter lifecycle. :::::{tab-set} @@ -64,8 +64,8 @@ exporter lifecycle. :sync: python ```python -from nemo_flow import plugin -from nemo_flow.observability import AtofConfig, ComponentSpec, ObservabilityConfig +from nemo_relay import plugin +from nemo_relay.observability import AtofConfig, ComponentSpec, ObservabilityConfig config = plugin.PluginConfig( components=[ @@ -100,8 +100,8 @@ finally: :sync: node ```js -const plugin = require("nemo-flow-node/plugin"); -const observability = require("nemo-flow-node/observability"); +const plugin = require("nemo-relay-node/plugin"); +const observability = require("nemo-relay-node/observability"); await plugin.initialize({ version: 1, @@ -131,10 +131,10 @@ try { :sync: rust ```rust -use nemo_flow::observability::plugin_component::{ +use nemo_relay::observability::plugin_component::{ AtofSectionConfig, ComponentSpec, ObservabilityConfig, }; -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; let component = ComponentSpec::new(ObservabilityConfig { atof: Some(AtofSectionConfig { @@ -174,7 +174,7 @@ subscriber name or explicit registration window. :sync: python ```python -from nemo_flow import AtofExporter, AtofExporterConfig, AtofExporterMode +from nemo_relay import AtofExporter, AtofExporterConfig, AtofExporterMode config = AtofExporterConfig() config.output_directory = "logs" @@ -197,7 +197,7 @@ exporter.shutdown() :sync: node ```js -const { AtofExporter } = require("nemo-flow-node"); +const { AtofExporter } = require("nemo-relay-node"); const exporter = new AtofExporter({ outputDirectory: "logs", @@ -222,7 +222,7 @@ try { :sync: rust ```rust -use nemo_flow::observability::atof::{ +use nemo_relay::observability::atof::{ AtofExporter, AtofExporterConfig, AtofExporterMode, }; diff --git a/docs/plugins/observability/configuration.md b/docs/plugins/observability/configuration.md index 7dd7b9c4d..44b06262c 100644 --- a/docs/plugins/observability/configuration.md +++ b/docs/plugins/observability/configuration.md @@ -18,7 +18,7 @@ gateway conflict rules, see [Plugin Configuration Files](../../build-plugins/plugin-configuration-files.md). :::{note} -Observability plugin configuration uses the generic NeMo Flow plugin document +Observability plugin configuration uses the generic NeMo Relay plugin document shape, so field names are `snake_case` in every binding. This differs from Node.js runtime classes such as `OpenTelemetrySubscriber`, which use Node-native `camelCase` option names outside the plugin system. @@ -40,11 +40,11 @@ only when it includes `enabled: true`. component-local subscriber names and registers them under the observability plugin namespace: -- Agent Trajectory Observability Format (ATOF): `__nemo_flow_plugin__observability__atof` -- Agent Trajectory Interchange Format (ATIF) dispatcher: `__nemo_flow_plugin__observability__atif` -- Per-agent ATIF scope subscriber: `__nemo_flow_plugin__observability__atif-{agent_scope_uuid}` -- OpenTelemetry: `__nemo_flow_plugin__observability__opentelemetry` -- OpenInference: `__nemo_flow_plugin__observability__openinference` +- Agent Trajectory Observability Format (ATOF): `__nemo_relay_plugin__observability__atof` +- Agent Trajectory Interchange Format (ATIF) dispatcher: `__nemo_relay_plugin__observability__atif` +- Per-agent ATIF scope subscriber: `__nemo_relay_plugin__observability__atif-{agent_scope_uuid}` +- OpenTelemetry: `__nemo_relay_plugin__observability__opentelemetry` +- OpenInference: `__nemo_relay_plugin__observability__openinference` ## `plugins.toml` Example @@ -73,10 +73,10 @@ filename_template = "trajectory-{session_id}.json" enabled = true transport = "http_binary" endpoint = "http://localhost:4318/v1/traces" -service_name = "nemo-flow" +service_name = "nemo-relay" service_namespace = "agent" service_version = "0.3.0" -instrumentation_scope = "nemo-flow-observability" +instrumentation_scope = "nemo-relay-observability" timeout_millis = 3000 [components.config.opentelemetry.headers] @@ -90,10 +90,10 @@ authorization = "Bearer " enabled = true transport = "http_binary" endpoint = "http://localhost:6006/v1/traces" -service_name = "nemo-flow" +service_name = "nemo-relay" service_namespace = "agent" service_version = "0.3.0" -instrumentation_scope = "nemo-flow-openinference" +instrumentation_scope = "nemo-relay-openinference" timeout_millis = 3000 [components.config.openinference.headers] @@ -122,8 +122,8 @@ disable an inherited section. :sync: python ```python -from nemo_flow import plugin, scope, ScopeType -from nemo_flow.observability import ( +from nemo_relay import plugin, scope, ScopeType +from nemo_relay.observability import ( AtifConfig, AtofConfig, ComponentSpec, @@ -149,19 +149,19 @@ config = plugin.PluginConfig( opentelemetry=OtlpConfig( enabled=True, endpoint="http://localhost:4318/v1/traces", - service_name="nemo-flow", + service_name="nemo-relay", service_namespace="agent", service_version="0.3.0", - instrumentation_scope="nemo-flow-observability", + instrumentation_scope="nemo-relay-observability", resource_attributes={"deployment.environment": "dev"}, ), openinference=OtlpConfig( enabled=True, endpoint="http://localhost:6006/v1/traces", - service_name="nemo-flow", + service_name="nemo-relay", service_namespace="agent", service_version="0.3.0", - instrumentation_scope="nemo-flow-openinference", + instrumentation_scope="nemo-relay-openinference", resource_attributes={"deployment.environment": "dev"}, ), ) @@ -187,8 +187,8 @@ finally: :sync: node ```js -const plugin = require("nemo-flow-node/plugin"); -const observability = require("nemo-flow-node/observability"); +const plugin = require("nemo-relay-node/plugin"); +const observability = require("nemo-relay-node/observability"); await plugin.initialize({ version: 1, @@ -209,10 +209,10 @@ await plugin.initialize({ opentelemetry: observability.otlpConfig({ enabled: true, endpoint: "http://localhost:4318/v1/traces", - service_name: "nemo-flow", + service_name: "nemo-relay", service_namespace: "agent", service_version: "0.3.0", - instrumentation_scope: "nemo-flow-observability", + instrumentation_scope: "nemo-relay-observability", resource_attributes: { "deployment.environment": "dev", }, @@ -220,10 +220,10 @@ await plugin.initialize({ openinference: observability.otlpConfig({ enabled: true, endpoint: "http://localhost:6006/v1/traces", - service_name: "nemo-flow", + service_name: "nemo-relay", service_namespace: "agent", service_version: "0.3.0", - instrumentation_scope: "nemo-flow-openinference", + instrumentation_scope: "nemo-relay-openinference", resource_attributes: { "deployment.environment": "dev", }, @@ -245,11 +245,11 @@ try { :sync: rust ```rust -use nemo_flow::observability::plugin_component::{ +use nemo_relay::observability::plugin_component::{ AtifSectionConfig, AtofSectionConfig, ComponentSpec, ObservabilityConfig, OtlpSectionConfig, }; -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; let component = ComponentSpec::new(ObservabilityConfig { atof: Some(AtofSectionConfig { @@ -267,20 +267,20 @@ let component = ComponentSpec::new(ObservabilityConfig { opentelemetry: Some(OtlpSectionConfig { enabled: true, endpoint: Some("http://localhost:4318/v1/traces".into()), - service_name: "nemo-flow".into(), + service_name: "nemo-relay".into(), service_namespace: Some("agent".into()), service_version: Some("0.3.0".into()), - instrumentation_scope: Some("nemo-flow-observability".into()), + instrumentation_scope: Some("nemo-relay-observability".into()), resource_attributes: [("deployment.environment".into(), "dev".into())].into(), ..OtlpSectionConfig::default() }), openinference: Some(OtlpSectionConfig { enabled: true, endpoint: Some("http://localhost:6006/v1/traces".into()), - service_name: "nemo-flow".into(), + service_name: "nemo-relay".into(), service_namespace: Some("agent".into()), service_version: Some("0.3.0".into()), - instrumentation_scope: Some("nemo-flow-openinference".into()), + instrumentation_scope: Some("nemo-relay-openinference".into()), resource_attributes: [("deployment.environment".into(), "dev".into())].into(), ..OtlpSectionConfig::default() }), diff --git a/docs/plugins/observability/openinference.md b/docs/plugins/observability/openinference.md index 43e389060..ea83a8b85 100644 --- a/docs/plugins/observability/openinference.md +++ b/docs/plugins/observability/openinference.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # OpenInference -Use the `openinference` section when you want NeMo Flow lifecycle events +Use the `openinference` section when you want NeMo Relay lifecycle events exported as OTLP trace spans with OpenInference-oriented semantics. OpenInference export maps model-centric payloads directly into trace @@ -32,7 +32,7 @@ endpoint = "http://localhost:6006/v1/traces" service_name = "agent-service" service_namespace = "nemo" service_version = "1.0.0" -instrumentation_scope = "nemo-flow-openinference" +instrumentation_scope = "nemo-relay-openinference" timeout_millis = 3000 [components.config.openinference.headers] @@ -57,7 +57,7 @@ OpenInference uses the same OTLP section shape as | `endpoint` | Exporter default | OTLP endpoint. | | `headers` | `{}` | String-to-string exporter headers. | | `resource_attributes` | `{}` | String-to-string OTLP resource attributes. | -| `service_name` | `nemo-flow` | `service.name` resource attribute. | +| `service_name` | `nemo-relay` | `service.name` resource attribute. | | `service_namespace` | Omitted | Optional `service.namespace`. | | `service_version` | Omitted | Optional `service.version`. | | `instrumentation_scope` | Omitted | Optional instrumentation scope name. | @@ -69,10 +69,10 @@ The backend should show OpenInference-oriented spans for scopes, tools, and LLM calls grouped by root scope. LLM usage metadata appears as token counters when provider responses include usage information. -Each lifecycle span includes `nemo_flow.uuid` and `nemo_flow.parent_uuid` +Each lifecycle span includes `nemo_relay.uuid` and `nemo_relay.parent_uuid` attributes. These values match ATIF `step.extra.ancestry.function_id` and `step.extra.ancestry.parent_id` for the same events. For plugin-managed ATIF, -the root agent span's `nemo_flow.uuid` also matches the ATIF `session_id`. +the root agent span's `nemo_relay.uuid` also matches the ATIF `session_id`. Backend-native `trace_id` and `span_id` values are not written into ATIF. Redact sensitive event payloads with sanitize guardrails before production @@ -80,7 +80,7 @@ export. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the +Use plugin configuration when the application should let NeMo Relay own the OpenInference subscriber lifecycle. :::::{tab-set} @@ -90,8 +90,8 @@ OpenInference subscriber lifecycle. :sync: python ```python -from nemo_flow import plugin -from nemo_flow.observability import ComponentSpec, ObservabilityConfig, OtlpConfig +from nemo_relay import plugin +from nemo_relay.observability import ComponentSpec, ObservabilityConfig, OtlpConfig config = plugin.PluginConfig( components=[ @@ -104,7 +104,7 @@ config = plugin.PluginConfig( service_name="agent-service", service_namespace="nemo", service_version="1.0.0", - instrumentation_scope="nemo-flow-openinference", + instrumentation_scope="nemo-relay-openinference", resource_attributes={"deployment.environment": "dev"}, headers={"authorization": "Bearer "}, ) @@ -131,8 +131,8 @@ finally: :sync: node ```js -const plugin = require("nemo-flow-node/plugin"); -const observability = require("nemo-flow-node/observability"); +const plugin = require("nemo-relay-node/plugin"); +const observability = require("nemo-relay-node/observability"); await plugin.initialize({ version: 1, @@ -146,7 +146,7 @@ await plugin.initialize({ service_name: "agent-service", service_namespace: "nemo", service_version: "1.0.0", - instrumentation_scope: "nemo-flow-openinference", + instrumentation_scope: "nemo-relay-openinference", resource_attributes: { "deployment.environment": "dev", }, @@ -171,10 +171,10 @@ try { :sync: rust ```rust -use nemo_flow::observability::plugin_component::{ +use nemo_relay::observability::plugin_component::{ ComponentSpec, ObservabilityConfig, OtlpSectionConfig, }; -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; let component = ComponentSpec::new(ObservabilityConfig { openinference: Some(OtlpSectionConfig { @@ -184,7 +184,7 @@ let component = ComponentSpec::new(ObservabilityConfig { service_name: "agent-service".into(), service_namespace: Some("nemo".into()), service_version: Some("1.0.0".into()), - instrumentation_scope: Some("nemo-flow-openinference".into()), + instrumentation_scope: Some("nemo-relay-openinference".into()), resource_attributes: [("deployment.environment".into(), "dev".into())].into(), headers: [("authorization".into(), "Bearer ".into())].into(), ..OtlpSectionConfig::default() @@ -220,7 +220,7 @@ direct `force_flush` control. :sync: python ```python -from nemo_flow import OpenInferenceConfig, OpenInferenceSubscriber +from nemo_relay import OpenInferenceConfig, OpenInferenceSubscriber config = OpenInferenceConfig() config.transport = "http_binary" @@ -244,7 +244,7 @@ subscriber.shutdown() :sync: node ```js -const { OpenInferenceSubscriber } = require("nemo-flow-node"); +const { OpenInferenceSubscriber } = require("nemo-relay-node"); const subscriber = new OpenInferenceSubscriber({ transport: "http_binary", @@ -272,7 +272,7 @@ try { :sync: rust ```rust -use nemo_flow::observability::openinference::{ +use nemo_relay::observability::openinference::{ OpenInferenceConfig, OpenInferenceSubscriber, }; diff --git a/docs/plugins/observability/opentelemetry.md b/docs/plugins/observability/opentelemetry.md index 53791e006..30e48bbcd 100644 --- a/docs/plugins/observability/opentelemetry.md +++ b/docs/plugins/observability/opentelemetry.md @@ -5,11 +5,11 @@ SPDX-License-Identifier: Apache-2.0 # OpenTelemetry -Use the `opentelemetry` section when you want NeMo Flow lifecycle events +Use the `opentelemetry` section when you want NeMo Relay lifecycle events exported as generic OpenTelemetry Protocol (OTLP) trace spans. OpenTelemetry export is a good fit when your tracing backend already expects -OTLP spans and you want NeMo Flow scopes, tool calls, LLM calls, and marks to +OTLP spans and you want NeMo Relay scopes, tool calls, LLM calls, and marks to appear in the same tracing pipeline as the rest of the application. ## `plugins.toml` Example @@ -31,7 +31,7 @@ endpoint = "http://localhost:4318/v1/traces" service_name = "agent-service" service_namespace = "nemo" service_version = "1.0.0" -instrumentation_scope = "nemo-flow-otel" +instrumentation_scope = "nemo-relay-otel" timeout_millis = 3000 [components.config.opentelemetry.headers] @@ -42,7 +42,7 @@ authorization = "Bearer " ``` This configuration registers a plugin-owned OpenTelemetry subscriber and sends -NeMo Flow trace spans to the configured OTLP endpoint. +NeMo Relay trace spans to the configured OTLP endpoint. ## Fields @@ -53,7 +53,7 @@ NeMo Flow trace spans to the configured OTLP endpoint. | `endpoint` | Exporter default | OTLP endpoint. | | `headers` | `{}` | String-to-string exporter headers. | | `resource_attributes` | `{}` | String-to-string OTLP resource attributes. | -| `service_name` | `nemo-flow` | `service.name` resource attribute. | +| `service_name` | `nemo-relay` | `service.name` resource attribute. | | `service_namespace` | Omitted | Optional `service.namespace`. | | `service_version` | Omitted | Optional `service.version`. | | `instrumentation_scope` | Omitted | Optional instrumentation scope name. | @@ -62,13 +62,13 @@ NeMo Flow trace spans to the configured OTLP endpoint. ## Expected Output The collector should receive OTLP trace export requests. The tracing backend -should show spans for NeMo Flow scopes, tools, LLM calls, and marks grouped by +should show spans for NeMo Relay scopes, tools, LLM calls, and marks grouped by root scope. -Each lifecycle span includes `nemo_flow.uuid` and `nemo_flow.parent_uuid` +Each lifecycle span includes `nemo_relay.uuid` and `nemo_relay.parent_uuid` attributes. These values match ATIF `step.extra.ancestry.function_id` and `step.extra.ancestry.parent_id` for the same events. For plugin-managed ATIF, -the root agent span's `nemo_flow.uuid` also matches the ATIF `session_id`. +the root agent span's `nemo_relay.uuid` also matches the ATIF `session_id`. Backend-native `trace_id` and `span_id` values are not written into ATIF. Register the plugin before the first instrumented request, use stable service @@ -77,7 +77,7 @@ graceful shutdown. ## Plugin Configuration -Use plugin configuration when the application should let NeMo Flow own the +Use plugin configuration when the application should let NeMo Relay own the OpenTelemetry subscriber lifecycle. :::::{tab-set} @@ -87,8 +87,8 @@ OpenTelemetry subscriber lifecycle. :sync: python ```python -from nemo_flow import plugin -from nemo_flow.observability import ComponentSpec, ObservabilityConfig, OtlpConfig +from nemo_relay import plugin +from nemo_relay.observability import ComponentSpec, ObservabilityConfig, OtlpConfig config = plugin.PluginConfig( components=[ @@ -101,7 +101,7 @@ config = plugin.PluginConfig( service_name="agent-service", service_namespace="nemo", service_version="1.0.0", - instrumentation_scope="nemo-flow-otel", + instrumentation_scope="nemo-relay-otel", resource_attributes={"deployment.environment": "dev"}, headers={"authorization": "Bearer "}, ) @@ -128,8 +128,8 @@ finally: :sync: node ```js -const plugin = require("nemo-flow-node/plugin"); -const observability = require("nemo-flow-node/observability"); +const plugin = require("nemo-relay-node/plugin"); +const observability = require("nemo-relay-node/observability"); await plugin.initialize({ version: 1, @@ -143,7 +143,7 @@ await plugin.initialize({ service_name: "agent-service", service_namespace: "nemo", service_version: "1.0.0", - instrumentation_scope: "nemo-flow-otel", + instrumentation_scope: "nemo-relay-otel", resource_attributes: { "deployment.environment": "dev", }, @@ -168,10 +168,10 @@ try { :sync: rust ```rust -use nemo_flow::observability::plugin_component::{ +use nemo_relay::observability::plugin_component::{ ComponentSpec, ObservabilityConfig, OtlpSectionConfig, }; -use nemo_flow::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; +use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; let component = ComponentSpec::new(ObservabilityConfig { opentelemetry: Some(OtlpSectionConfig { @@ -181,7 +181,7 @@ let component = ComponentSpec::new(ObservabilityConfig { service_name: "agent-service".into(), service_namespace: Some("nemo".into()), service_version: Some("1.0.0".into()), - instrumentation_scope: Some("nemo-flow-otel".into()), + instrumentation_scope: Some("nemo-relay-otel".into()), resource_attributes: [("deployment.environment".into(), "dev".into())].into(), headers: [("authorization".into(), "Bearer ".into())].into(), ..OtlpSectionConfig::default() @@ -217,7 +217,7 @@ direct `force_flush` control. :sync: python ```python -from nemo_flow import OpenTelemetryConfig, OpenTelemetrySubscriber +from nemo_relay import OpenTelemetryConfig, OpenTelemetrySubscriber config = OpenTelemetryConfig() config.transport = "http_binary" @@ -241,7 +241,7 @@ subscriber.shutdown() :sync: node ```js -const { OpenTelemetrySubscriber } = require("nemo-flow-node"); +const { OpenTelemetrySubscriber } = require("nemo-relay-node"); const subscriber = new OpenTelemetrySubscriber({ transport: "http_binary", @@ -269,7 +269,7 @@ try { :sync: rust ```rust -use nemo_flow::observability::otel::{OpenTelemetryConfig, OpenTelemetrySubscriber}; +use nemo_relay::observability::otel::{OpenTelemetryConfig, OpenTelemetrySubscriber}; let config = OpenTelemetryConfig::http_binary("agent-service") .with_endpoint("http://localhost:4318/v1/traces") diff --git a/docs/reference/api/nodejs/index.md b/docs/reference/api/nodejs/index.md index d8e5a43e4..ec63941cc 100644 --- a/docs/reference/api/nodejs/index.md +++ b/docs/reference/api/nodejs/index.md @@ -11,7 +11,7 @@ These pages are generated from the exported TypeScript declaration surfaces in ` This summary lists the package identity and support status for the binding. -- Package name: `nemo-flow-node` +- Package name: `nemo-relay-node` - Runtime requirement: Node.js `>=20` - Local development path: `crates/node` @@ -24,10 +24,10 @@ for typed helpers, plugin helpers, adaptive helpers, and observability helpers. These entry points are the primary APIs to use from this binding. - Package root: scope stack, event, tool, LLM, middleware, and subscriber APIs -- `nemo-flow-node/typed`: typed wrappers and codec-aware execution helpers -- `nemo-flow-node/plugin`: plugin-facing helpers and configuration types -- `nemo-flow-node/adaptive`: adaptive helpers layered on top of the runtime -- `nemo-flow-node/observability`: built-in observability plugin helpers +- `nemo-relay-node/typed`: typed wrappers and codec-aware execution helpers +- `nemo-relay-node/plugin`: plugin-facing helpers and configuration types +- `nemo-relay-node/adaptive`: adaptive helpers layered on top of the runtime +- `nemo-relay-node/observability`: built-in observability plugin helpers ## How To Read The Generated Pages diff --git a/docs/reference/api/python/index.md b/docs/reference/api/python/index.md index 608af0fad..14dce98ea 100644 --- a/docs/reference/api/python/index.md +++ b/docs/reference/api/python/index.md @@ -5,18 +5,18 @@ SPDX-License-Identifier: Apache-2.0 # Python API -These pages are generated from the `python/nemo_flow` package source. +These pages are generated from the `python/nemo_relay` package source. ## Binding At A Glance This summary lists the package identity and support status for the binding. -- Package name: `nemo-flow` +- Package name: `nemo-relay` - Local development path: repository root `pyproject.toml` with `uv sync` -- Generated package root: `nemo_flow` +- Generated package root: `nemo_relay` The Python binding exposes the runtime through a public package layer in -`python/nemo_flow` and a compiled native extension exposed as `nemo_flow._native`. +`python/nemo_relay` and a compiled native extension exposed as `nemo_relay._native`. Most users should work from the public package modules rather than the native layer directly. @@ -24,17 +24,17 @@ layer directly. These entry points are the primary APIs to use from this binding. -- `nemo_flow.scope`: create scopes, emit mark events, and manage scope handles -- `nemo_flow.tools` and `nemo_flow.llm`: run tool and LLM lifecycles from Python -- `nemo_flow.guardrails` and `nemo_flow.intercepts`: register global middleware -- `nemo_flow.scope_local`: register middleware against a specific scope hierarchy -- `nemo_flow.subscribers`: observe emitted runtime lifecycle events -- `nemo_flow.plugin`, `nemo_flow.adaptive`, and `nemo_flow.observability`: configure plugin-backed, adaptive, and exporter behavior -- `nemo_flow.typed` and `nemo_flow.codecs`: use typed wrappers and request/response codecs +- `nemo_relay.scope`: create scopes, emit mark events, and manage scope handles +- `nemo_relay.tools` and `nemo_relay.llm`: run tool and LLM lifecycles from Python +- `nemo_relay.guardrails` and `nemo_relay.intercepts`: register global middleware +- `nemo_relay.scope_local`: register middleware against a specific scope hierarchy +- `nemo_relay.subscribers`: observe emitted runtime lifecycle events +- `nemo_relay.plugin`, `nemo_relay.adaptive`, and `nemo_relay.observability`: configure plugin-backed, adaptive, and exporter behavior +- `nemo_relay.typed` and `nemo_relay.codecs`: use typed wrappers and request/response codecs ## How To Read The Generated Pages -The generated `nemo_flow` package page is the package root. Under that page you +The generated `nemo_relay` package page is the package root. Under that page you will find submodule pages for the public binding surface, including: - `llm` @@ -50,13 +50,13 @@ will find submodule pages for the public binding surface, including: - `typed` - `codecs` -Use the {doc}`generated Python package index <_generated/nemo_flow/index>` +Use the {doc}`generated Python package index <_generated/nemo_relay/index>` when you want the docstring-level details for a specific symbol or module. ```{toctree} :maxdepth: 1 -nemo_flow <_generated/nemo_flow/index> +nemo_relay <_generated/nemo_relay/index> ``` ## Related Guides diff --git a/docs/reference/api/rust/index.md b/docs/reference/api/rust/index.md index fb6c5e419..7bc0bb25c 100644 --- a/docs/reference/api/rust/index.md +++ b/docs/reference/api/rust/index.md @@ -11,8 +11,8 @@ These pages are generated from the public Rust crates that back the core runtime This summary lists the package identity and support status for the binding. -- Published crates: `nemo-flow`, `nemo-flow-adaptive`, `nemo-flow-ffi`, and - `nemo-flow-cli` +- Published crates: `nemo-relay`, `nemo-relay-adaptive`, `nemo-relay-ffi`, and + `nemo-relay-cli` - Local development paths: `crates/core`, `crates/adaptive`, `crates/ffi`, and `crates/cli` - Primary audience: Rust consumers who want the native runtime surface directly @@ -25,44 +25,44 @@ module tree. These entry points are the primary APIs to use from this binding. -- `nemo-flow`: core runtime APIs for scopes, tools, LLMs, registries, subscribers, codecs, streams, observability exporters, and the built-in observability plugin -- `nemo-flow-adaptive`: adaptive runtime helpers, learner implementations, storage backends, and adaptive configuration -- `nemo-flow-cli`: binary gateway for coding-agent hooks and passthrough LLM observability -- `nemo-flow-ffi`: raw C ABI used by downstream native bindings +- `nemo-relay`: core runtime APIs for scopes, tools, LLMs, registries, subscribers, codecs, streams, observability exporters, and the built-in observability plugin +- `nemo-relay-adaptive`: adaptive runtime helpers, learner implementations, storage backends, and adaptive configuration +- `nemo-relay-cli`: binary gateway for coding-agent hooks and passthrough LLM observability +- `nemo-relay-ffi`: raw C ABI used by downstream native bindings -Within `nemo-flow`, most integrations start in `api`, especially the `scope`, +Within `nemo-relay`, most integrations start in `api`, especially the `scope`, `tool`, `llm`, `registry`, and `subscriber` modules. Other important public modules include `codec`, `observability`, `stream`, `error`, and `json`. The `observability::plugin_component` module contains the built-in `observability` plugin config types. -Within `nemo-flow-adaptive`, the main surfaces include adaptive configuration, +Within `nemo-relay-adaptive`, the main surfaces include adaptive configuration, plugin components, storage abstractions, learners, trie-backed data structures, and optional Redis-backed helpers when the feature is enabled. -`nemo-flow-cli` is a binary crate, so its end-user surface is documented in -the NeMo Flow CLI guides rather than generated Rust API pages. +`nemo-relay-cli` is a binary crate, so its end-user surface is documented in +the NeMo Relay CLI guides rather than generated Rust API pages. ## How To Read The Generated Pages Use the crate pages first, then expand into the public modules under each crate: -- `nemo-flow` for core runtime behavior -- `nemo-flow-adaptive` for adaptive and learning-oriented behavior -- `nemo-flow-cli` for coding-agent observability through hooks and the +- `nemo-relay` for core runtime behavior +- `nemo-relay-adaptive` for adaptive and learning-oriented behavior +- `nemo-relay-cli` for coding-agent observability through hooks and the passthrough LLM gateway That structure matches how Rust consumers import items from the crates. Use the generated crate entry points when you need symbol-level detail: -- {doc}`nemo_flow <_generated/nemo-flow/src>` -- {doc}`nemo_flow_adaptive <_generated/nemo-flow-adaptive/src>` +- {doc}`nemo_relay <_generated/nemo-relay/src>` +- {doc}`nemo_relay_adaptive <_generated/nemo-relay-adaptive/src>` ```{toctree} :maxdepth: 1 -nemo-flow <_generated/nemo-flow/src> -nemo-flow-adaptive <_generated/nemo-flow-adaptive/src> +nemo-relay <_generated/nemo-relay/src> +nemo-relay-adaptive <_generated/nemo-relay-adaptive/src> ``` ## Related Guides @@ -79,4 +79,4 @@ Use these links to continue from the API reference into task-focused guides. - [Observability Configuration](../../../plugins/observability/configuration.md) - [Typed Wrappers and Codecs](../../../integrate-frameworks/using-codecs.md) - [Framework Integration Surfaces](../../../integrate-frameworks/about.md) -- [NeMo Flow CLI Basic Usage](../../../nemo-flow-cli/basic-usage.md) +- [NeMo Relay CLI Basic Usage](../../../nemo-relay-cli/basic-usage.md) diff --git a/docs/reference/performance.md b/docs/reference/performance.md index ba6443604..1b579605f 100644 --- a/docs/reference/performance.md +++ b/docs/reference/performance.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Performance -NeMo Flow keeps runtime overhead focused around the work that is active for the current scope and call. +NeMo Relay keeps runtime overhead focused around the work that is active for the current scope and call. ## Runtime Model diff --git a/docs/resources/glossary.md b/docs/resources/glossary.md index f4d5c71ec..60e77e599 100644 --- a/docs/resources/glossary.md +++ b/docs/resources/glossary.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Glossary -NeMo Flow uses specialized runtime, integration, plugin, adaptive, and +NeMo Relay uses specialized runtime, integration, plugin, adaptive, and observability terms across bindings. This glossary defines the shared terms so the rest of the documentation can use them consistently. @@ -34,7 +34,7 @@ Adaptive Hint hint to adjust behavior when explicitly configured to do so. Adaptive Tuning - **Adaptive tuning** is the NeMo Flow runtime capability that observes + **Adaptive tuning** is the NeMo Relay runtime capability that observes instrumented work and enables controlled behavior changes through the plugin system. @@ -49,12 +49,12 @@ Adaptive Telemetry Agent Trajectory Interchange Format (ATIF) **Agent Trajectory Interchange Format (ATIF)** is an external trajectory - format used for offline analysis, replay, or evaluation. The NeMo Flow ATIF + format used for offline analysis, replay, or evaluation. The NeMo Relay ATIF exporter collects lifecycle events and exports ATIF v1.6 trajectory data. Agent Trajectory Observability Format (ATOF) **Agent Trajectory Observability Format (ATOF)** is the canonical event format - NeMo Flow emits for scope lifecycle events and mark events. Subscribers and + NeMo Relay emits for scope lifecycle events and mark events. Subscribers and exporters consume ATOF events before translating them into downstream observability formats such as ATIF trajectories, OpenTelemetry traces, or OpenInference spans. @@ -66,7 +66,7 @@ Annotated Request And Response Data provider request or response shape. Binding - A **binding** is a language-specific public API surface for the NeMo Flow + A **binding** is a language-specific public API surface for the NeMo Relay runtime, such as Python, Node.js, Go, WebAssembly, Rust, or C FFI. Break Chain @@ -76,18 +76,18 @@ Break Chain Callback A **callback** is the application, framework, tool, or provider function that - does the real work. Managed execution passes this callback through NeMo Flow + does the real work. Managed execution passes this callback through NeMo Relay so middleware and lifecycle events surround the invocation. Category Profile A **category profile** is the event field that stores category-specific - semantic details. NeMo Flow uses it for values such as LLM ``model_name``, + semantic details. NeMo Relay uses it for values such as LLM ``model_name``, tool ``tool_call_id``, and custom ``subtype``. Codec - A **codec** is a deterministic translator at a NeMo Flow boundary. Codecs let + A **codec** is a deterministic translator at a NeMo Relay boundary. Codecs let framework or provider-native values remain convenient for application code - while NeMo Flow observes JSON-compatible or normalized data. + while NeMo Relay observes JSON-compatible or normalized data. Collection Window A **collection window** is the period during which an in-process exporter, @@ -103,7 +103,7 @@ Conditional Execution run at all. Event - An **event** is the runtime record of something that happened. NeMo Flow emits + An **event** is the runtime record of something that happened. NeMo Relay emits events for scope start and end, tool start and end, LLM start and end, and named mark points. @@ -131,12 +131,12 @@ Explicit Lifecycle API but does not let execution intercepts wrap the real callback automatically. Exporter - An **exporter** is a subscriber-oriented component that translates NeMo Flow + An **exporter** is a subscriber-oriented component that translates NeMo Relay events into an external artifact or backend format, such as an ATIF trajectory or OTLP trace spans. FFI - **FFI** means foreign function interface. NeMo Flow's C FFI layer exposes core + **FFI** means foreign function interface. NeMo Relay's C FFI layer exposes core runtime behavior to non-Rust languages and is used by the Go binding. Finalizer @@ -145,7 +145,7 @@ Finalizer sanitize-response guardrails, subscribers, and exporters can observe. Global And Scope-Local Registration - NeMo Flow supports two main ownership levels for middleware and subscribers. + NeMo Relay supports two main ownership levels for middleware and subscribers. - **Global registrations** stay active for the whole process until removed. - **Scope-local registrations** are owned by one active scope and are cleaned @@ -163,7 +163,7 @@ Guardrail Integration Boundary An **integration boundary** is the stable point in an application, framework, - or provider adapter where NeMo Flow can wrap, observe, or transform a tool or + or provider adapter where NeMo Relay can wrap, observe, or transform a tool or LLM invocation. Intercept @@ -171,7 +171,7 @@ Intercept real callback. JSON-Compatible Payload - A **JSON-compatible payload** is data that can be represented in NeMo Flow's + A **JSON-compatible payload** is data that can be represented in NeMo Relay's JSON model. Event data, middleware payloads, and codec output should be JSON-compatible. @@ -192,27 +192,27 @@ LLM Call LLM Stream An **LLM stream** is a streaming model response managed across multiple chunks - rather than a single response object. NeMo Flow captures the originating scope + rather than a single response object. NeMo Relay captures the originating scope stack, runs stream execution intercepts, collects chunks, and finalizes the stream into a response-side event payload. Managed Execution And Manual Lifecycle - NeMo Flow supports two main ways to model tool and LLM work. + NeMo Relay supports two main ways to model tool and LLM work. - - **Managed execution** means NeMo Flow owns the middleware pipeline and + - **Managed execution** means NeMo Relay owns the middleware pipeline and emitted lifecycle around the invocation. - **Manual lifecycle** means some other framework or runtime owns the real - call boundary, and NeMo Flow only records the start and end points + call boundary, and NeMo Relay only records the start and end points explicitly. Managed execution is the default choice for application code. Manual lifecycle exists mainly for framework integrations that cannot delegate the - real invocation to NeMo Flow. + real invocation to NeMo Relay. Managed Execution Wrapper A **managed execution wrapper** is the integration pattern where a tool or LLM - provider callback is routed through NeMo Flow's managed execute helper. This - is the preferred pattern when NeMo Flow can own middleware ordering, lifecycle + provider callback is routed through NeMo Relay's managed execute helper. This + is the preferred pattern when NeMo Relay can own middleware ordering, lifecycle pairing, and event emission around the real callback. Mark Event @@ -226,7 +226,7 @@ Middleware Middleware can inspect, reject, transform, wrap, or sanitize execution at well-defined lifecycle points. - NeMo Flow has two major middleware families: + NeMo Relay has two major middleware families: - **Intercepts** affect the real execution path. - **Guardrails** block work or rewrite the observability payload. @@ -246,17 +246,17 @@ Next Function Non-Serializable Data **Non-serializable data** is framework or SDK state that cannot be represented as JSON, such as clients, streams, callbacks, file handles, or class - instances. Keep those objects outside NeMo Flow payloads and pass only stable + instances. Keep those objects outside NeMo Relay payloads and pass only stable identifiers or projections through events and middleware. OpenInference **OpenInference** is an AI-observability semantic convention layered on trace - spans. NeMo Flow's OpenInference subscriber maps lifecycle payloads to + spans. NeMo Relay's OpenInference subscriber maps lifecycle payloads to OpenInference-oriented attributes such as model inputs, outputs, and token usage. OpenTelemetry - **OpenTelemetry** is a vendor-neutral observability ecosystem. NeMo Flow can + **OpenTelemetry** is a vendor-neutral observability ecosystem. NeMo Relay can export lifecycle events as OpenTelemetry-compatible trace spans. OpenTelemetry Protocol (OTLP) @@ -411,7 +411,7 @@ Tool Parallelism Trace Span A **trace span** is a timed observability record in a tracing backend. - Exported NeMo Flow scopes, tool calls, LLM calls, and marks appear as spans + Exported NeMo Relay scopes, tool calls, LLM calls, and marks appear as spans when using OpenTelemetry or OpenInference export. Trajectory @@ -421,6 +421,6 @@ Trajectory Typed Value Codec A **typed value codec** converts application-facing values to JSON before - NeMo Flow runs middleware or emits events, then converts JSON back into the + NeMo Relay runs middleware or emits events, then converts JSON back into the type expected by the framework callback or caller. ``` diff --git a/docs/resources/legal/license-agreement.md b/docs/resources/legal/license-agreement.md index 2eb3a5f2b..a2b277948 100644 --- a/docs/resources/legal/license-agreement.md +++ b/docs/resources/legal/license-agreement.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # License Agreement -NeMo Flow is licensed under the Apache License 2.0. +NeMo Relay is licensed under the Apache License 2.0. The full license text is available in the repository root `LICENSE` file. diff --git a/docs/resources/legal/oss.md b/docs/resources/legal/oss.md index 775870913..074a38eda 100644 --- a/docs/resources/legal/oss.md +++ b/docs/resources/legal/oss.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Open Source Software -NeMo Flow includes open source dependencies across Rust, Python, and Node.js package surfaces. +NeMo Relay includes open source dependencies across Rust, Python, and Node.js package surfaces. Dependency attribution files live at the repository root: @@ -13,4 +13,4 @@ Dependency attribution files live at the repository root: - [`ATTRIBUTIONS-Python.md`](../../../ATTRIBUTIONS-Python.md) - [`ATTRIBUTIONS-Node.md`](../../../ATTRIBUTIONS-Node.md) -Use the repository root `LICENSE` file for the NeMo Flow project license. +Use the repository root `LICENSE` file for the NeMo Relay project license. diff --git a/docs/resources/support-and-faqs.md b/docs/resources/support-and-faqs.md index 51831b470..1ba69217f 100644 --- a/docs/resources/support-and-faqs.md +++ b/docs/resources/support-and-faqs.md @@ -6,35 +6,35 @@ SPDX-License-Identifier: Apache-2.0 # Support and FAQs Use this page to decide where to start, which runtime surface to use, and where -to look when a NeMo Flow workflow does not behave as expected. +to look when a NeMo Relay workflow does not behave as expected. ## Library Positioning -Use these questions to understand what NeMo Flow is, what it is not, and how it +Use these questions to understand what NeMo Relay is, what it is not, and how it fits into the agent and NVIDIA NeMo ecosystem. -### What Is NeMo Flow Responsible For? +### What Is NeMo Relay Responsible For? -NeMo Flow provides shared runtime instrumentation for scopes, tool calls, LLM +NeMo Relay provides shared runtime instrumentation for scopes, tool calls, LLM calls, middleware, lifecycle events, subscribers, plugins, and adaptive tuning. It gives applications and framework integrations a consistent execution model across supported bindings. -NeMo Flow sits inside an application, framework, or integration and makes +NeMo Relay sits inside an application, framework, or integration and makes runtime behavior observable, policy-aware, and reusable. ### Is This An Agent Framework? -NeMo Flow is an agent runtime framework, not a full agent application +NeMo Relay is an agent runtime framework, not a full agent application framework. It does not decide which agent pattern to use, choose a planner, own memory, provide a hosted workbench, or replace an existing harness. -Use NeMo Flow when you want the tool calls, LLM calls, scopes, middleware, +Use NeMo Relay when you want the tool calls, LLM calls, scopes, middleware, plugins, and observability inside an agent system to follow one runtime model. -### What Is NeMo Flow Not? +### What Is NeMo Relay Not? -NeMo Flow is not: +NeMo Relay is not: - A model provider - A vector database @@ -48,44 +48,44 @@ middleware, lifecycle events, subscribers, plugins, and adaptive behavior. ### How Does This Differ From NeMo Agent Toolkit? -NeMo Flow is the lower-level runtime layer for scopes, middleware, events, +NeMo Relay is the lower-level runtime layer for scopes, middleware, events, plugins, and observability around tool and LLM execution. NeMo Agent Toolkit is a higher-level agent toolkit in the NVIDIA NeMo ecosystem. -Use NeMo Agent Toolkit to build, optimize, and run agent workflows. Use NeMo Flow +Use NeMo Agent Toolkit to build, optimize, and run agent workflows. Use NeMo Relay inside an application, harness, framework integration, or plugin when you need consistent runtime instrumentation and policy behavior around the actual tool and model calls. -### How Does NeMo Flow Relate To Other NVIDIA NeMo Products? +### How Does NeMo Relay Relate To Other NVIDIA NeMo Products? -NeMo Flow belongs in the NVIDIA NeMo ecosystem, but it has a specific role: it +NeMo Relay belongs in the NVIDIA NeMo ecosystem, but it has a specific role: it is a runtime instrumentation and policy layer for agent execution. It does not replace model training, model serving, guardrail authoring, data pipelines, or agent application frameworks provided by other NeMo projects. -When another NeMo product or framework owns the high-level workflow, NeMo Flow +When another NeMo product or framework owns the high-level workflow, NeMo Relay can be used at the execution boundaries where scopes, lifecycle events, middleware, subscribers, exporters, or adaptive plugins are needed. -### Does NeMo Flow Orchestrate Agents? +### Does NeMo Relay Orchestrate Agents? -No. NeMo Flow does not choose the next step, schedule a multi-agent workflow, +No. NeMo Relay does not choose the next step, schedule a multi-agent workflow, own a planner, or decide which tool an agent should call. That remains the responsibility of the application, framework, or agent harness. -NeMo Flow observes and controls the execution boundaries that the orchestrator +NeMo Relay observes and controls the execution boundaries that the orchestrator uses: scopes, tool calls, LLM calls, middleware, events, subscribers, and plugins. -### Why The Name "NeMo Flow"? +### Why The Name "NeMo Relay"? "NeMo" places the project in the NVIDIA NeMo ecosystem. "Flow" refers to the runtime flow of agent work through scopes, middleware, events, subscribers, plugins, and exporters. -The name is about the execution path NeMo Flow makes visible and controllable; -it is not a claim that NeMo Flow owns the full agent workflow or orchestration +The name is about the execution path NeMo Relay makes visible and controllable; +it is not a claim that NeMo Relay owns the full agent workflow or orchestration layer. ## Technology And Bindings @@ -104,9 +104,9 @@ The documentation and examples also cover integration with Agent Trajectory Interchange Format (ATIF) trajectory export, OpenTelemetry traces, OpenInference-compatible data, and third-party agent framework patch sets. -### Why Is NeMo Flow's Core Written In Rust? +### Why Is NeMo Relay's Core Written In Rust? -Rust gives NeMo Flow one native source of truth for runtime behavior while +Rust gives NeMo Relay one native source of truth for runtime behavior while keeping overhead low at hot tool and LLM boundaries. It also gives the project strong ownership, error, and async primitives for scope stacks, middleware registries, callbacks, subscribers, and binding-facing FFI layers. @@ -121,7 +121,7 @@ and have the broadest getting-started, concept, guide, and generated API coverage. - Use [Python Quick Start](../getting-started/python/index.md) when you are adding - NeMo Flow to Python application code or agent harnesses. + NeMo Relay to Python application code or agent harnesses. - Use [Node.js Quick Start](../getting-started/nodejs.md) when your application, framework integration, or plugin-facing code runs in Node.js. - Use [Rust Quick Start](../getting-started/rust.md) when you want the native @@ -170,7 +170,7 @@ Scopes establish parent-child relationships for events and define the lifetime for scope-local middleware and subscribers. Refer to [Scopes](../about/concepts/scopes.md) and [Adding Scopes and Marks](../instrument-applications/adding-scopes-and-marks.md). -### How Does NeMo Flow Handle Multiple Concurrent Agents Or Requests? +### How Does NeMo Relay Handle Multiple Concurrent Agents Or Requests? Use an isolated scope stack for each concurrent request, tenant, worker, or agent run. The root scope identifies the run, and emitted events include root @@ -212,7 +212,7 @@ streaming LLM flows can use stream-specific execution behavior. Start with [Instrument a Tool Call](../instrument-applications/instrument-tool-call.md) or [Instrument an LLM Call](../instrument-applications/instrument-llm-call.md). -### Does NeMo Flow Support Streaming LLM Responses? +### Does NeMo Relay Support Streaming LLM Responses? Yes. Streaming LLM workflows have a stream execution path so middleware can run around chunk delivery and finalization, not only around a single response @@ -245,7 +245,7 @@ Refer to [Middleware](../about/concepts/middleware.md) and ### What Is The Middleware Pipeline? The middleware pipeline is the ordered runtime path that a managed tool or LLM -call follows before, during, and after the real callback. It is how NeMo Flow +call follows before, during, and after the real callback. It is how NeMo Relay applies policy, request transformation, execution wrapping, and observability sanitization without moving that logic into every call site. @@ -287,7 +287,7 @@ and the real callback, then response sanitization and end-event emission. The start event is emitted before execution intercepts run, so subscribers see a lifecycle start even when an execution intercept replaces the callback. -Registries are priority ordered. When scope-local behavior is present, NeMo Flow +Registries are priority ordered. When scope-local behavior is present, NeMo Relay combines applicable global and ancestor scope-local entries into the execution chain. Refer to [Managed Execution Order](../about/concepts/middleware.md#managed-execution-order). @@ -295,10 +295,10 @@ chain. Refer to [Managed Execution Order](../about/concepts/middleware.md#manage Middleware and event payloads should be JSON-compatible. Keep SDK clients, streams, sockets, callbacks, file handles, and framework-specific object -instances outside NeMo Flow payloads. +instances outside NeMo Relay payloads. When a framework exposes non-serializable objects, pass stable IDs or summarized -metadata through NeMo Flow and keep the original objects in framework-owned +metadata through NeMo Relay and keep the original objects in framework-owned storage. Refer to [Handle Non-Serializable Data](../integrate-frameworks/non-serializable-data.md). ### How Do I Keep Sensitive Data Out Of Observability? @@ -338,7 +338,7 @@ Refer to [Exporter Selection](../plugins/observability/about.md#exporter-selecti [OpenInference](../plugins/observability/openinference.md), and [Agent Trajectory Interchange Format (ATIF)](../plugins/observability/atif.md). -### Can I Use NeMo Flow Just For Observability Without Adaptive Tuning Or Middleware? +### Can I Use NeMo Relay Just For Observability Without Adaptive Tuning Or Middleware? Yes. Adaptive tuning and custom middleware are optional. You can start by adding scopes, routing tool or LLM calls through managed execution helpers or @@ -403,14 +403,14 @@ downstream code. Refer to [Framework Integrations](../about/concepts/framework-integrations.md) and [Integrate into Frameworks](../integrate-frameworks/about.md). -### How Does NeMo Flow Connect To My Favorite Agent Harness Or Framework? +### How Does NeMo Relay Connect To My Favorite Agent Harness Or Framework? -Connect NeMo Flow at the stable boundaries where the harness or framework +Connect NeMo Relay at the stable boundaries where the harness or framework starts a run, invokes a tool, calls an LLM provider, streams model output, or emits lifecycle milestones. Use managed execution wrappers when the framework can expose the real callback -to NeMo Flow. Use explicit start and end lifecycle APIs when the framework owns +to NeMo Relay. Use explicit start and end lifecycle APIs when the framework owns the invocation internally. Use codecs when the framework uses typed or provider-specific payloads but middleware and events need JSON-compatible data. @@ -493,7 +493,7 @@ Start with [Contribute](../contribute/about.md) and the repository root [Workflow And Reviews](../contribute/workflow-and-reviews.md), and [Testing And Documentation](../contribute/testing-and-docs.md). -### How Will AI Coding Assistants Find NeMo Flow? +### How Will AI Coding Assistants Find NeMo Relay? AI coding assistants should start from the repository root `AGENTS.md`, `README.md`, and the documentation index. Those entry points describe the @@ -501,7 +501,7 @@ runtime model, repository layout, supported bindings, validation commands, and contribution workflow. For symbol-level work, assistants should use the generated Rust, Python, and -Node.js API references. For repository-specific automation, use the NeMo Flow +Node.js API references. For repository-specific automation, use the NeMo Relay agent skills under `skills/` and keep examples aligned with the public docs. ### Which Tests Should I Run For A Change? @@ -510,10 +510,10 @@ Choose the smallest validation set that covers the touched surface: - Rust core or adaptive changes: `cargo test --workspace` or focused crate tests. - Python binding changes: `uv run pytest`. -- Node.js binding changes: `npm test --workspace=nemo-flow-node`. -- Go binding changes: build the release FFI library first, then run Go tests under `go/nemo_flow`. +- Node.js binding changes: `npm test --workspace=nemo-relay-node`. +- Go binding changes: build the release FFI library first, then run Go tests under `go/nemo_relay`. - WebAssembly changes: run `just test-wasm` and the WebAssembly crate tests - (`cargo test -p nemo-flow-wasm`) when integration behavior changed. For + (`cargo test -p nemo-relay-wasm`) when integration behavior changed. For focused debugging, you can run `wasm-pack test --node crates/wasm` directly. - Documentation changes: run `./scripts/build-docs.sh html`. @@ -522,5 +522,5 @@ current contribution workflow. ### What License Applies? -NeMo Flow is licensed under Apache-2.0. Source and documentation files use SPDX +NeMo Relay is licensed under Apache-2.0. Source and documentation files use SPDX headers. Refer to [Legal](legal/index.md) and the repository root `LICENSE`. diff --git a/docs/troubleshooting/troubleshooting-guide.md b/docs/troubleshooting/troubleshooting-guide.md index 3fe0e7918..c54b21bcd 100644 --- a/docs/troubleshooting/troubleshooting-guide.md +++ b/docs/troubleshooting/troubleshooting-guide.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 # Troubleshooting Guide -Use this page when a NeMo Flow setup, build, or runtime workflow does not behave as expected. +Use this page when a NeMo Relay setup, build, or runtime workflow does not behave as expected. ## Package Or Build Setup Fails @@ -18,14 +18,14 @@ If a command worked previously and now fails, check whether a toolchain update c Run the narrowest failing build first: ```bash -cargo build -p nemo-flow +cargo build -p nemo-relay ``` If the core crate builds but another crate fails, rerun the binding-specific build or test command from [Testing and Documentation](../contribute/testing-and-docs.md). Binding crates often depend on generated native artifacts, host toolchain headers, or runtime-specific test setup. ## Python Native Module Does Not Import -If `import nemo_flow` fails, rebuild the Python environment and native extension: +If `import nemo_relay` fails, rebuild the Python environment and native extension: ```bash uv sync @@ -40,7 +40,7 @@ If Node.js reports a missing or incompatible native addon, reinstall dependencie ```bash npm install -npm test --workspace=nemo-flow-node +npm test --workspace=nemo-relay-node ``` Use [Node.js Getting Started](../getting-started/nodejs.md) to confirm that the example runs against the generated local build, not a stale package or a globally installed copy. @@ -50,8 +50,8 @@ Use [Node.js Getting Started](../getting-started/nodejs.md) to confirm that the The Go binding loads the shared FFI library through CGo. Build the release FFI library before running Go tests, and point the linker and runtime loader at the release target directory: ```bash -cargo build --release -p nemo-flow-ffi -cd go/nemo_flow +cargo build --release -p nemo-relay-ffi +cd go/nemo_relay CGO_LDFLAGS="-L../../target/release" LD_LIBRARY_PATH="../../target/release" go test -race -v ./... ``` @@ -141,7 +141,7 @@ Use [Wrap LLM Calls](../integrate-frameworks/wrap-llm-calls.md) and [Provider Re ## Provider Payloads Fail To Convert -JSON conversion errors usually mean the integration passed a value that cannot be represented in NeMo Flow's JSON model, such as functions, class instances, handles, or provider-specific streaming objects. +JSON conversion errors usually mean the integration passed a value that cannot be represented in NeMo Relay's JSON model, such as functions, class instances, handles, or provider-specific streaming objects. Use [Non-Serializable Data](../integrate-frameworks/non-serializable-data.md), [Provider Codecs](../integrate-frameworks/provider-codecs.md), and [Using Codecs](../integrate-frameworks/using-codecs.md) to define explicit conversions for provider-specific payloads. @@ -175,6 +175,6 @@ If the patch still does not apply, confirm that the local checkout is clean and ## Third-Party Integration Behaves Differently From Core APIs -First reproduce the behavior through the closest core or binding-level API. If the core API behaves correctly, inspect the integration wrapper, codec, or provider adapter that translates provider calls into NeMo Flow calls. +First reproduce the behavior through the closest core or binding-level API. If the core API behaves correctly, inspect the integration wrapper, codec, or provider adapter that translates provider calls into NeMo Relay calls. Use [Integrate Frameworks](../integrate-frameworks/about.md), [Wrap Tool Calls](../integrate-frameworks/wrap-tool-calls.md), and [Wrap LLM Calls](../integrate-frameworks/wrap-llm-calls.md) to compare the integration path with the core runtime path. diff --git a/docs/typedoc.node.json b/docs/typedoc.node.json index 65c627f6a..2f9aa3f28 100644 --- a/docs/typedoc.node.json +++ b/docs/typedoc.node.json @@ -1,6 +1,6 @@ { "$schema": "https://typedoc.org/schema.json", - "name": "NeMo Flow Node.js API", + "name": "NeMo Relay Node.js API", "excludeInternal": true, "excludePrivate": true, "excludeProtected": true, diff --git a/examples/nemoguardrails/README.md b/examples/nemoguardrails/README.md index 5242ef515..a1e91f299 100644 --- a/examples/nemoguardrails/README.md +++ b/examples/nemoguardrails/README.md @@ -6,9 +6,9 @@ SPDX-License-Identifier: Apache-2.0 # NeMo Guardrails Plugin Example This directory contains an example Python plugin that uses the NeMo Guardrails -Python API from NeMo Flow. +Python API from NeMo Relay. -It is intentionally outside the `nemo_flow` package. Applications can copy, +It is intentionally outside the `nemo_relay` package. Applications can copy, vendor, or package this plugin if they want to use it. The single-file plugin implementation, runnable agent, and Guardrails config @@ -22,7 +22,7 @@ artifacts live under `example`. output rails. - Input and output checks around non-streaming `llm.execute(...)` calls. - Optional checks around managed `tools.execute(...)` arguments and results. -- Request and response decoding with NeMo Flow's built-in OpenAI Chat, OpenAI +- Request and response decoding with NeMo Relay's built-in OpenAI Chat, OpenAI Responses, and Anthropic Messages codecs. - A concrete example agent that exercises the plugin with a live NVIDIA OpenAI-compatible chat request. @@ -32,12 +32,12 @@ artifacts live under `example`. ## Boundaries This example keeps provider response rewriting out of the plugin. Guardrails can -rewrite LLM input because NeMo Flow request codecs support decode and encode. +rewrite LLM input because NeMo Relay request codecs support decode and encode. If Guardrails returns modified LLM output, the example raises instead of mutating provider-shaped responses. The example also does not cover streaming calls or a full `generate_async` -agent-runtime integration. Tool checks use NeMo Flow tool middleware and +agent-runtime integration. Tool checks use NeMo Relay tool middleware and serialized JSON payloads. ## Use It @@ -64,16 +64,16 @@ Register and initialize the plugin: ```python import asyncio -import nemo_flow +import nemo_relay import plugin as nemoguardrails_plugin async def main() -> None: nemoguardrails_plugin.register() try: - config = nemo_flow.plugin.PluginConfig( + config = nemo_relay.plugin.PluginConfig( components=[ - nemo_flow.plugin.ComponentSpec( + nemo_relay.plugin.ComponentSpec( kind=nemoguardrails_plugin.DEFAULT_KIND, config={ "config_path": "./rails", @@ -82,9 +82,9 @@ async def main() -> None: ) ] ) - await nemo_flow.plugin.initialize(config) + await nemo_relay.plugin.initialize(config) finally: - nemo_flow.plugin.clear() + nemo_relay.plugin.clear() nemoguardrails_plugin.deregister() @@ -98,7 +98,7 @@ initializes this plugin, runs a managed `tools.execute(...)` call, and sends the tool result through a managed `llm.execute(...)` call to NVIDIA-hosted inference. -Run it from a checkout where NeMo Flow and NeMo Guardrails are installed. The +Run it from a checkout where NeMo Relay and NeMo Guardrails are installed. The default lane uses a passthrough Guardrails config and the `current_time` tool. This is the fastest live validation path because it exercises the real plugin, real `nemoguardrails` initialization, tool execution, and LLM execution without diff --git a/examples/nemoguardrails/example/agent_example.py b/examples/nemoguardrails/example/agent_example.py index 0e3a9f6b3..3ba516901 100644 --- a/examples/nemoguardrails/example/agent_example.py +++ b/examples/nemoguardrails/example/agent_example.py @@ -18,9 +18,9 @@ import plugin as nemoguardrails_plugin -from nemo_flow import Json, JsonObject, LLMRequest, ScopeType, llm, scope, tools -from nemo_flow import plugin as flow_plugin -from nemo_flow.codecs import OpenAIChatCodec +from nemo_relay import Json, JsonObject, LLMRequest, ScopeType, llm, scope, tools +from nemo_relay import plugin as relay_plugin +from nemo_relay.codecs import OpenAIChatCodec EXAMPLE_ROOT = Path(__file__).resolve().parent @@ -106,10 +106,10 @@ def _guardrails_component_config(args: argparse.Namespace) -> JsonObject: return cast(JsonObject, config) -def _plugin_config(args: argparse.Namespace) -> flow_plugin.PluginConfig: - return flow_plugin.PluginConfig( +def _plugin_config(args: argparse.Namespace) -> relay_plugin.PluginConfig: + return relay_plugin.PluginConfig( components=[ - flow_plugin.ComponentSpec( + relay_plugin.ComponentSpec( kind=nemoguardrails_plugin.DEFAULT_KIND, config=_guardrails_component_config(args), ) @@ -203,7 +203,7 @@ async def run_agent() -> None: try: nemoguardrails_plugin.register() registered = True - await flow_plugin.initialize(_plugin_config(args)) + await relay_plugin.initialize(_plugin_config(args)) with scope.scope("nemoguardrails-example-agent", ScopeType.Agent): tool_result = await _execute_example_tool(args.tool) @@ -239,7 +239,7 @@ async def run_agent() -> None: print("\nAssistant:") print(_assistant_text(response)) finally: - flow_plugin.clear() + relay_plugin.clear() if registered: nemoguardrails_plugin.deregister() diff --git a/examples/nemoguardrails/example/example_config.yml b/examples/nemoguardrails/example/example_config.yml index 845287442..8b56f36ae 100644 --- a/examples/nemoguardrails/example/example_config.yml +++ b/examples/nemoguardrails/example/example_config.yml @@ -17,7 +17,7 @@ rails: prompts: - task: self_check_input content: |- - You are checking whether a NeMo Flow request should be allowed. + You are checking whether a NeMo Relay request should be allowed. The input may be plain user text or a JSON object with tool_name and arguments fields. @@ -31,7 +31,7 @@ prompts: - task: self_check_output content: |- - You are checking whether a NeMo Flow response should be returned. + You are checking whether a NeMo Relay response should be returned. The output may be assistant text or a JSON object with tool_name, arguments, and result fields. diff --git a/examples/nemoguardrails/example/plugin.py b/examples/nemoguardrails/example/plugin.py index 571f296b5..897ab95b3 100644 --- a/examples/nemoguardrails/example/plugin.py +++ b/examples/nemoguardrails/example/plugin.py @@ -10,9 +10,9 @@ from collections.abc import Callable from typing import Any, Protocol, cast -from nemo_flow import Json, LLMRequest -from nemo_flow import plugin as flow_plugin -from nemo_flow.codecs import ( +from nemo_relay import Json, LLMRequest +from nemo_relay import plugin as relay_plugin +from nemo_relay.codecs import ( AnthropicMessagesCodec, LlmCodec, LlmResponseCodec, @@ -412,15 +412,15 @@ async def tool_intercept(tool_name: str, args: Json, next_call): def register(kind: str = DEFAULT_KIND) -> None: - """Register the NeMo Guardrails plugin kind with NeMo Flow.""" + """Register the NeMo Guardrails plugin kind with NeMo Relay.""" - flow_plugin.register(kind, cast(flow_plugin.Plugin, NeMoGuardrailsPlugin())) + relay_plugin.register(kind, cast(relay_plugin.Plugin, NeMoGuardrailsPlugin())) def deregister(kind: str = DEFAULT_KIND) -> bool: - """Deregister the NeMo Guardrails plugin kind from NeMo Flow.""" + """Deregister the NeMo Guardrails plugin kind from NeMo Relay.""" - return flow_plugin.deregister(kind) + return relay_plugin.deregister(kind) __all__ = [ diff --git a/examples/nemoguardrails/example/rails/config.yml b/examples/nemoguardrails/example/rails/config.yml index 845287442..8b56f36ae 100644 --- a/examples/nemoguardrails/example/rails/config.yml +++ b/examples/nemoguardrails/example/rails/config.yml @@ -17,7 +17,7 @@ rails: prompts: - task: self_check_input content: |- - You are checking whether a NeMo Flow request should be allowed. + You are checking whether a NeMo Relay request should be allowed. The input may be plain user text or a JSON object with tool_name and arguments fields. @@ -31,7 +31,7 @@ prompts: - task: self_check_output content: |- - You are checking whether a NeMo Flow response should be returned. + You are checking whether a NeMo Relay response should be returned. The output may be assistant text or a JSON object with tool_name, arguments, and result fields. diff --git a/go/nemo_flow/go.mod b/go/nemo_flow/go.mod deleted file mode 100644 index 09fe6a8b7..000000000 --- a/go/nemo_flow/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/NVIDIA/NeMo-Flow/go/nemo_flow - -go 1.21 diff --git a/go/nemo_flow/README.md b/go/nemo_relay/README.md similarity index 56% rename from go/nemo_flow/README.md rename to go/nemo_relay/README.md index 7bce110bf..0d6b533d8 100644 --- a/go/nemo_flow/README.md +++ b/go/nemo_relay/README.md @@ -3,22 +3,22 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow Go Binding - -The Go binding exposes NeMo Flow runtime APIs through CGo and the raw -`nemo-flow-ffi` library. Use it when a Go application or integration needs the +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay Go Binding + +The Go binding exposes NeMo Relay runtime APIs through CGo and the raw +`nemo-relay-ffi` library. Use it when a Go application or integration needs the same scope, middleware, lifecycle event, and observability model used by the Rust runtime. @@ -27,14 +27,14 @@ primary supported surfaces. ## Why Use It? -- 🧭 **Use NeMo Flow from Go**: Group agent, tool, and LLM work into the same +- 🧭 **Use NeMo Relay from Go**: Group agent, tool, and LLM work into the same scope and lifecycle model as the Rust runtime. - 🔌 **Bridge through CGo and FFI**: Consume the shared runtime through the - repository-maintained `nemo-flow-ffi` layer. + repository-maintained `nemo-relay-ffi` layer. - 📡 **Observe runtime behavior**: Register subscribers for scope, tool, LLM, and mark events emitted by the runtime. - 🚧 **Evaluate an experimental binding**: Use the source-first Go surface when - a Go integration needs NeMo Flow semantics. + a Go integration needs NeMo Relay semantics. ## What You Get @@ -54,17 +54,17 @@ primary supported surfaces. Build the FFI library from a repository checkout before using the Go binding: ```bash -git clone https://github.com/NVIDIA/NeMo-Flow.git -cd NeMo-Flow -cargo build --release -p nemo-flow-ffi +git clone https://github.com/NVIDIA/NeMo-Relay.git +cd NeMo-Relay +cargo build --release -p nemo-relay-ffi ``` For a Go application that consumes a local checkout, point the module at the checked-out binding: ```bash -go mod edit -replace github.com/NVIDIA/NeMo-Flow/go/nemo_flow=../NeMo-Flow/go/nemo_flow -go get github.com/NVIDIA/NeMo-Flow/go/nemo_flow +go mod edit -replace github.com/NVIDIA/NeMo-Relay/go/nemo_relay=../NeMo-Relay/go/nemo_relay +go get github.com/NVIDIA/NeMo-Relay/go/nemo_relay ``` ## Getting Started @@ -73,7 +73,7 @@ Run the binding tests from the repository checkout to verify the CGo link path and the FFI library: ```bash -cd go/nemo_flow +cd go/nemo_relay go test ./... ``` @@ -87,9 +87,9 @@ import ( "fmt" "log" - nemo "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/scope" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/tools" + nemo "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/scope" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/tools" ) func main() { diff --git a/go/nemo_flow/adaptive.go b/go/nemo_relay/adaptive.go similarity index 99% rename from go/nemo_flow/adaptive.go rename to go/nemo_relay/adaptive.go index cae2afc9c..eb7ce81f5 100644 --- a/go/nemo_flow/adaptive.go +++ b/go/nemo_relay/adaptive.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import "encoding/json" diff --git a/go/nemo_flow/adaptive/adaptive.go b/go/nemo_relay/adaptive/adaptive.go similarity index 58% rename from go/nemo_flow/adaptive/adaptive.go rename to go/nemo_relay/adaptive/adaptive.go index 7ea632bb0..43f87fc92 100644 --- a/go/nemo_flow/adaptive/adaptive.go +++ b/go/nemo_relay/adaptive/adaptive.go @@ -3,101 +3,101 @@ package adaptive -import nemo_flow "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" +import nemo_relay "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" // UnsupportedBehavior controls how adaptive config validation handles unsupported input. -type UnsupportedBehavior = nemo_flow.UnsupportedBehavior +type UnsupportedBehavior = nemo_relay.UnsupportedBehavior const ( - UnsupportedBehaviorIgnore = nemo_flow.UnsupportedBehaviorIgnore - UnsupportedBehaviorWarn = nemo_flow.UnsupportedBehaviorWarn - UnsupportedBehaviorError = nemo_flow.UnsupportedBehaviorError + UnsupportedBehaviorIgnore = nemo_relay.UnsupportedBehaviorIgnore + UnsupportedBehaviorWarn = nemo_relay.UnsupportedBehaviorWarn + UnsupportedBehaviorError = nemo_relay.UnsupportedBehaviorError ) // DiagnosticLevel is the severity of one adaptive validation diagnostic. -type DiagnosticLevel = nemo_flow.DiagnosticLevel +type DiagnosticLevel = nemo_relay.DiagnosticLevel const ( - DiagnosticLevelWarning = nemo_flow.DiagnosticLevelWarning - DiagnosticLevelError = nemo_flow.DiagnosticLevelError + DiagnosticLevelWarning = nemo_relay.DiagnosticLevelWarning + DiagnosticLevelError = nemo_relay.DiagnosticLevelError ) // Config is the canonical adaptive config document. -type Config = nemo_flow.AdaptiveConfig +type Config = nemo_relay.AdaptiveConfig // ComponentSpec wraps adaptive config as a top-level adaptive component. -type ComponentSpec = nemo_flow.AdaptiveComponentSpec +type ComponentSpec = nemo_relay.AdaptiveComponentSpec // StateConfig selects the adaptive state backend. -type StateConfig = nemo_flow.AdaptiveStateConfig +type StateConfig = nemo_relay.AdaptiveStateConfig // BackendSpec selects the adaptive state backend kind and backend-specific config. -type BackendSpec = nemo_flow.AdaptiveBackendSpec +type BackendSpec = nemo_relay.AdaptiveBackendSpec // TelemetryConfig configures built-in adaptive telemetry. -type TelemetryConfig = nemo_flow.TelemetryConfig +type TelemetryConfig = nemo_relay.TelemetryConfig // AdaptiveHintsConfig configures built-in adaptive hint injection. -type AdaptiveHintsConfig = nemo_flow.AdaptiveHintsConfig +type AdaptiveHintsConfig = nemo_relay.AdaptiveHintsConfig // ToolParallelismConfig configures built-in adaptive tool scheduling. -type ToolParallelismConfig = nemo_flow.ToolParallelismConfig +type ToolParallelismConfig = nemo_relay.ToolParallelismConfig // AcgStabilityThresholds configures ACG prompt-stability classification. -type AcgStabilityThresholds = nemo_flow.AcgStabilityThresholds +type AcgStabilityThresholds = nemo_relay.AcgStabilityThresholds // AcgConfig configures the adaptive cache governor. -type AcgConfig = nemo_flow.AcgConfig +type AcgConfig = nemo_relay.AcgConfig // PluginKind is the top-level plugin kind used by the adaptive component. -const PluginKind = nemo_flow.AdaptivePluginKind +const PluginKind = nemo_relay.AdaptivePluginKind // NewConfig returns a default adaptive config with version 1. func NewConfig() Config { - return nemo_flow.NewAdaptiveConfig() + return nemo_relay.NewAdaptiveConfig() } // NewInMemoryBackend returns an in-memory adaptive backend spec. func NewInMemoryBackend() BackendSpec { - return nemo_flow.NewInMemoryAdaptiveBackend() + return nemo_relay.NewInMemoryAdaptiveBackend() } // NewRedisBackend returns a Redis adaptive backend spec. func NewRedisBackend(url, keyPrefix string) BackendSpec { - return nemo_flow.NewRedisAdaptiveBackend(url, keyPrefix) + return nemo_relay.NewRedisAdaptiveBackend(url, keyPrefix) } // NewTelemetryConfig returns default adaptive telemetry settings. func NewTelemetryConfig() TelemetryConfig { - return nemo_flow.NewTelemetryConfig() + return nemo_relay.NewTelemetryConfig() } // NewAdaptiveHintsConfig returns default adaptive hints injection settings. func NewAdaptiveHintsConfig() AdaptiveHintsConfig { - return nemo_flow.NewAdaptiveHintsConfig() + return nemo_relay.NewAdaptiveHintsConfig() } // NewToolParallelismConfig returns default adaptive tool scheduling settings. func NewToolParallelismConfig() ToolParallelismConfig { - return nemo_flow.NewToolParallelismConfig() + return nemo_relay.NewToolParallelismConfig() } // NewAcgStabilityThresholds returns default ACG stability thresholds. func NewAcgStabilityThresholds() AcgStabilityThresholds { - return nemo_flow.NewAcgStabilityThresholds() + return nemo_relay.NewAcgStabilityThresholds() } // NewAcgConfig returns default adaptive cache governor settings. func NewAcgConfig() AcgConfig { - return nemo_flow.NewAcgConfig() + return nemo_relay.NewAcgConfig() } // NewComponentSpec wraps adaptive config as an enabled top-level adaptive component. func NewComponentSpec(config Config) ComponentSpec { - return nemo_flow.NewAdaptiveComponentSpec(config) + return nemo_relay.NewAdaptiveComponentSpec(config) } // Component converts adaptive config directly into the shared plugin shape. -func Component(config Config) nemo_flow.PluginComponentSpec { - return nemo_flow.AdaptiveComponent(config) +func Component(config Config) nemo_relay.PluginComponentSpec { + return nemo_relay.AdaptiveComponent(config) } diff --git a/go/nemo_flow/adaptive/optimizer_test.go b/go/nemo_relay/adaptive/optimizer_test.go similarity index 92% rename from go/nemo_flow/adaptive/optimizer_test.go rename to go/nemo_relay/adaptive/optimizer_test.go index bfbbd3cee..7d18e321b 100644 --- a/go/nemo_flow/adaptive/optimizer_test.go +++ b/go/nemo_relay/adaptive/optimizer_test.go @@ -4,7 +4,7 @@ package adaptive import ( - nemo_flow "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + nemo_relay "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" "testing" ) @@ -25,9 +25,9 @@ func TestConfigBuilders(t *testing.T) { acg := NewAcgConfig() config.Acg = &acg - report, err := nemo_flow.ValidatePluginConfig(nemo_flow.PluginConfig{ + report, err := nemo_relay.ValidatePluginConfig(nemo_relay.PluginConfig{ Version: 1, - Components: []nemo_flow.PluginComponentSpec{Component(config)}, + Components: []nemo_relay.PluginComponentSpec{Component(config)}, }) if err != nil { t.Fatalf("ValidatePluginConfig failed: %v", err) diff --git a/go/nemo_flow/adaptive_plugin_test.go b/go/nemo_relay/adaptive_plugin_test.go similarity index 99% rename from go/nemo_flow/adaptive_plugin_test.go rename to go/nemo_relay/adaptive_plugin_test.go index ceef5c64d..44d580b0c 100644 --- a/go/nemo_flow/adaptive_plugin_test.go +++ b/go/nemo_relay/adaptive_plugin_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/adaptive_test.go b/go/nemo_relay/adaptive_test.go similarity index 99% rename from go/nemo_flow/adaptive_test.go rename to go/nemo_relay/adaptive_test.go index df6719339..fba86b6ff 100644 --- a/go/nemo_flow/adaptive_test.go +++ b/go/nemo_relay/adaptive_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/atof_test.go b/go/nemo_relay/atof_test.go similarity index 99% rename from go/nemo_flow/atof_test.go rename to go/nemo_relay/atof_test.go index 1bed1345f..f7ea11af9 100644 --- a/go/nemo_flow/atof_test.go +++ b/go/nemo_relay/atof_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/callbacks.go b/go/nemo_relay/callbacks.go similarity index 85% rename from go/nemo_flow/callbacks.go rename to go/nemo_relay/callbacks.go index b71d44472..68f3d7f71 100644 --- a/go/nemo_flow/callbacks.go +++ b/go/nemo_relay/callbacks.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// callbacks.go defines the Go callback type aliases used by the NeMo Flow +// callbacks.go defines the Go callback type aliases used by the NeMo Relay // middleware and subscriber systems, and the CGo trampoline functions that // bridge Go closures to C function pointers. // @@ -14,7 +14,7 @@ // arguments. The goFreeTrampoline is called by the C side when the callback // is deregistered, removing the closure from the registry. -package nemo_flow +package nemo_relay /* #include @@ -27,45 +27,45 @@ typedef struct FfiLLMHandle FfiLLMHandle; typedef struct FfiLLMRequest FfiLLMRequest; typedef struct FfiEvent FfiEvent; -typedef void (*NemoFlowFreeFn)(void* user_data); -typedef char* (*NemoFlowToolSanitizeFn)(void* user_data, const char* name, const char* args_json); -typedef char* (*NemoFlowToolConditionalFn)(void* user_data, const char* name, const char* args_json); -typedef char* (*NemoFlowToolExecFn)(void* user_data, const char* args_json); -typedef FfiLLMRequest* (*NemoFlowLlmRequestCb)(void* user_data, const FfiLLMRequest* request); -typedef char* (*NemoFlowLlmConditionalCb)(void* user_data, const FfiLLMRequest* request); -typedef char* (*NemoFlowLlmExecFn)(void* user_data, const char* native_json); -typedef char* (*NemoFlowLlmResponseFn)(void* user_data, const char* response_json); -typedef void (*NemoFlowEventSubscriberFn)(void* user_data, const FfiEvent* event); +typedef void (*NemoRelayFreeFn)(void* user_data); +typedef char* (*NemoRelayToolSanitizeFn)(void* user_data, const char* name, const char* args_json); +typedef char* (*NemoRelayToolConditionalFn)(void* user_data, const char* name, const char* args_json); +typedef char* (*NemoRelayToolExecFn)(void* user_data, const char* args_json); +typedef FfiLLMRequest* (*NemoRelayLlmRequestCb)(void* user_data, const FfiLLMRequest* request); +typedef char* (*NemoRelayLlmConditionalCb)(void* user_data, const FfiLLMRequest* request); +typedef char* (*NemoRelayLlmExecFn)(void* user_data, const char* native_json); +typedef char* (*NemoRelayLlmResponseFn)(void* user_data, const char* response_json); +typedef void (*NemoRelayEventSubscriberFn)(void* user_data, const FfiEvent* event); typedef struct FfiPluginContext FfiPluginContext; // Middleware chain next function types -typedef char* (*NemoFlowToolExecNextFn)(const char* args_json, void* next_ctx); -typedef char* (*NemoFlowToolExecInterceptCb)(void* user_data, const char* args_json, NemoFlowToolExecNextFn next_fn, void* next_ctx); -typedef char* (*NemoFlowLlmExecNextFn)(const char* native_json, void* next_ctx); -typedef char* (*NemoFlowLlmExecInterceptCb)(void* user_data, const char* native_json, NemoFlowLlmExecNextFn next_fn, void* next_ctx); +typedef char* (*NemoRelayToolExecNextFn)(const char* args_json, void* next_ctx); +typedef char* (*NemoRelayToolExecInterceptCb)(void* user_data, const char* args_json, NemoRelayToolExecNextFn next_fn, void* next_ctx); +typedef char* (*NemoRelayLlmExecNextFn)(const char* native_json, void* next_ctx); +typedef char* (*NemoRelayLlmExecInterceptCb)(void* user_data, const char* native_json, NemoRelayLlmExecNextFn next_fn, void* next_ctx); // Helper to call the tool exec next function pointer from Go -static inline char* callToolExecNext(NemoFlowToolExecNextFn next_fn, const char* args_json, void* next_ctx) { +static inline char* callToolExecNext(NemoRelayToolExecNextFn next_fn, const char* args_json, void* next_ctx) { return next_fn(args_json, next_ctx); } // Helper to call the LLM exec next function pointer from Go -static inline char* callLlmExecNext(NemoFlowLlmExecNextFn next_fn, const char* native_json, void* next_ctx) { +static inline char* callLlmExecNext(NemoRelayLlmExecNextFn next_fn, const char* native_json, void* next_ctx) { return next_fn(native_json, next_ctx); } // LLMRequest accessors (also declared in types.go, needed here for trampolines) -extern FfiLLMRequest* nemo_flow_llm_request_new(const char* headers_json, const char* content_json); -extern char* nemo_flow_llm_request_headers(const FfiLLMRequest* ptr); -extern char* nemo_flow_llm_request_content(const FfiLLMRequest* ptr); -extern void nemo_flow_string_free(char* ptr); -extern void nemo_flow_set_last_error_message(const char* msg); +extern FfiLLMRequest* nemo_relay_llm_request_new(const char* headers_json, const char* content_json); +extern char* nemo_relay_llm_request_headers(const FfiLLMRequest* ptr); +extern char* nemo_relay_llm_request_content(const FfiLLMRequest* ptr); +extern void nemo_relay_string_free(char* ptr); +extern void nemo_relay_set_last_error_message(const char* msg); // Codec callback typedefs (kept for trampoline use at execute time) -typedef char* (*NemoFlowCodecDecodeCb)(void* user_data, const FfiLLMRequest* request); -typedef char* (*NemoFlowCodecEncodeCb)(void* user_data, const char* annotated_json, const FfiLLMRequest* original_request); -typedef NemoFlowCodecDecodeCb NemoFlowCodecDecodeFn; -typedef NemoFlowCodecEncodeCb NemoFlowCodecEncodeFn; +typedef char* (*NemoRelayCodecDecodeCb)(void* user_data, const FfiLLMRequest* request); +typedef char* (*NemoRelayCodecEncodeCb)(void* user_data, const char* annotated_json, const FfiLLMRequest* original_request); +typedef NemoRelayCodecDecodeCb NemoRelayCodecDecodeFn; +typedef NemoRelayCodecEncodeCb NemoRelayCodecEncodeFn; */ import "C" @@ -93,7 +93,7 @@ var ( func setLastErrorMessage(msg string) { cMsg := C.CString(msg) defer C.free(unsafe.Pointer(cMsg)) - C.nemo_flow_set_last_error_message(cMsg) + C.nemo_relay_set_last_error_message(cMsg) } // registerClosure stores fn in the global registry and returns an @@ -109,7 +109,7 @@ func registerClosure(fn interface{}) unsafe.Pointer { // pointer through C and can release it explicitly on deregistration. p := (*uintptr)(closureTokenAlloc()) if p == nil { - panic("nemo_flow: failed to allocate callback token") + panic("nemo_relay: failed to allocate callback token") } *p = id return unsafe.Pointer(p) @@ -391,12 +391,12 @@ func goLlmRequestTrampoline(userData unsafe.Pointer, request *C.FfiLLMRequest) * fn := lookupClosure(userData).(LLMRequestFunc) // Extract headers and content from the incoming FfiLLMRequest - cHeaders := C.nemo_flow_llm_request_headers(request) - cContent := C.nemo_flow_llm_request_content(request) + cHeaders := C.nemo_relay_llm_request_headers(request) + cContent := C.nemo_relay_llm_request_content(request) goHeaders := json.RawMessage(C.GoString(cHeaders)) goContent := json.RawMessage(C.GoString(cContent)) - C.nemo_flow_string_free(cHeaders) - C.nemo_flow_string_free(cContent) + C.nemo_relay_string_free(cHeaders) + C.nemo_relay_string_free(cContent) // Call the Go callback newHeaders, newContent := fn(goHeaders, goContent) @@ -406,7 +406,7 @@ func goLlmRequestTrampoline(userData unsafe.Pointer, request *C.FfiLLMRequest) * cNewContent := C.CString(string(newContent)) defer C.free(unsafe.Pointer(cNewHeaders)) defer C.free(unsafe.Pointer(cNewContent)) - return C.nemo_flow_llm_request_new(cNewHeaders, cNewContent) + return C.nemo_relay_llm_request_new(cNewHeaders, cNewContent) } //export goLlmResponseTrampoline @@ -422,12 +422,12 @@ func goLlmConditionalTrampoline(userData unsafe.Pointer, request *C.FfiLLMReques fn := lookupClosure(userData).(LLMConditionalFunc) // Extract headers and content from the incoming FfiLLMRequest - cHeaders := C.nemo_flow_llm_request_headers(request) - cContent := C.nemo_flow_llm_request_content(request) + cHeaders := C.nemo_relay_llm_request_headers(request) + cContent := C.nemo_relay_llm_request_content(request) goHeaders := json.RawMessage(C.GoString(cHeaders)) goContent := json.RawMessage(C.GoString(cContent)) - C.nemo_flow_string_free(cHeaders) - C.nemo_flow_string_free(cContent) + C.nemo_relay_string_free(cHeaders) + C.nemo_relay_string_free(cContent) result := fn(goHeaders, goContent) if result == nil { @@ -450,7 +450,7 @@ func goLlmExecTrampoline(userData unsafe.Pointer, nativeJSON *C.char) *C.char { } //export goToolExecInterceptTrampoline -func goToolExecInterceptTrampoline(userData unsafe.Pointer, argsJSON *C.char, nextFn C.NemoFlowToolExecNextFn, nextCtx unsafe.Pointer) *C.char { +func goToolExecInterceptTrampoline(userData unsafe.Pointer, argsJSON *C.char, nextFn C.NemoRelayToolExecNextFn, nextCtx unsafe.Pointer) *C.char { fn := lookupClosure(userData).(ToolExecutionInterceptFunc) goArgs := json.RawMessage(C.GoString(argsJSON)) goNext := func(args json.RawMessage) (json.RawMessage, error) { @@ -460,7 +460,7 @@ func goToolExecInterceptTrampoline(userData unsafe.Pointer, argsJSON *C.char, ne if result == nil { return nil, lastError() } - defer C.nemo_flow_string_free(result) + defer C.nemo_relay_string_free(result) return json.RawMessage(C.GoString(result)), nil } result, err := fn(goArgs, goNext) @@ -472,7 +472,7 @@ func goToolExecInterceptTrampoline(userData unsafe.Pointer, argsJSON *C.char, ne } //export goLlmExecInterceptTrampoline -func goLlmExecInterceptTrampoline(userData unsafe.Pointer, nativeJSON *C.char, nextFn C.NemoFlowLlmExecNextFn, nextCtx unsafe.Pointer) *C.char { +func goLlmExecInterceptTrampoline(userData unsafe.Pointer, nativeJSON *C.char, nextFn C.NemoRelayLlmExecNextFn, nextCtx unsafe.Pointer) *C.char { fn := lookupClosure(userData).(LLMExecutionInterceptFunc) goJSON := json.RawMessage(C.GoString(nativeJSON)) @@ -484,7 +484,7 @@ func goLlmExecInterceptTrampoline(userData unsafe.Pointer, nativeJSON *C.char, n if result == nil { return nil, lastError() } - defer C.nemo_flow_string_free(result) + defer C.nemo_relay_string_free(result) return json.RawMessage(C.GoString(result)), nil } @@ -516,12 +516,12 @@ func goLlmRequestInterceptTrampoline( ) C.int32_t { fn := lookupClosure(userData).(LLMRequestInterceptFunc) goName := C.GoString(name) - cHeaders := C.nemo_flow_llm_request_headers(request) - cContent := C.nemo_flow_llm_request_content(request) + cHeaders := C.nemo_relay_llm_request_headers(request) + cContent := C.nemo_relay_llm_request_content(request) goHeaders := json.RawMessage(C.GoString(cHeaders)) goContent := json.RawMessage(C.GoString(cContent)) - C.nemo_flow_string_free(cHeaders) - C.nemo_flow_string_free(cContent) + C.nemo_relay_string_free(cHeaders) + C.nemo_relay_string_free(cContent) var goAnnotated json.RawMessage if annotatedJSON != nil { goAnnotated = json.RawMessage(C.GoString(annotatedJSON)) @@ -529,18 +529,18 @@ func goLlmRequestInterceptTrampoline( newHeaders, newContent, newAnnotated, err := llmRequestInterceptPayload(fn, goName, goHeaders, goContent, goAnnotated) if err != nil { setLastErrorMessage(err.Error()) - return 5 // NemoFlowStatus::Internal + return 5 // NemoRelayStatus::Internal } // Create output FfiLLMRequest cNewHeaders := C.CString(string(newHeaders)) cNewContent := C.CString(string(newContent)) defer C.free(unsafe.Pointer(cNewHeaders)) defer C.free(unsafe.Pointer(cNewContent)) - *outRequest = C.nemo_flow_llm_request_new(cNewHeaders, cNewContent) + *outRequest = C.nemo_relay_llm_request_new(cNewHeaders, cNewContent) if newAnnotated != nil { *outAnnotatedJSON = C.CString(string(newAnnotated)) } - return 0 // NemoFlowStatus::Ok + return 0 // NemoRelayStatus::Ok } //export goPluginValidateTrampoline diff --git a/go/nemo_flow/callbacks_test.go b/go/nemo_relay/callbacks_test.go similarity index 97% rename from go/nemo_flow/callbacks_test.go rename to go/nemo_relay/callbacks_test.go index 10d5d5140..0da74a49d 100644 --- a/go/nemo_flow/callbacks_test.go +++ b/go/nemo_relay/callbacks_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/context_test.go b/go/nemo_relay/context_test.go similarity index 99% rename from go/nemo_flow/context_test.go rename to go/nemo_relay/context_test.go index bc39f34e9..81ab523a4 100644 --- a/go/nemo_flow/context_test.go +++ b/go/nemo_relay/context_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/coverage_gap_test.go b/go/nemo_relay/coverage_gap_test.go similarity index 99% rename from go/nemo_flow/coverage_gap_test.go rename to go/nemo_relay/coverage_gap_test.go index 6b8176688..ca515444c 100644 --- a/go/nemo_flow/coverage_gap_test.go +++ b/go/nemo_relay/coverage_gap_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/deregister_test.go b/go/nemo_relay/deregister_test.go similarity index 99% rename from go/nemo_flow/deregister_test.go rename to go/nemo_relay/deregister_test.go index c58795659..437b47641 100644 --- a/go/nemo_flow/deregister_test.go +++ b/go/nemo_relay/deregister_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/error_test.go b/go/nemo_relay/error_test.go similarity index 99% rename from go/nemo_flow/error_test.go rename to go/nemo_relay/error_test.go index 428ce8455..860dda87e 100644 --- a/go/nemo_flow/error_test.go +++ b/go/nemo_relay/error_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_relay/go.mod b/go/nemo_relay/go.mod new file mode 100644 index 000000000..1ca2b8c55 --- /dev/null +++ b/go/nemo_relay/go.mod @@ -0,0 +1,3 @@ +module github.com/NVIDIA/NeMo-Relay/go/nemo_relay + +go 1.21 diff --git a/go/nemo_flow/guardrails/guardrails.go b/go/nemo_relay/guardrails/guardrails.go similarity index 63% rename from go/nemo_flow/guardrails/guardrails.go rename to go/nemo_relay/guardrails/guardrails.go index 35873ddef..7fb212280 100644 --- a/go/nemo_flow/guardrails/guardrails.go +++ b/go/nemo_relay/guardrails/guardrails.go @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package guardrails provides shorthand access to NeMo Flow guardrail registration. +// Package guardrails provides shorthand access to NeMo Relay guardrail registration. // // Guardrails are priority-ordered middleware that sanitize or gate tool and LLM // calls. They run in priority order (lower values first). Function names drop -// the "Guardrail" suffix found in the parent nemo_flow package. +// the "Guardrail" suffix found in the parent nemo_relay package. // // Three guardrail categories are supported for both tools and LLMs: // - SanitizeRequest: modifies outgoing request arguments/parameters. @@ -14,7 +14,7 @@ // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/guardrails" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/guardrails" // // // Register a tool request sanitizer that redacts sensitive fields. // err := guardrails.RegisterToolSanitizeRequest("redact-pii", 10, @@ -31,7 +31,7 @@ package guardrails import ( "encoding/json" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) // --- Tool Sanitize Request --- @@ -40,15 +40,15 @@ import ( // arguments before they are passed to the tool. The callback receives the tool // name and arguments JSON and must return the (possibly modified) arguments. // Guardrails run in priority order (lower values first). This is a shorthand -// for [nemo_flow.RegisterToolSanitizeRequestGuardrail]. -func RegisterToolSanitizeRequest(name string, priority int32, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.RegisterToolSanitizeRequestGuardrail(name, priority, fn) +// for [nemo_relay.RegisterToolSanitizeRequestGuardrail]. +func RegisterToolSanitizeRequest(name string, priority int32, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.RegisterToolSanitizeRequestGuardrail(name, priority, fn) } // DeregisterToolSanitizeRequest removes a tool sanitize-request guardrail by -// name. This is a shorthand for [nemo_flow.DeregisterToolSanitizeRequestGuardrail]. +// name. This is a shorthand for [nemo_relay.DeregisterToolSanitizeRequestGuardrail]. func DeregisterToolSanitizeRequest(name string) error { - return nemo_flow.DeregisterToolSanitizeRequestGuardrail(name) + return nemo_relay.DeregisterToolSanitizeRequestGuardrail(name) } // --- Tool Sanitize Response --- @@ -56,15 +56,15 @@ func DeregisterToolSanitizeRequest(name string) error { // RegisterToolSanitizeResponse registers a guardrail that sanitizes tool // response data before it is returned to the caller. The callback receives the // tool name and response JSON and must return the (possibly modified) response. -// This is a shorthand for [nemo_flow.RegisterToolSanitizeResponseGuardrail]. -func RegisterToolSanitizeResponse(name string, priority int32, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.RegisterToolSanitizeResponseGuardrail(name, priority, fn) +// This is a shorthand for [nemo_relay.RegisterToolSanitizeResponseGuardrail]. +func RegisterToolSanitizeResponse(name string, priority int32, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.RegisterToolSanitizeResponseGuardrail(name, priority, fn) } // DeregisterToolSanitizeResponse removes a tool sanitize-response guardrail by -// name. This is a shorthand for [nemo_flow.DeregisterToolSanitizeResponseGuardrail]. +// name. This is a shorthand for [nemo_relay.DeregisterToolSanitizeResponseGuardrail]. func DeregisterToolSanitizeResponse(name string) error { - return nemo_flow.DeregisterToolSanitizeResponseGuardrail(name) + return nemo_relay.DeregisterToolSanitizeResponseGuardrail(name) } // --- Tool Conditional Execution --- @@ -72,31 +72,31 @@ func DeregisterToolSanitizeResponse(name string) error { // RegisterToolConditionalExecution registers a guardrail that conditionally // gates tool execution. The callback returns nil to allow execution or a // non-nil pointer to an error message string to reject it. This is a shorthand -// for [nemo_flow.RegisterToolConditionalExecutionGuardrail]. -func RegisterToolConditionalExecution(name string, priority int32, fn nemo_flow.ToolConditionalFunc) error { - return nemo_flow.RegisterToolConditionalExecutionGuardrail(name, priority, fn) +// for [nemo_relay.RegisterToolConditionalExecutionGuardrail]. +func RegisterToolConditionalExecution(name string, priority int32, fn nemo_relay.ToolConditionalFunc) error { + return nemo_relay.RegisterToolConditionalExecutionGuardrail(name, priority, fn) } // DeregisterToolConditionalExecution removes a tool conditional-execution // guardrail by name. This is a shorthand for -// [nemo_flow.DeregisterToolConditionalExecutionGuardrail]. +// [nemo_relay.DeregisterToolConditionalExecutionGuardrail]. func DeregisterToolConditionalExecution(name string) error { - return nemo_flow.DeregisterToolConditionalExecutionGuardrail(name) + return nemo_relay.DeregisterToolConditionalExecutionGuardrail(name) } // --- LLM Sanitize Request --- // RegisterLlmSanitizeRequest registers a guardrail that sanitizes the LLM // request data (headers and content) before the call is made. This is a -// shorthand for [nemo_flow.RegisterLlmSanitizeRequestGuardrail]. -func RegisterLlmSanitizeRequest(name string, priority int32, fn nemo_flow.LLMRequestFunc) error { - return nemo_flow.RegisterLlmSanitizeRequestGuardrail(name, priority, fn) +// shorthand for [nemo_relay.RegisterLlmSanitizeRequestGuardrail]. +func RegisterLlmSanitizeRequest(name string, priority int32, fn nemo_relay.LLMRequestFunc) error { + return nemo_relay.RegisterLlmSanitizeRequestGuardrail(name, priority, fn) } // DeregisterLlmSanitizeRequest removes an LLM sanitize-request guardrail by -// name. This is a shorthand for [nemo_flow.DeregisterLlmSanitizeRequestGuardrail]. +// name. This is a shorthand for [nemo_relay.DeregisterLlmSanitizeRequestGuardrail]. func DeregisterLlmSanitizeRequest(name string) error { - return nemo_flow.DeregisterLlmSanitizeRequestGuardrail(name) + return nemo_relay.DeregisterLlmSanitizeRequestGuardrail(name) } // --- LLM Sanitize Response --- @@ -104,15 +104,15 @@ func DeregisterLlmSanitizeRequest(name string) error { // RegisterLlmSanitizeResponse registers a guardrail that sanitizes LLM response // data before it is returned to the caller. The callback receives the response // as plain JSON. This is a shorthand for -// [nemo_flow.RegisterLlmSanitizeResponseGuardrail]. -func RegisterLlmSanitizeResponse(name string, priority int32, fn nemo_flow.LLMResponseFunc) error { - return nemo_flow.RegisterLlmSanitizeResponseGuardrail(name, priority, fn) +// [nemo_relay.RegisterLlmSanitizeResponseGuardrail]. +func RegisterLlmSanitizeResponse(name string, priority int32, fn nemo_relay.LLMResponseFunc) error { + return nemo_relay.RegisterLlmSanitizeResponseGuardrail(name, priority, fn) } // DeregisterLlmSanitizeResponse removes an LLM sanitize-response guardrail by -// name. This is a shorthand for [nemo_flow.DeregisterLlmSanitizeResponseGuardrail]. +// name. This is a shorthand for [nemo_relay.DeregisterLlmSanitizeResponseGuardrail]. func DeregisterLlmSanitizeResponse(name string) error { - return nemo_flow.DeregisterLlmSanitizeResponseGuardrail(name) + return nemo_relay.DeregisterLlmSanitizeResponseGuardrail(name) } // --- LLM Conditional Execution --- @@ -121,128 +121,128 @@ func DeregisterLlmSanitizeResponse(name string) error { // gates LLM execution. The callback receives LLM request parameters and returns // nil to allow execution or a non-nil pointer to an error message string to // reject it. This is a shorthand for -// [nemo_flow.RegisterLlmConditionalExecutionGuardrail]. -func RegisterLlmConditionalExecution(name string, priority int32, fn nemo_flow.LLMConditionalFunc) error { - return nemo_flow.RegisterLlmConditionalExecutionGuardrail(name, priority, fn) +// [nemo_relay.RegisterLlmConditionalExecutionGuardrail]. +func RegisterLlmConditionalExecution(name string, priority int32, fn nemo_relay.LLMConditionalFunc) error { + return nemo_relay.RegisterLlmConditionalExecutionGuardrail(name, priority, fn) } // DeregisterLlmConditionalExecution removes an LLM conditional-execution // guardrail by name. This is a shorthand for -// [nemo_flow.DeregisterLlmConditionalExecutionGuardrail]. +// [nemo_relay.DeregisterLlmConditionalExecutionGuardrail]. func DeregisterLlmConditionalExecution(name string) error { - return nemo_flow.DeregisterLlmConditionalExecutionGuardrail(name) + return nemo_relay.DeregisterLlmConditionalExecutionGuardrail(name) } // --- Scope-local Tool Sanitize Request --- // ScopeRegisterToolSanitizeRequest registers a scope-local guardrail that // sanitizes tool request arguments. This is a shorthand for -// [nemo_flow.ScopeRegisterToolSanitizeRequestGuardrail]. -func ScopeRegisterToolSanitizeRequest(scopeUUID, name string, priority int32, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.ScopeRegisterToolSanitizeRequestGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterToolSanitizeRequestGuardrail]. +func ScopeRegisterToolSanitizeRequest(scopeUUID, name string, priority int32, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.ScopeRegisterToolSanitizeRequestGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterToolSanitizeRequest removes a scope-local tool sanitize-request // guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterToolSanitizeRequestGuardrail]. +// [nemo_relay.ScopeDeregisterToolSanitizeRequestGuardrail]. func ScopeDeregisterToolSanitizeRequest(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterToolSanitizeRequestGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterToolSanitizeRequestGuardrail(scopeUUID, name) } // --- Scope-local Tool Sanitize Response --- // ScopeRegisterToolSanitizeResponse registers a scope-local guardrail that // sanitizes tool response data. This is a shorthand for -// [nemo_flow.ScopeRegisterToolSanitizeResponseGuardrail]. -func ScopeRegisterToolSanitizeResponse(scopeUUID, name string, priority int32, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.ScopeRegisterToolSanitizeResponseGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterToolSanitizeResponseGuardrail]. +func ScopeRegisterToolSanitizeResponse(scopeUUID, name string, priority int32, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.ScopeRegisterToolSanitizeResponseGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterToolSanitizeResponse removes a scope-local tool // sanitize-response guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterToolSanitizeResponseGuardrail]. +// [nemo_relay.ScopeDeregisterToolSanitizeResponseGuardrail]. func ScopeDeregisterToolSanitizeResponse(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterToolSanitizeResponseGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterToolSanitizeResponseGuardrail(scopeUUID, name) } // --- Scope-local Tool Conditional Execution --- // ScopeRegisterToolConditionalExecution registers a scope-local guardrail that // conditionally gates tool execution. This is a shorthand for -// [nemo_flow.ScopeRegisterToolConditionalExecutionGuardrail]. -func ScopeRegisterToolConditionalExecution(scopeUUID, name string, priority int32, fn nemo_flow.ToolConditionalFunc) error { - return nemo_flow.ScopeRegisterToolConditionalExecutionGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterToolConditionalExecutionGuardrail]. +func ScopeRegisterToolConditionalExecution(scopeUUID, name string, priority int32, fn nemo_relay.ToolConditionalFunc) error { + return nemo_relay.ScopeRegisterToolConditionalExecutionGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterToolConditionalExecution removes a scope-local tool // conditional-execution guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterToolConditionalExecutionGuardrail]. +// [nemo_relay.ScopeDeregisterToolConditionalExecutionGuardrail]. func ScopeDeregisterToolConditionalExecution(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterToolConditionalExecutionGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterToolConditionalExecutionGuardrail(scopeUUID, name) } // --- Scope-local LLM Sanitize Request --- // ScopeRegisterLlmSanitizeRequest registers a scope-local guardrail that // sanitizes the LLM request data. This is a shorthand for -// [nemo_flow.ScopeRegisterLlmSanitizeRequestGuardrail]. -func ScopeRegisterLlmSanitizeRequest(scopeUUID, name string, priority int32, fn nemo_flow.LLMRequestFunc) error { - return nemo_flow.ScopeRegisterLlmSanitizeRequestGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterLlmSanitizeRequestGuardrail]. +func ScopeRegisterLlmSanitizeRequest(scopeUUID, name string, priority int32, fn nemo_relay.LLMRequestFunc) error { + return nemo_relay.ScopeRegisterLlmSanitizeRequestGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterLlmSanitizeRequest removes a scope-local LLM sanitize-request // guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterLlmSanitizeRequestGuardrail]. +// [nemo_relay.ScopeDeregisterLlmSanitizeRequestGuardrail]. func ScopeDeregisterLlmSanitizeRequest(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmSanitizeRequestGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmSanitizeRequestGuardrail(scopeUUID, name) } // --- Scope-local LLM Sanitize Response --- // ScopeRegisterLlmSanitizeResponse registers a scope-local guardrail that // sanitizes LLM response data. This is a shorthand for -// [nemo_flow.ScopeRegisterLlmSanitizeResponseGuardrail]. -func ScopeRegisterLlmSanitizeResponse(scopeUUID, name string, priority int32, fn nemo_flow.LLMResponseFunc) error { - return nemo_flow.ScopeRegisterLlmSanitizeResponseGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterLlmSanitizeResponseGuardrail]. +func ScopeRegisterLlmSanitizeResponse(scopeUUID, name string, priority int32, fn nemo_relay.LLMResponseFunc) error { + return nemo_relay.ScopeRegisterLlmSanitizeResponseGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterLlmSanitizeResponse removes a scope-local LLM // sanitize-response guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterLlmSanitizeResponseGuardrail]. +// [nemo_relay.ScopeDeregisterLlmSanitizeResponseGuardrail]. func ScopeDeregisterLlmSanitizeResponse(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmSanitizeResponseGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmSanitizeResponseGuardrail(scopeUUID, name) } // --- Scope-local LLM Conditional Execution --- // ScopeRegisterLlmConditionalExecution registers a scope-local guardrail that // conditionally gates LLM execution. This is a shorthand for -// [nemo_flow.ScopeRegisterLlmConditionalExecutionGuardrail]. -func ScopeRegisterLlmConditionalExecution(scopeUUID, name string, priority int32, fn nemo_flow.LLMConditionalFunc) error { - return nemo_flow.ScopeRegisterLlmConditionalExecutionGuardrail(scopeUUID, name, priority, fn) +// [nemo_relay.ScopeRegisterLlmConditionalExecutionGuardrail]. +func ScopeRegisterLlmConditionalExecution(scopeUUID, name string, priority int32, fn nemo_relay.LLMConditionalFunc) error { + return nemo_relay.ScopeRegisterLlmConditionalExecutionGuardrail(scopeUUID, name, priority, fn) } // ScopeDeregisterLlmConditionalExecution removes a scope-local LLM // conditional-execution guardrail by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterLlmConditionalExecutionGuardrail]. +// [nemo_relay.ScopeDeregisterLlmConditionalExecutionGuardrail]. func ScopeDeregisterLlmConditionalExecution(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmConditionalExecutionGuardrail(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmConditionalExecutionGuardrail(scopeUUID, name) } // --- Tool Conditional Execution (standalone) --- // ToolConditionalExecution runs the registered tool conditional execution // guardrail chain. Returns nil if all pass, or an error if blocked. This is a -// shorthand for [nemo_flow.ToolConditionalExecution]. +// shorthand for [nemo_relay.ToolConditionalExecution]. func ToolConditionalExecution(name string, args json.RawMessage) error { - return nemo_flow.ToolConditionalExecution(name, args) + return nemo_relay.ToolConditionalExecution(name, args) } // --- LLM Conditional Execution (standalone) --- // LlmConditionalExecution runs the registered LLM conditional execution // guardrail chain. Returns nil if all pass, or an error if blocked. This is a -// shorthand for [nemo_flow.LlmConditionalExecution]. +// shorthand for [nemo_relay.LlmConditionalExecution]. func LlmConditionalExecution(request json.RawMessage) error { - return nemo_flow.LlmConditionalExecution(request) + return nemo_relay.LlmConditionalExecution(request) } diff --git a/go/nemo_flow/guardrails/guardrails_test.go b/go/nemo_relay/guardrails/guardrails_test.go similarity index 92% rename from go/nemo_flow/guardrails/guardrails_test.go rename to go/nemo_relay/guardrails/guardrails_test.go index 76059d132..0c65f4012 100644 --- a/go/nemo_flow/guardrails/guardrails_test.go +++ b/go/nemo_relay/guardrails/guardrails_test.go @@ -8,8 +8,8 @@ import ( "sync" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/guardrails" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/guardrails" ) func makeRequest() map[string]interface{} { @@ -24,7 +24,7 @@ func captureEndEventOutput(t *testing.T, subscriberName, eventName string) (func var output json.RawMessage var mu sync.Mutex - if err := nemo_flow.RegisterSubscriber(subscriberName, func(event nemo_flow.Event) { + if err := nemo_relay.RegisterSubscriber(subscriberName, func(event nemo_relay.Event) { mu.Lock() defer mu.Unlock() if event.Kind() == "scope" && event.ScopeCategory() == "end" && event.Name() == eventName { @@ -40,7 +40,7 @@ func captureEndEventOutput(t *testing.T, subscriberName, eventName string) (func return append(json.RawMessage(nil), output...) } cleanup := func() { - _ = nemo_flow.DeregisterSubscriber(subscriberName) + _ = nemo_relay.DeregisterSubscriber(subscriberName) } return getOutput, cleanup } @@ -99,7 +99,7 @@ func runGlobalToolGuardrailShorthandChecks(t *testing.T, output func() json.RawM _ = guardrails.DeregisterToolConditionalExecution("guardrails_tool_cond") }) - if _, err := nemo_flow.ToolCallExecute("guardrails_tool", json.RawMessage(`{"value": 1}`), + if _, err := nemo_relay.ToolCallExecute("guardrails_tool", json.RawMessage(`{"value": 1}`), func(args json.RawMessage) (json.RawMessage, error) { return json.RawMessage(`{"ok": true}`), nil }, @@ -155,7 +155,7 @@ func runGlobalLLMGuardrailShorthandChecks(t *testing.T, output func() json.RawMe _ = guardrails.DeregisterLlmConditionalExecution("guardrails_llm_cond") }) - if _, err := nemo_flow.LlmCallExecute("guardrails_llm", makeRequest(), + if _, err := nemo_relay.LlmCallExecute("guardrails_llm", makeRequest(), func(nativeJSON json.RawMessage) (json.RawMessage, error) { return json.RawMessage(`{"ok": true}`), nil }, @@ -188,7 +188,7 @@ func runScopeLocalToolGuardrailShorthandChecks(t *testing.T, scopeUUID string) { t.Fatalf("ScopeRegisterToolConditionalExecution failed: %v", err) } - if _, err := nemo_flow.ToolCallExecute("guardrails_scope_tool", json.RawMessage(`{"ok": true}`), + if _, err := nemo_relay.ToolCallExecute("guardrails_scope_tool", json.RawMessage(`{"ok": true}`), func(args json.RawMessage) (json.RawMessage, error) { return args, nil }, ); err != nil { t.Fatalf("ToolCallExecute failed: %v", err) @@ -226,7 +226,7 @@ func runScopeLocalLLMGuardrailShorthandChecks(t *testing.T, scopeUUID string) { t.Fatalf("ScopeRegisterLlmConditionalExecution failed: %v", err) } - if _, err := nemo_flow.LlmCallExecute("guardrails_scope_llm", makeRequest(), + if _, err := nemo_relay.LlmCallExecute("guardrails_scope_llm", makeRequest(), func(nativeJSON json.RawMessage) (json.RawMessage, error) { return json.RawMessage(`{"ok": true}`), nil }, @@ -256,18 +256,18 @@ func TestGuardrailShorthandsGlobal(t *testing.T) { } func TestGuardrailShorthandsScopeLocal(t *testing.T) { - stack, err := nemo_flow.NewScopeStack() + stack, err := nemo_relay.NewScopeStack() if err != nil { t.Fatalf("NewScopeStack failed: %v", err) } defer stack.Close() stack.Run(func() { - handle, err := nemo_flow.PushScope("guardrails_scope", nemo_flow.ScopeTypeAgent) + handle, err := nemo_relay.PushScope("guardrails_scope", nemo_relay.ScopeTypeAgent) if err != nil { t.Fatalf("PushScope failed: %v", err) } - defer nemo_flow.PopScope(handle) + defer nemo_relay.PopScope(handle) scopeUUID := handle.UUID() runScopeLocalToolGuardrailShorthandChecks(t, scopeUUID) diff --git a/go/nemo_flow/intercepts/intercepts.go b/go/nemo_relay/intercepts/intercepts.go similarity index 62% rename from go/nemo_flow/intercepts/intercepts.go rename to go/nemo_relay/intercepts/intercepts.go index 4c7c9ca16..5872b74a6 100644 --- a/go/nemo_flow/intercepts/intercepts.go +++ b/go/nemo_relay/intercepts/intercepts.go @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package intercepts provides shorthand access to NeMo Flow intercept registration. +// Package intercepts provides shorthand access to NeMo Relay intercept registration. // // Intercepts are priority-ordered middleware that transform or replace tool and // LLM calls. They run in priority order (lower values first). Function names -// drop the "Intercept" suffix found in the parent nemo_flow package. +// drop the "Intercept" suffix found in the parent nemo_relay package. // // Intercept categories for both tools and LLMs: // - Request: transforms request arguments/parameters; supports breakChain. @@ -17,7 +17,7 @@ // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/intercepts" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/intercepts" // // // Register a tool request intercept that injects a trace ID. // err := intercepts.RegisterToolRequest("add-trace-id", 5, false, @@ -34,22 +34,22 @@ package intercepts import ( "encoding/json" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) // --- Tool Request --- // RegisterToolRequest registers an intercept that transforms tool request // arguments. When breakChain is true, no lower-priority intercepts run after -// this one. This is a shorthand for [nemo_flow.RegisterToolRequestIntercept]. -func RegisterToolRequest(name string, priority int32, breakChain bool, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.RegisterToolRequestIntercept(name, priority, breakChain, fn) +// this one. This is a shorthand for [nemo_relay.RegisterToolRequestIntercept]. +func RegisterToolRequest(name string, priority int32, breakChain bool, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.RegisterToolRequestIntercept(name, priority, breakChain, fn) } // DeregisterToolRequest removes a tool request intercept by name. This is a -// shorthand for [nemo_flow.DeregisterToolRequestIntercept]. +// shorthand for [nemo_relay.DeregisterToolRequestIntercept]. func DeregisterToolRequest(name string) error { - return nemo_flow.DeregisterToolRequestIntercept(name) + return nemo_relay.DeregisterToolRequestIntercept(name) } // --- Tool Execution --- @@ -57,15 +57,15 @@ func DeregisterToolRequest(name string) error { // RegisterToolExecution registers a tool execution intercept following the // middleware chain pattern. execFn is called with args and a next function. // Call next to continue the chain or skip it to short-circuit. This is a -// shorthand for [nemo_flow.RegisterToolExecutionIntercept]. -func RegisterToolExecution(name string, priority int32, execFn nemo_flow.ToolExecutionInterceptFunc) error { - return nemo_flow.RegisterToolExecutionIntercept(name, priority, execFn) +// shorthand for [nemo_relay.RegisterToolExecutionIntercept]. +func RegisterToolExecution(name string, priority int32, execFn nemo_relay.ToolExecutionInterceptFunc) error { + return nemo_relay.RegisterToolExecutionIntercept(name, priority, execFn) } // DeregisterToolExecution removes a tool execution intercept by name. This is a -// shorthand for [nemo_flow.DeregisterToolExecutionIntercept]. +// shorthand for [nemo_relay.DeregisterToolExecutionIntercept]. func DeregisterToolExecution(name string) error { - return nemo_flow.DeregisterToolExecutionIntercept(name) + return nemo_relay.DeregisterToolExecutionIntercept(name) } // --- LLM Request --- @@ -73,15 +73,15 @@ func DeregisterToolExecution(name string) error { // RegisterLlmRequest registers an intercept that transforms the LLM request // (headers, content, and optionally annotated JSON). When breakChain is true, // no lower-priority intercepts run after this one. This is a shorthand for -// [nemo_flow.RegisterLlmRequestIntercept]. -func RegisterLlmRequest(name string, priority int32, breakChain bool, fn nemo_flow.LLMRequestInterceptFunc) error { - return nemo_flow.RegisterLlmRequestIntercept(name, priority, breakChain, fn) +// [nemo_relay.RegisterLlmRequestIntercept]. +func RegisterLlmRequest(name string, priority int32, breakChain bool, fn nemo_relay.LLMRequestInterceptFunc) error { + return nemo_relay.RegisterLlmRequestIntercept(name, priority, breakChain, fn) } // DeregisterLlmRequest removes an LLM request intercept by name. This is a -// shorthand for [nemo_flow.DeregisterLlmRequestIntercept]. +// shorthand for [nemo_relay.DeregisterLlmRequestIntercept]. func DeregisterLlmRequest(name string) error { - return nemo_flow.DeregisterLlmRequestIntercept(name) + return nemo_relay.DeregisterLlmRequestIntercept(name) } // --- LLM Execution --- @@ -89,15 +89,15 @@ func DeregisterLlmRequest(name string) error { // RegisterLlmExecution registers an LLM execution intercept following the // middleware chain pattern. execFn is called with the request and a next // function. Call next to continue the chain or skip it to short-circuit. This -// is a shorthand for [nemo_flow.RegisterLlmExecutionIntercept]. -func RegisterLlmExecution(name string, priority int32, execFn nemo_flow.LLMExecutionInterceptFunc) error { - return nemo_flow.RegisterLlmExecutionIntercept(name, priority, execFn) +// is a shorthand for [nemo_relay.RegisterLlmExecutionIntercept]. +func RegisterLlmExecution(name string, priority int32, execFn nemo_relay.LLMExecutionInterceptFunc) error { + return nemo_relay.RegisterLlmExecutionIntercept(name, priority, execFn) } // DeregisterLlmExecution removes an LLM execution intercept by name. This is a -// shorthand for [nemo_flow.DeregisterLlmExecutionIntercept]. +// shorthand for [nemo_relay.DeregisterLlmExecutionIntercept]. func DeregisterLlmExecution(name string) error { - return nemo_flow.DeregisterLlmExecutionIntercept(name) + return nemo_relay.DeregisterLlmExecutionIntercept(name) } // --- LLM Stream Execution --- @@ -105,107 +105,107 @@ func DeregisterLlmExecution(name string) error { // RegisterLlmStreamExecution registers a streaming LLM execution intercept // following the middleware chain pattern. execFn is called with the request and // a next function. Call next to continue the chain or skip it to short-circuit. -// This is a shorthand for [nemo_flow.RegisterLlmStreamExecutionIntercept]. -func RegisterLlmStreamExecution(name string, priority int32, execFn nemo_flow.LLMExecutionInterceptFunc) error { - return nemo_flow.RegisterLlmStreamExecutionIntercept(name, priority, execFn) +// This is a shorthand for [nemo_relay.RegisterLlmStreamExecutionIntercept]. +func RegisterLlmStreamExecution(name string, priority int32, execFn nemo_relay.LLMExecutionInterceptFunc) error { + return nemo_relay.RegisterLlmStreamExecutionIntercept(name, priority, execFn) } // DeregisterLlmStreamExecution removes an LLM stream execution intercept by -// name. This is a shorthand for [nemo_flow.DeregisterLlmStreamExecutionIntercept]. +// name. This is a shorthand for [nemo_relay.DeregisterLlmStreamExecutionIntercept]. func DeregisterLlmStreamExecution(name string) error { - return nemo_flow.DeregisterLlmStreamExecutionIntercept(name) + return nemo_relay.DeregisterLlmStreamExecutionIntercept(name) } // --- Scope-local Tool Request --- // ScopeRegisterToolRequest registers a scope-local intercept that transforms // tool request arguments. This is a shorthand for -// [nemo_flow.ScopeRegisterToolRequestIntercept]. -func ScopeRegisterToolRequest(scopeUUID, name string, priority int32, breakChain bool, fn nemo_flow.ToolSanitizeFunc) error { - return nemo_flow.ScopeRegisterToolRequestIntercept(scopeUUID, name, priority, breakChain, fn) +// [nemo_relay.ScopeRegisterToolRequestIntercept]. +func ScopeRegisterToolRequest(scopeUUID, name string, priority int32, breakChain bool, fn nemo_relay.ToolSanitizeFunc) error { + return nemo_relay.ScopeRegisterToolRequestIntercept(scopeUUID, name, priority, breakChain, fn) } // ScopeDeregisterToolRequest removes a scope-local tool request intercept by -// name. This is a shorthand for [nemo_flow.ScopeDeregisterToolRequestIntercept]. +// name. This is a shorthand for [nemo_relay.ScopeDeregisterToolRequestIntercept]. func ScopeDeregisterToolRequest(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterToolRequestIntercept(scopeUUID, name) + return nemo_relay.ScopeDeregisterToolRequestIntercept(scopeUUID, name) } // --- Scope-local Tool Execution --- // ScopeRegisterToolExecution registers a scope-local tool execution intercept // following the middleware chain pattern. This is a shorthand for -// [nemo_flow.ScopeRegisterToolExecutionIntercept]. -func ScopeRegisterToolExecution(scopeUUID, name string, priority int32, execFn nemo_flow.ToolExecutionInterceptFunc) error { - return nemo_flow.ScopeRegisterToolExecutionIntercept(scopeUUID, name, priority, execFn) +// [nemo_relay.ScopeRegisterToolExecutionIntercept]. +func ScopeRegisterToolExecution(scopeUUID, name string, priority int32, execFn nemo_relay.ToolExecutionInterceptFunc) error { + return nemo_relay.ScopeRegisterToolExecutionIntercept(scopeUUID, name, priority, execFn) } // ScopeDeregisterToolExecution removes a scope-local tool execution intercept by -// name. This is a shorthand for [nemo_flow.ScopeDeregisterToolExecutionIntercept]. +// name. This is a shorthand for [nemo_relay.ScopeDeregisterToolExecutionIntercept]. func ScopeDeregisterToolExecution(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterToolExecutionIntercept(scopeUUID, name) + return nemo_relay.ScopeDeregisterToolExecutionIntercept(scopeUUID, name) } // --- Scope-local LLM Request --- // ScopeRegisterLlmRequest registers a scope-local intercept that transforms the // LLM request using the unified annotated-aware signature. This is a shorthand -// for [nemo_flow.ScopeRegisterLlmRequestIntercept]. -func ScopeRegisterLlmRequest(scopeUUID, name string, priority int32, breakChain bool, fn nemo_flow.LLMRequestInterceptFunc) error { - return nemo_flow.ScopeRegisterLlmRequestIntercept(scopeUUID, name, priority, breakChain, fn) +// for [nemo_relay.ScopeRegisterLlmRequestIntercept]. +func ScopeRegisterLlmRequest(scopeUUID, name string, priority int32, breakChain bool, fn nemo_relay.LLMRequestInterceptFunc) error { + return nemo_relay.ScopeRegisterLlmRequestIntercept(scopeUUID, name, priority, breakChain, fn) } // ScopeDeregisterLlmRequest removes a scope-local LLM request intercept by -// name. This is a shorthand for [nemo_flow.ScopeDeregisterLlmRequestIntercept]. +// name. This is a shorthand for [nemo_relay.ScopeDeregisterLlmRequestIntercept]. func ScopeDeregisterLlmRequest(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmRequestIntercept(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmRequestIntercept(scopeUUID, name) } // --- Scope-local LLM Execution --- // ScopeRegisterLlmExecution registers a scope-local LLM execution intercept // following the middleware chain pattern. This is a shorthand for -// [nemo_flow.ScopeRegisterLlmExecutionIntercept]. -func ScopeRegisterLlmExecution(scopeUUID, name string, priority int32, execFn nemo_flow.LLMExecutionInterceptFunc) error { - return nemo_flow.ScopeRegisterLlmExecutionIntercept(scopeUUID, name, priority, execFn) +// [nemo_relay.ScopeRegisterLlmExecutionIntercept]. +func ScopeRegisterLlmExecution(scopeUUID, name string, priority int32, execFn nemo_relay.LLMExecutionInterceptFunc) error { + return nemo_relay.ScopeRegisterLlmExecutionIntercept(scopeUUID, name, priority, execFn) } // ScopeDeregisterLlmExecution removes a scope-local LLM execution intercept by -// name. This is a shorthand for [nemo_flow.ScopeDeregisterLlmExecutionIntercept]. +// name. This is a shorthand for [nemo_relay.ScopeDeregisterLlmExecutionIntercept]. func ScopeDeregisterLlmExecution(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmExecutionIntercept(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmExecutionIntercept(scopeUUID, name) } // --- Scope-local LLM Stream Execution --- // ScopeRegisterLlmStreamExecution registers a scope-local streaming LLM // execution intercept following the middleware chain pattern. This is a shorthand -// for [nemo_flow.ScopeRegisterLlmStreamExecutionIntercept]. -func ScopeRegisterLlmStreamExecution(scopeUUID, name string, priority int32, execFn nemo_flow.LLMExecutionInterceptFunc) error { - return nemo_flow.ScopeRegisterLlmStreamExecutionIntercept(scopeUUID, name, priority, execFn) +// for [nemo_relay.ScopeRegisterLlmStreamExecutionIntercept]. +func ScopeRegisterLlmStreamExecution(scopeUUID, name string, priority int32, execFn nemo_relay.LLMExecutionInterceptFunc) error { + return nemo_relay.ScopeRegisterLlmStreamExecutionIntercept(scopeUUID, name, priority, execFn) } // ScopeDeregisterLlmStreamExecution removes a scope-local LLM stream execution // intercept by name. This is a shorthand for -// [nemo_flow.ScopeDeregisterLlmStreamExecutionIntercept]. +// [nemo_relay.ScopeDeregisterLlmStreamExecutionIntercept]. func ScopeDeregisterLlmStreamExecution(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterLlmStreamExecutionIntercept(scopeUUID, name) + return nemo_relay.ScopeDeregisterLlmStreamExecutionIntercept(scopeUUID, name) } // --- Tool Request Intercepts (standalone) --- // ToolRequestIntercepts runs the registered tool request intercept chain and // returns the transformed arguments. This is a shorthand for -// [nemo_flow.ToolRequestIntercepts]. +// [nemo_relay.ToolRequestIntercepts]. func ToolRequestIntercepts(name string, args json.RawMessage) (json.RawMessage, error) { - return nemo_flow.ToolRequestIntercepts(name, args) + return nemo_relay.ToolRequestIntercepts(name, args) } // --- LLM Request Intercepts (standalone) --- // LlmRequestIntercepts runs the registered LLM request intercept chain and // returns the transformed request. This is a shorthand for -// [nemo_flow.LlmRequestIntercepts]. +// [nemo_relay.LlmRequestIntercepts]. func LlmRequestIntercepts(name string, request json.RawMessage) (json.RawMessage, error) { - return nemo_flow.LlmRequestIntercepts(name, request) + return nemo_relay.LlmRequestIntercepts(name, request) } diff --git a/go/nemo_flow/intercepts/intercepts_test.go b/go/nemo_relay/intercepts/intercepts_test.go similarity index 92% rename from go/nemo_flow/intercepts/intercepts_test.go rename to go/nemo_relay/intercepts/intercepts_test.go index 49af857c9..1bb6eb8da 100644 --- a/go/nemo_flow/intercepts/intercepts_test.go +++ b/go/nemo_relay/intercepts/intercepts_test.go @@ -7,8 +7,8 @@ import ( "encoding/json" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/intercepts" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/intercepts" ) func makeRequest() json.RawMessage { @@ -65,7 +65,7 @@ func runGlobalToolInterceptShorthandChecks(t *testing.T) { _ = intercepts.DeregisterToolExecution("intercepts_tool_exec") }) - result, err := nemo_flow.ToolCallExecute("intercepts_tool", json.RawMessage(`{"value": 1}`), + result, err := nemo_relay.ToolCallExecute("intercepts_tool", json.RawMessage(`{"value": 1}`), func(args json.RawMessage) (json.RawMessage, error) { return json.RawMessage(`{"ok": true}`), nil }, @@ -135,7 +135,7 @@ func runGlobalLLMInterceptShorthandChecks(t *testing.T) { _ = intercepts.DeregisterLlmExecution("intercepts_llm_exec") }) - response, err := nemo_flow.LlmCallExecute("intercepts_llm", map[string]interface{}{ + response, err := nemo_relay.LlmCallExecute("intercepts_llm", map[string]interface{}{ "headers": map[string]interface{}{}, "content": map[string]interface{}{"messages": []interface{}{}, "model": "test-model"}, }, func(nativeJSON json.RawMessage) (json.RawMessage, error) { @@ -180,7 +180,7 @@ func runScopeLocalToolInterceptShorthandChecks(t *testing.T, scopeUUID string) { ); err != nil { t.Fatalf("ScopeRegisterToolExecution failed: %v", err) } - if _, err := nemo_flow.ToolCallExecute("intercepts_scope_tool", json.RawMessage(`{"ok": true}`), + if _, err := nemo_relay.ToolCallExecute("intercepts_scope_tool", json.RawMessage(`{"ok": true}`), func(args json.RawMessage) (json.RawMessage, error) { return args, nil }, ); err != nil { t.Fatalf("ToolCallExecute failed: %v", err) @@ -218,7 +218,7 @@ func runScopeLocalLLMInterceptShorthandChecks(t *testing.T, scopeUUID string) { ); err != nil { t.Fatalf("ScopeRegisterLlmStreamExecution failed: %v", err) } - if _, err := nemo_flow.LlmCallExecute("intercepts_scope_llm", map[string]interface{}{ + if _, err := nemo_relay.LlmCallExecute("intercepts_scope_llm", map[string]interface{}{ "headers": map[string]interface{}{}, "content": map[string]interface{}{"messages": []interface{}{}, "model": "test-model"}, }, func(nativeJSON json.RawMessage) (json.RawMessage, error) { @@ -244,18 +244,18 @@ func TestInterceptShorthandsGlobal(t *testing.T) { } func TestInterceptShorthandsScopeLocal(t *testing.T) { - stack, err := nemo_flow.NewScopeStack() + stack, err := nemo_relay.NewScopeStack() if err != nil { t.Fatalf("NewScopeStack failed: %v", err) } defer stack.Close() stack.Run(func() { - handle, err := nemo_flow.PushScope("intercepts_scope", nemo_flow.ScopeTypeAgent) + handle, err := nemo_relay.PushScope("intercepts_scope", nemo_relay.ScopeTypeAgent) if err != nil { t.Fatalf("PushScope failed: %v", err) } - defer nemo_flow.PopScope(handle) + defer nemo_relay.PopScope(handle) scopeUUID := handle.UUID() diff --git a/go/nemo_flow/llm/llm.go b/go/nemo_relay/llm/llm.go similarity index 58% rename from go/nemo_flow/llm/llm.go rename to go/nemo_relay/llm/llm.go index c28fe0ee5..662fa6b3e 100644 --- a/go/nemo_flow/llm/llm.go +++ b/go/nemo_relay/llm/llm.go @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package llm provides shorthand access to NeMo Flow LLM call operations. +// Package llm provides shorthand access to NeMo Relay LLM call operations. // // It re-exports the core LLM lifecycle functions (LlmCall, LlmCallEnd, // LlmCallExecute, LlmStreamCallExecute) under shorter names for convenience. // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/llm" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/llm" // // native := map[string]interface{}{"model": "gpt-4", "messages": []interface{}{}} // result, err := llm.Execute("chat", native, @@ -22,56 +22,56 @@ package llm import ( "encoding/json" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) -// Call starts an LLM call lifecycle and returns an [nemo_flow.LLMHandle], +// Call starts an LLM call lifecycle and returns an [nemo_relay.LLMHandle], // emitting a Start event. End the call with [CallEnd]. This is a shorthand for -// [nemo_flow.LlmCall]. -func Call(name string, native interface{}, opts ...nemo_flow.LLMCallOption) (*nemo_flow.LLMHandle, error) { - return nemo_flow.LlmCall(name, native, opts...) +// [nemo_relay.LlmCall]. +func Call(name string, native interface{}, opts ...nemo_relay.LLMCallOption) (*nemo_relay.LLMHandle, error) { + return nemo_relay.LlmCall(name, native, opts...) } // CallEnd completes an LLM call that was started with [Call], emitting an End -// event. This is a shorthand for [nemo_flow.LlmCallEnd]. -func CallEnd(handle *nemo_flow.LLMHandle, response json.RawMessage, opts ...nemo_flow.LLMCallOption) error { - return nemo_flow.LlmCallEnd(handle, response, opts...) +// event. This is a shorthand for [nemo_relay.LlmCallEnd]. +func CallEnd(handle *nemo_relay.LLMHandle, response json.RawMessage, opts ...nemo_relay.LLMCallOption) error { + return nemo_relay.LlmCallEnd(handle, response, opts...) } // Execute runs a complete LLM call lifecycle with the full middleware pipeline // (conditional-execution guardrails, request intercepts, sanitize-request // guardrails, execution intercepts, fn, sanitize-response // guardrails) and returns the final response JSON. This is a shorthand for -// [nemo_flow.LlmCallExecute]. -func Execute(name string, native interface{}, fn nemo_flow.LLMExecutionFunc, opts ...nemo_flow.LLMCallOption) (json.RawMessage, error) { - return nemo_flow.LlmCallExecute(name, native, fn, opts...) +// [nemo_relay.LlmCallExecute]. +func Execute(name string, native interface{}, fn nemo_relay.LLMExecutionFunc, opts ...nemo_relay.LLMCallOption) (json.RawMessage, error) { + return nemo_relay.LlmCallExecute(name, native, fn, opts...) } // StreamExecute runs a streaming LLM call lifecycle with the full middleware // pipeline (conditional-execution guardrails run first on the raw request) and -// returns an [nemo_flow.LlmStream] for consuming JSON chunks. This is a -// shorthand for [nemo_flow.LlmStreamCallExecute]. +// returns an [nemo_relay.LlmStream] for consuming JSON chunks. This is a +// shorthand for [nemo_relay.LlmStreamCallExecute]. // // The collector callback is invoked with each intercepted chunk JSON for // accumulation. The finalizer callback is invoked once when the stream is // exhausted and must return a JSON string representing the aggregated response. // Pass nil for either to use the default no-op behavior. -func StreamExecute(name string, native interface{}, fn nemo_flow.LLMExecutionFunc, collector nemo_flow.CollectorFunc, finalizer nemo_flow.FinalizerFunc, opts ...nemo_flow.LLMCallOption) (*nemo_flow.LlmStream, error) { - return nemo_flow.LlmStreamCallExecute(name, native, fn, collector, finalizer, opts...) +func StreamExecute(name string, native interface{}, fn nemo_relay.LLMExecutionFunc, collector nemo_relay.CollectorFunc, finalizer nemo_relay.FinalizerFunc, opts ...nemo_relay.LLMCallOption) (*nemo_relay.LlmStream, error) { + return nemo_relay.LlmStreamCallExecute(name, native, fn, collector, finalizer, opts...) } // RequestIntercepts runs the registered LLM request intercept chain on the // given request and returns the transformed request. This is a shorthand for -// [nemo_flow.LlmRequestIntercepts]. +// [nemo_relay.LlmRequestIntercepts]. func RequestIntercepts(name string, request json.RawMessage) (json.RawMessage, error) { - return nemo_flow.LlmRequestIntercepts(name, request) + return nemo_relay.LlmRequestIntercepts(name, request) } // ConditionalExecution runs the registered LLM conditional execution guardrail // chain. Returns nil if all guardrails pass, or an error with the rejection // reason if blocked. The request should be in LLMRequest JSON format // ({"headers": {...}, "content": {...}}). This is a shorthand for -// [nemo_flow.LlmConditionalExecution]. +// [nemo_relay.LlmConditionalExecution]. func ConditionalExecution(request json.RawMessage) error { - return nemo_flow.LlmConditionalExecution(request) + return nemo_relay.LlmConditionalExecution(request) } diff --git a/go/nemo_flow/llm/llm_shorthand_test.go b/go/nemo_relay/llm/llm_shorthand_test.go similarity index 87% rename from go/nemo_flow/llm/llm_shorthand_test.go rename to go/nemo_relay/llm/llm_shorthand_test.go index 0aee9a8dd..2be60eadc 100644 --- a/go/nemo_flow/llm/llm_shorthand_test.go +++ b/go/nemo_relay/llm/llm_shorthand_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - llmpkg "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/llm" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + llmpkg "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/llm" ) func makeRequest() map[string]interface{} { @@ -44,7 +44,7 @@ func assertLLMExecuteResult(t *testing.T) { func assertLLMRequestInterceptShorthand(t *testing.T) { t.Helper() - if err := nemo_flow.RegisterLlmRequestIntercept("llm_req_int", 1, false, + if err := nemo_relay.RegisterLlmRequestIntercept("llm_req_int", 1, false, func(name string, headers, content, annotated json.RawMessage) (json.RawMessage, json.RawMessage, json.RawMessage, error) { var payload map[string]interface{} _ = json.Unmarshal(content, &payload) @@ -56,7 +56,7 @@ func assertLLMRequestInterceptShorthand(t *testing.T) { t.Fatalf("RegisterLlmRequestIntercept failed: %v", err) } t.Cleanup(func() { - _ = nemo_flow.DeregisterLlmRequestIntercept("llm_req_int") + _ = nemo_relay.DeregisterLlmRequestIntercept("llm_req_int") }) request, err := llmpkg.RequestIntercepts("llm_req", json.RawMessage(`{"headers":{},"content":{"model":"test-model"}}`)) @@ -78,13 +78,13 @@ func assertLLMRequestInterceptShorthand(t *testing.T) { func assertLLMConditionalShorthand(t *testing.T) { t.Helper() - if err := nemo_flow.RegisterLlmConditionalExecutionGuardrail("llm_cond", 1, + if err := nemo_relay.RegisterLlmConditionalExecutionGuardrail("llm_cond", 1, func(headers, content json.RawMessage) *string { return nil }, ); err != nil { t.Fatalf("RegisterLlmConditionalExecutionGuardrail failed: %v", err) } t.Cleanup(func() { - _ = nemo_flow.DeregisterLlmConditionalExecutionGuardrail("llm_cond") + _ = nemo_relay.DeregisterLlmConditionalExecutionGuardrail("llm_cond") }) if err := llmpkg.ConditionalExecution(json.RawMessage(`{"headers":{},"content":{"model":"test-model"}}`)); err != nil { @@ -92,7 +92,7 @@ func assertLLMConditionalShorthand(t *testing.T) { } } -func drainShorthandStream(t *testing.T, stream *nemo_flow.LlmStream) { +func drainShorthandStream(t *testing.T, stream *nemo_relay.LlmStream) { t.Helper() for { diff --git a/go/nemo_flow/llm_test.go b/go/nemo_relay/llm_test.go similarity index 99% rename from go/nemo_flow/llm_test.go rename to go/nemo_relay/llm_test.go index 1a8f67093..b787c3d89 100644 --- a/go/nemo_flow/llm_test.go +++ b/go/nemo_relay/llm_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/nemo_flow.go b/go/nemo_relay/nemo_relay.go similarity index 74% rename from go/nemo_flow/nemo_flow.go rename to go/nemo_relay/nemo_relay.go index 2135ef089..aa5f1a94f 100644 --- a/go/nemo_flow/nemo_flow.go +++ b/go/nemo_relay/nemo_relay.go @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package nemo_flow provides Go bindings for the NeMo Flow agent runtime via CGo. +// Package nemo_relay provides Go bindings for the NeMo Relay agent runtime via CGo. // -// NeMo Flow is a multi-language agent runtime framework that provides execution +// NeMo Relay is a multi-language agent runtime framework that provides execution // scope management, lifecycle events, and middleware (guardrails and intercepts) // for tool and LLM calls. The core runtime is written in Rust; this package -// wraps the C FFI layer produced by the nemo-flow-ffi crate. +// wraps the C FFI layer produced by the nemo-relay-ffi crate. // // The package exposes a hierarchical scope stack, tool and LLM call lifecycle // management, priority-ordered guardrails for request/response sanitization and @@ -17,13 +17,13 @@ // Sub-packages scope, tools, llm, guardrails, intercepts, and subscribers // re-export the most common functions under shorter names for convenience. // -// Build prerequisites: the nemo-flow-ffi library must be built first -// (cargo build --release -p nemo-flow-ffi). The package searches the +// Build prerequisites: the nemo-relay-ffi library must be built first +// (cargo build --release -p nemo-relay-ffi). The package searches the // repo-local Cargo target directories automatically. -package nemo_flow +package nemo_relay /* -#cgo LDFLAGS: -L${SRCDIR}/../../target/release -L${SRCDIR}/../../target/debug -lnemo_flow_ffi +#cgo LDFLAGS: -L${SRCDIR}/../../target/release -L${SRCDIR}/../../target/debug -lnemo_relay_ffi #cgo windows LDFLAGS: -luserenv -lntdll -lws2_32 -ladvapi32 -lbcrypt #include #include @@ -39,216 +39,216 @@ typedef struct FfiEvent FfiEvent; typedef struct FfiStream FfiStream; typedef struct FfiCodecHandle FfiCodecHandle; -typedef void (*NemoFlowFreeFn)(void* user_data); +typedef void (*NemoRelayFreeFn)(void* user_data); // Core API -extern int32_t nemo_flow_get_handle(FfiScopeHandle** out); -extern int32_t nemo_flow_push_scope(const char* name, int32_t scope_type, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* input_json, const int64_t* timestamp_unix_micros, FfiScopeHandle** out); -extern int32_t nemo_flow_pop_scope(const FfiScopeHandle* handle, const char* output_json, const int64_t* timestamp_unix_micros); -extern int32_t nemo_flow_event(const char* name, const FfiScopeHandle* parent, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); +extern int32_t nemo_relay_get_handle(FfiScopeHandle** out); +extern int32_t nemo_relay_push_scope(const char* name, int32_t scope_type, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* input_json, const int64_t* timestamp_unix_micros, FfiScopeHandle** out); +extern int32_t nemo_relay_pop_scope(const FfiScopeHandle* handle, const char* output_json, const int64_t* timestamp_unix_micros); +extern int32_t nemo_relay_event(const char* name, const FfiScopeHandle* parent, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); // Tool lifecycle -extern int32_t nemo_flow_tool_call(const char* name, const char* args_json, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* tool_call_id, const int64_t* timestamp_unix_micros, FfiToolHandle** out); -extern int32_t nemo_flow_tool_call_end(const FfiToolHandle* handle, const char* result_json, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); +extern int32_t nemo_relay_tool_call(const char* name, const char* args_json, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* tool_call_id, const int64_t* timestamp_unix_micros, FfiToolHandle** out); +extern int32_t nemo_relay_tool_call_end(const FfiToolHandle* handle, const char* result_json, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); // Tool call execute (with C function pointer callbacks) -typedef char* (*NemoFlowToolExecFn)(void* user_data, const char* args_json); -extern int32_t nemo_flow_tool_call_execute( +typedef char* (*NemoRelayToolExecFn)(void* user_data, const char* args_json); +extern int32_t nemo_relay_tool_call_execute( const char* name, const char* args_json, - NemoFlowToolExecFn func_cb, void* func_user_data, NemoFlowFreeFn func_free, + NemoRelayToolExecFn func_cb, void* func_user_data, NemoRelayFreeFn func_free, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, char** out); // LLM lifecycle -typedef void (*NemoFlowCollectorCb)(const char* chunk_json); -typedef struct Option_NemoFlowCollectorCb { NemoFlowCollectorCb cb; } Option_NemoFlowCollectorCb; -typedef char* (*NemoFlowFinalizerCb)(); -typedef struct Option_NemoFlowFinalizerCb { NemoFlowFinalizerCb cb; } Option_NemoFlowFinalizerCb; +typedef void (*NemoRelayCollectorCb)(const char* chunk_json); +typedef struct Option_NemoRelayCollectorCb { NemoRelayCollectorCb cb; } Option_NemoRelayCollectorCb; +typedef char* (*NemoRelayFinalizerCb)(); +typedef struct Option_NemoRelayFinalizerCb { NemoRelayFinalizerCb cb; } Option_NemoRelayFinalizerCb; -static inline Option_NemoFlowCollectorCb makeOptCollectorCb(NemoFlowCollectorCb cb) { - Option_NemoFlowCollectorCb opt = { cb }; +static inline Option_NemoRelayCollectorCb makeOptCollectorCb(NemoRelayCollectorCb cb) { + Option_NemoRelayCollectorCb opt = { cb }; return opt; } -static inline Option_NemoFlowFinalizerCb makeOptFinalizerCb(NemoFlowFinalizerCb cb) { - Option_NemoFlowFinalizerCb opt = { cb }; +static inline Option_NemoRelayFinalizerCb makeOptFinalizerCb(NemoRelayFinalizerCb cb) { + Option_NemoRelayFinalizerCb opt = { cb }; return opt; } -extern int32_t nemo_flow_llm_call(const char* name, const char* native_json, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* model_name, const int64_t* timestamp_unix_micros, FfiLLMHandle** out); -extern int32_t nemo_flow_llm_call_end(const FfiLLMHandle* handle, const char* response_json, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); +extern int32_t nemo_relay_llm_call(const char* name, const char* native_json, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* model_name, const int64_t* timestamp_unix_micros, FfiLLMHandle** out); +extern int32_t nemo_relay_llm_call_end(const FfiLLMHandle* handle, const char* response_json, const char* data_json, const char* metadata_json, const int64_t* timestamp_unix_micros); // LLM call execute -typedef char* (*NemoFlowLlmExecFn)(void* user_data, const char* native_json); -typedef char* (*NemoFlowCodecDecodeFn)(void* user_data, const FfiLLMRequest* request); -typedef char* (*NemoFlowCodecEncodeFn)(void* user_data, const char* annotated_json, const FfiLLMRequest* original_request); -extern int32_t nemo_flow_llm_call_execute( +typedef char* (*NemoRelayLlmExecFn)(void* user_data, const char* native_json); +typedef char* (*NemoRelayCodecDecodeFn)(void* user_data, const FfiLLMRequest* request); +typedef char* (*NemoRelayCodecEncodeFn)(void* user_data, const char* annotated_json, const FfiLLMRequest* original_request); +extern int32_t nemo_relay_llm_call_execute( const char* name, const char* native_json, - NemoFlowLlmExecFn func_cb, void* func_user_data, NemoFlowFreeFn func_free, + NemoRelayLlmExecFn func_cb, void* func_user_data, NemoRelayFreeFn func_free, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* model_name, - NemoFlowCodecDecodeFn codec_decode, NemoFlowCodecEncodeFn codec_encode, - void* codec_user_data, NemoFlowFreeFn codec_free_fn, + NemoRelayCodecDecodeFn codec_decode, NemoRelayCodecEncodeFn codec_encode, + void* codec_user_data, NemoRelayFreeFn codec_free_fn, const FfiCodecHandle* response_codec, char** out); // LLM stream execute -extern int32_t nemo_flow_llm_stream_call_execute( +extern int32_t nemo_relay_llm_stream_call_execute( const char* name, const char* native_json, - NemoFlowLlmExecFn func_cb, void* func_user_data, NemoFlowFreeFn func_free, - Option_NemoFlowCollectorCb collector, Option_NemoFlowFinalizerCb finalizer, + NemoRelayLlmExecFn func_cb, void* func_user_data, NemoRelayFreeFn func_free, + Option_NemoRelayCollectorCb collector, Option_NemoRelayFinalizerCb finalizer, const FfiScopeHandle* parent, uint32_t attributes, const char* data_json, const char* metadata_json, const char* model_name, - NemoFlowCodecDecodeFn codec_decode, NemoFlowCodecEncodeFn codec_encode, - void* codec_user_data, NemoFlowFreeFn codec_free_fn, + NemoRelayCodecDecodeFn codec_decode, NemoRelayCodecEncodeFn codec_encode, + void* codec_user_data, NemoRelayFreeFn codec_free_fn, const FfiCodecHandle* response_codec, FfiStream** out); // Built-in codec constructors -extern FfiCodecHandle* nemo_flow_openai_chat_codec_new(void); -extern FfiCodecHandle* nemo_flow_openai_responses_codec_new(void); -extern FfiCodecHandle* nemo_flow_anthropic_messages_codec_new(void); -extern void nemo_flow_codec_free(FfiCodecHandle* handle); +extern FfiCodecHandle* nemo_relay_openai_chat_codec_new(void); +extern FfiCodecHandle* nemo_relay_openai_responses_codec_new(void); +extern FfiCodecHandle* nemo_relay_anthropic_messages_codec_new(void); +extern void nemo_relay_codec_free(FfiCodecHandle* handle); -extern void nemo_flow_set_last_error_message(const char* msg); +extern void nemo_relay_set_last_error_message(const char* msg); // Tool guardrails -typedef char* (*NemoFlowToolSanitizeFn)(void* user_data, const char* name, const char* args_json); -extern int32_t nemo_flow_register_tool_sanitize_request_guardrail(const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_tool_sanitize_request_guardrail(const char* name); -extern int32_t nemo_flow_register_tool_sanitize_response_guardrail(const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_tool_sanitize_response_guardrail(const char* name); +typedef char* (*NemoRelayToolSanitizeFn)(void* user_data, const char* name, const char* args_json); +extern int32_t nemo_relay_register_tool_sanitize_request_guardrail(const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_tool_sanitize_request_guardrail(const char* name); +extern int32_t nemo_relay_register_tool_sanitize_response_guardrail(const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_tool_sanitize_response_guardrail(const char* name); -typedef char* (*NemoFlowToolConditionalFn)(void* user_data, const char* name, const char* args_json); -extern int32_t nemo_flow_register_tool_conditional_execution_guardrail(const char* name, int32_t priority, NemoFlowToolConditionalFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_tool_conditional_execution_guardrail(const char* name); +typedef char* (*NemoRelayToolConditionalFn)(void* user_data, const char* name, const char* args_json); +extern int32_t nemo_relay_register_tool_conditional_execution_guardrail(const char* name, int32_t priority, NemoRelayToolConditionalFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_tool_conditional_execution_guardrail(const char* name); // Tool intercepts -extern int32_t nemo_flow_register_tool_request_intercept(const char* name, int32_t priority, _Bool break_chain, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_tool_request_intercept(const char* name); +extern int32_t nemo_relay_register_tool_request_intercept(const char* name, int32_t priority, _Bool break_chain, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_tool_request_intercept(const char* name); // Middleware chain intercept callback types (must be declared before use in externs) -typedef char* (*NemoFlowToolExecNextFn)(const char* args_json, void* next_ctx); -typedef char* (*NemoFlowToolExecInterceptCb)(void* user_data, const char* args_json, NemoFlowToolExecNextFn next_fn, void* next_ctx); -extern int32_t nemo_flow_register_tool_execution_intercept(const char* name, int32_t priority, NemoFlowToolExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_deregister_tool_execution_intercept(const char* name); +typedef char* (*NemoRelayToolExecNextFn)(const char* args_json, void* next_ctx); +typedef char* (*NemoRelayToolExecInterceptCb)(void* user_data, const char* args_json, NemoRelayToolExecNextFn next_fn, void* next_ctx); +extern int32_t nemo_relay_register_tool_execution_intercept(const char* name, int32_t priority, NemoRelayToolExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_deregister_tool_execution_intercept(const char* name); // LLM guardrails -typedef FfiLLMRequest* (*NemoFlowLlmRequestCb)(void* user_data, const FfiLLMRequest* request); -extern int32_t nemo_flow_register_llm_sanitize_request_guardrail(const char* name, int32_t priority, NemoFlowLlmRequestCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_llm_sanitize_request_guardrail(const char* name); +typedef FfiLLMRequest* (*NemoRelayLlmRequestCb)(void* user_data, const FfiLLMRequest* request); +extern int32_t nemo_relay_register_llm_sanitize_request_guardrail(const char* name, int32_t priority, NemoRelayLlmRequestCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_llm_sanitize_request_guardrail(const char* name); -typedef char* (*NemoFlowLlmResponseFn)(void* user_data, const char* response_json); -extern int32_t nemo_flow_register_llm_sanitize_response_guardrail(const char* name, int32_t priority, NemoFlowLlmResponseFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_llm_sanitize_response_guardrail(const char* name); +typedef char* (*NemoRelayLlmResponseFn)(void* user_data, const char* response_json); +extern int32_t nemo_relay_register_llm_sanitize_response_guardrail(const char* name, int32_t priority, NemoRelayLlmResponseFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_llm_sanitize_response_guardrail(const char* name); -typedef char* (*NemoFlowLlmConditionalCb)(void* user_data, const FfiLLMRequest* request); -extern int32_t nemo_flow_register_llm_conditional_execution_guardrail(const char* name, int32_t priority, NemoFlowLlmConditionalCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_llm_conditional_execution_guardrail(const char* name); +typedef char* (*NemoRelayLlmConditionalCb)(void* user_data, const FfiLLMRequest* request); +extern int32_t nemo_relay_register_llm_conditional_execution_guardrail(const char* name, int32_t priority, NemoRelayLlmConditionalCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_llm_conditional_execution_guardrail(const char* name); // LLM intercepts -typedef int32_t (*NemoFlowLlmRequestInterceptCb)(void* user_data, const char* name, const FfiLLMRequest* request, const char* annotated_json, FfiLLMRequest** out_request, char** out_annotated_json); -extern int32_t nemo_flow_register_llm_request_intercept(const char* name, int32_t priority, _Bool break_chain, NemoFlowLlmRequestInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_llm_request_intercept(const char* name); -typedef char* (*NemoFlowLlmExecNextFn)(const char* native_json, void* next_ctx); -typedef char* (*NemoFlowLlmExecInterceptCb)(void* user_data, const char* native_json, NemoFlowLlmExecNextFn next_fn, void* next_ctx); +typedef int32_t (*NemoRelayLlmRequestInterceptCb)(void* user_data, const char* name, const FfiLLMRequest* request, const char* annotated_json, FfiLLMRequest** out_request, char** out_annotated_json); +extern int32_t nemo_relay_register_llm_request_intercept(const char* name, int32_t priority, _Bool break_chain, NemoRelayLlmRequestInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_llm_request_intercept(const char* name); +typedef char* (*NemoRelayLlmExecNextFn)(const char* native_json, void* next_ctx); +typedef char* (*NemoRelayLlmExecInterceptCb)(void* user_data, const char* native_json, NemoRelayLlmExecNextFn next_fn, void* next_ctx); -extern int32_t nemo_flow_register_llm_execution_intercept(const char* name, int32_t priority, NemoFlowLlmExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_deregister_llm_execution_intercept(const char* name); -extern int32_t nemo_flow_register_llm_stream_execution_intercept(const char* name, int32_t priority, NemoFlowLlmExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_deregister_llm_stream_execution_intercept(const char* name); +extern int32_t nemo_relay_register_llm_execution_intercept(const char* name, int32_t priority, NemoRelayLlmExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_deregister_llm_execution_intercept(const char* name); +extern int32_t nemo_relay_register_llm_stream_execution_intercept(const char* name, int32_t priority, NemoRelayLlmExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_deregister_llm_stream_execution_intercept(const char* name); // Subscribers -typedef void (*NemoFlowEventSubscriberFn)(void* user_data, const FfiEvent* event); -extern int32_t nemo_flow_register_subscriber(const char* name, NemoFlowEventSubscriberFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_subscriber(const char* name); +typedef void (*NemoRelayEventSubscriberFn)(void* user_data, const FfiEvent* event); +extern int32_t nemo_relay_register_subscriber(const char* name, NemoRelayEventSubscriberFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_subscriber(const char* name); // Scope-local tool guardrails -extern int32_t nemo_flow_scope_register_tool_sanitize_request_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_tool_sanitize_request_guardrail(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_tool_sanitize_response_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_tool_sanitize_response_guardrail(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_tool_conditional_execution_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowToolConditionalFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_tool_conditional_execution_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_tool_sanitize_request_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_tool_sanitize_request_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_tool_sanitize_response_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_tool_sanitize_response_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_tool_conditional_execution_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayToolConditionalFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_tool_conditional_execution_guardrail(const char* scope_uuid, const char* name); // Scope-local tool intercepts -extern int32_t nemo_flow_scope_register_tool_request_intercept(const char* scope_uuid, const char* name, int32_t priority, _Bool break_chain, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_tool_request_intercept(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_tool_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoFlowToolExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_scope_deregister_tool_execution_intercept(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_tool_request_intercept(const char* scope_uuid, const char* name, int32_t priority, _Bool break_chain, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_tool_request_intercept(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_tool_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoRelayToolExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_scope_deregister_tool_execution_intercept(const char* scope_uuid, const char* name); // Scope-local LLM guardrails -extern int32_t nemo_flow_scope_register_llm_sanitize_request_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowLlmRequestCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_llm_sanitize_request_guardrail(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_llm_sanitize_response_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowLlmResponseFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_llm_sanitize_response_guardrail(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_llm_conditional_execution_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoFlowLlmConditionalCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_llm_conditional_execution_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_sanitize_request_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayLlmRequestCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_llm_sanitize_request_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_sanitize_response_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayLlmResponseFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_llm_sanitize_response_guardrail(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_conditional_execution_guardrail(const char* scope_uuid, const char* name, int32_t priority, NemoRelayLlmConditionalCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_llm_conditional_execution_guardrail(const char* scope_uuid, const char* name); // Scope-local LLM intercepts -extern int32_t nemo_flow_scope_register_llm_request_intercept(const char* scope_uuid, const char* name, int32_t priority, _Bool break_chain, NemoFlowLlmRequestInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_llm_request_intercept(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_llm_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoFlowLlmExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_scope_deregister_llm_execution_intercept(const char* scope_uuid, const char* name); -extern int32_t nemo_flow_scope_register_llm_stream_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoFlowLlmExecInterceptCb exec_cb, void* exec_user_data, NemoFlowFreeFn exec_free); -extern int32_t nemo_flow_scope_deregister_llm_stream_execution_intercept(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_request_intercept(const char* scope_uuid, const char* name, int32_t priority, _Bool break_chain, NemoRelayLlmRequestInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_llm_request_intercept(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoRelayLlmExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_scope_deregister_llm_execution_intercept(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_llm_stream_execution_intercept(const char* scope_uuid, const char* name, int32_t priority, NemoRelayLlmExecInterceptCb exec_cb, void* exec_user_data, NemoRelayFreeFn exec_free); +extern int32_t nemo_relay_scope_deregister_llm_stream_execution_intercept(const char* scope_uuid, const char* name); // Scope-local subscribers -extern int32_t nemo_flow_scope_register_subscriber(const char* scope_uuid, const char* name, NemoFlowEventSubscriberFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_scope_deregister_subscriber(const char* scope_uuid, const char* name); +extern int32_t nemo_relay_scope_register_subscriber(const char* scope_uuid, const char* name, NemoRelayEventSubscriberFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_scope_deregister_subscriber(const char* scope_uuid, const char* name); // Standalone middleware chains -extern int32_t nemo_flow_tool_request_intercepts(const char* name, const char* args_json, char** out); -extern int32_t nemo_flow_tool_conditional_execution(const char* name, const char* args_json); -extern int32_t nemo_flow_llm_request_intercepts(const char* name, const char* request_json, char** out); -extern int32_t nemo_flow_llm_conditional_execution(const char* request_json); +extern int32_t nemo_relay_tool_request_intercepts(const char* name, const char* args_json, char** out); +extern int32_t nemo_relay_tool_conditional_execution(const char* name, const char* args_json); +extern int32_t nemo_relay_llm_request_intercepts(const char* name, const char* request_json, char** out); +extern int32_t nemo_relay_llm_conditional_execution(const char* request_json); // Error -extern const char* nemo_flow_last_error(); +extern const char* nemo_relay_last_error(); // String free -extern void nemo_flow_string_free(char* ptr); +extern void nemo_relay_string_free(char* ptr); // Scope stack isolation -extern int32_t nemo_flow_scope_stack_create(FfiScopeStack** out); -extern int32_t nemo_flow_scope_stack_set_thread(const FfiScopeStack* stack); -extern int32_t nemo_flow_scope_stack_capture_thread(FfiThreadScopeStackBinding** out); -extern int32_t nemo_flow_scope_stack_restore_thread(FfiThreadScopeStackBinding* binding); -extern _Bool nemo_flow_scope_stack_active(void); -extern void nemo_flow_scope_stack_free(FfiScopeStack* ptr); +extern int32_t nemo_relay_scope_stack_create(FfiScopeStack** out); +extern int32_t nemo_relay_scope_stack_set_thread(const FfiScopeStack* stack); +extern int32_t nemo_relay_scope_stack_capture_thread(FfiThreadScopeStackBinding** out); +extern int32_t nemo_relay_scope_stack_restore_thread(FfiThreadScopeStackBinding* binding); +extern _Bool nemo_relay_scope_stack_active(void); +extern void nemo_relay_scope_stack_free(FfiScopeStack* ptr); // ATIF exporter -extern int32_t nemo_flow_atif_exporter_create(const char*, const char*, const char*, const char*, void**); -extern int32_t nemo_flow_atif_exporter_register(const void*, const char*); -extern int32_t nemo_flow_atif_exporter_deregister(const char*); -extern int32_t nemo_flow_atif_exporter_export(const void*, char**); -extern int32_t nemo_flow_atif_exporter_clear(const void*); -extern void nemo_flow_atif_exporter_free(void*); +extern int32_t nemo_relay_atif_exporter_create(const char*, const char*, const char*, const char*, void**); +extern int32_t nemo_relay_atif_exporter_register(const void*, const char*); +extern int32_t nemo_relay_atif_exporter_deregister(const char*); +extern int32_t nemo_relay_atif_exporter_export(const void*, char**); +extern int32_t nemo_relay_atif_exporter_clear(const void*); +extern void nemo_relay_atif_exporter_free(void*); // ATOF JSONL exporter -extern int32_t nemo_flow_atof_exporter_create(const char*, const char*, const char*, void**); -extern int32_t nemo_flow_atof_exporter_register(const void*, const char*); -extern int32_t nemo_flow_atof_exporter_deregister(const char*); -extern int32_t nemo_flow_atof_exporter_force_flush(const void*); -extern int32_t nemo_flow_atof_exporter_shutdown(const void*); -extern int32_t nemo_flow_atof_exporter_path(const void*, char**); -extern void nemo_flow_atof_exporter_free(void*); +extern int32_t nemo_relay_atof_exporter_create(const char*, const char*, const char*, void**); +extern int32_t nemo_relay_atof_exporter_register(const void*, const char*); +extern int32_t nemo_relay_atof_exporter_deregister(const char*); +extern int32_t nemo_relay_atof_exporter_force_flush(const void*); +extern int32_t nemo_relay_atof_exporter_shutdown(const void*); +extern int32_t nemo_relay_atof_exporter_path(const void*, char**); +extern void nemo_relay_atof_exporter_free(void*); // OpenTelemetry subscriber -extern int32_t nemo_flow_otel_subscriber_create(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, uint64_t, void**); -extern int32_t nemo_flow_otel_subscriber_register(const void*, const char*); -extern int32_t nemo_flow_otel_subscriber_deregister(const char*); -extern int32_t nemo_flow_otel_subscriber_force_flush(const void*); -extern int32_t nemo_flow_otel_subscriber_shutdown(const void*); -extern void nemo_flow_otel_subscriber_free(void*); +extern int32_t nemo_relay_otel_subscriber_create(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, uint64_t, void**); +extern int32_t nemo_relay_otel_subscriber_register(const void*, const char*); +extern int32_t nemo_relay_otel_subscriber_deregister(const char*); +extern int32_t nemo_relay_otel_subscriber_force_flush(const void*); +extern int32_t nemo_relay_otel_subscriber_shutdown(const void*); +extern void nemo_relay_otel_subscriber_free(void*); // OpenInference subscriber -extern int32_t nemo_flow_openinference_subscriber_create(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, uint64_t, void**); -extern int32_t nemo_flow_openinference_subscriber_register(const void*, const char*); -extern int32_t nemo_flow_openinference_subscriber_deregister(const char*); -extern int32_t nemo_flow_openinference_subscriber_force_flush(const void*); -extern int32_t nemo_flow_openinference_subscriber_shutdown(const void*); -extern void nemo_flow_openinference_subscriber_free(void*); +extern int32_t nemo_relay_openinference_subscriber_create(const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, uint64_t, void**); +extern int32_t nemo_relay_openinference_subscriber_register(const void*, const char*); +extern int32_t nemo_relay_openinference_subscriber_deregister(const char*); +extern int32_t nemo_relay_openinference_subscriber_force_flush(const void*); +extern int32_t nemo_relay_openinference_subscriber_shutdown(const void*); +extern void nemo_relay_openinference_subscriber_free(void*); // Go trampoline forward declarations (defined via //export in callbacks.go) extern char* goToolSanitizeTrampoline(void*, const char*, const char*); @@ -260,8 +260,8 @@ extern FfiLLMRequest* goLlmRequestTrampoline(void*, const FfiLLMRequest*); extern char* goLlmResponseTrampoline(void*, const char*); extern char* goLlmConditionalTrampoline(void*, const FfiLLMRequest*); extern char* goLlmExecTrampoline(void*, const char*); -extern char* goToolExecInterceptTrampoline(void*, const char*, NemoFlowToolExecNextFn, void*); -extern char* goLlmExecInterceptTrampoline(void*, const char*, NemoFlowLlmExecNextFn, void*); +extern char* goToolExecInterceptTrampoline(void*, const char*, NemoRelayToolExecNextFn, void*); +extern char* goLlmExecInterceptTrampoline(void*, const char*, NemoRelayLlmExecNextFn, void*); // Codec trampolines (used at execute time, not registration) extern char* goCodecDecodeTrampoline(void*, const FfiLLMRequest*); @@ -279,7 +279,7 @@ import ( "unsafe" ) -const defaultServiceName = "nemo-flow" +const defaultServiceName = "nemo-relay" func checkedValue[T any](status int32, value T) (T, error) { if err := checkStatus(C.int32_t(status)); err != nil { @@ -292,12 +292,12 @@ func checkedValue[T any](status int32, value T) (T, error) { var ( getHandleFunc = func() (*ScopeHandle, error) { var out *C.FfiScopeHandle - status := C.nemo_flow_get_handle(&out) + status := C.nemo_relay_get_handle(&out) return checkedValue(int32(status), newScopeHandle(out)) } newScopeStackFunc = func() (*ScopeStack, error) { var ptr *C.FfiScopeStack - status := C.nemo_flow_scope_stack_create(&ptr) + status := C.nemo_relay_scope_stack_create(&ptr) return checkedValue(int32(status), &ScopeStack{ptr: ptr}) } newAtifExporterFunc = func(sessionID, agentName, agentVersion, modelName string) (*AtifExporter, error) { @@ -315,7 +315,7 @@ var ( } var ptr unsafe.Pointer - status := C.nemo_flow_atif_exporter_create(cSessionID, cAgentName, cAgentVersion, cModelName, &ptr) + status := C.nemo_relay_atif_exporter_create(cSessionID, cAgentName, cAgentVersion, cModelName, &ptr) return checkedValue(int32(status), &AtifExporter{ptr: ptr}) } newAtofExporterFunc = func(config AtofExporterConfig) (*AtofExporter, error) { @@ -339,7 +339,7 @@ var ( } var ptr unsafe.Pointer - status := C.nemo_flow_atof_exporter_create(cOutputDirectory, cMode, cFilename, &ptr) + status := C.nemo_relay_atof_exporter_create(cOutputDirectory, cMode, cFilename, &ptr) return checkedValue(int32(status), &AtofExporter{ptr: ptr}) } ) @@ -349,9 +349,9 @@ var ( // --------------------------------------------------------------------------- func lastError() error { - msg := C.nemo_flow_last_error() + msg := C.nemo_relay_last_error() if msg == nil { - return errors.New("unknown nemo_flow error") + return errors.New("unknown nemo_relay error") } return errors.New(C.GoString(msg)) } @@ -515,7 +515,7 @@ func PushScope(name string, scopeType ScopeType, opts ...ScopeOption) (*ScopeHan } var out *C.FfiScopeHandle - status := C.nemo_flow_push_scope(cName, C.int32_t(scopeType), o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.input, o.timestamp, &out) + status := C.nemo_relay_push_scope(cName, C.int32_t(scopeType), o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.input, o.timestamp, &out) if err := checkStatus(status); err != nil { return nil, err } @@ -538,7 +538,7 @@ func PopScope(handle *ScopeHandle, opts ...ScopeEndOption) error { if o.timestamp != nil { defer C.free(unsafe.Pointer(o.timestamp)) } - return checkStatus(C.nemo_flow_pop_scope(handle.ptr, o.output, o.timestamp)) + return checkStatus(C.nemo_relay_pop_scope(handle.ptr, o.output, o.timestamp)) } // --------------------------------------------------------------------------- @@ -617,7 +617,7 @@ func EmitEvent(name string, opts ...EventOption) error { defer C.free(unsafe.Pointer(o.timestamp)) } - return checkStatus(C.nemo_flow_event(cName, o.parent, o.data, o.metadata, o.timestamp)) + return checkStatus(C.nemo_relay_event(cName, o.parent, o.data, o.metadata, o.timestamp)) } // --------------------------------------------------------------------------- @@ -734,7 +734,7 @@ func ToolCall(name string, args json.RawMessage, opts ...ToolCallOption) (*ToolH defer C.free(unsafe.Pointer(cArgs)) var out *C.FfiToolHandle - status := C.nemo_flow_tool_call(cName, cArgs, o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.toolCallID, o.timestamp, &out) + status := C.nemo_relay_tool_call(cName, cArgs, o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.toolCallID, o.timestamp, &out) if err := checkStatus(status); err != nil { return nil, err } @@ -757,7 +757,7 @@ func ToolCallEnd(handle *ToolHandle, result json.RawMessage, opts ...ToolCallOpt cResult := C.CString(string(result)) defer C.free(unsafe.Pointer(cResult)) - return checkStatus(C.nemo_flow_tool_call_end(handle.ptr, cResult, o.data, o.metadata, o.timestamp)) + return checkStatus(C.nemo_relay_tool_call_end(handle.ptr, cResult, o.data, o.metadata, o.timestamp)) } // ToolCallExecute runs a complete tool call lifecycle through the full @@ -784,11 +784,11 @@ func ToolCallExecute(name string, args json.RawMessage, fn ToolExecutionFunc, op defer C.free(unsafe.Pointer(cArgs)) var out *C.char - status := C.nemo_flow_tool_call_execute( + status := C.nemo_relay_tool_call_execute( cName, cArgs, - C.NemoFlowToolExecFn(C.goToolExecTrampoline), + C.NemoRelayToolExecFn(C.goToolExecTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), o.parent, C.uint32_t(o.attributes), o.data, o.metadata, &out, @@ -797,7 +797,7 @@ func ToolCallExecute(name string, args json.RawMessage, fn ToolExecutionFunc, op return nil, err } result := json.RawMessage(C.GoString(out)) - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) return result, nil } @@ -812,10 +812,10 @@ type llmCallOptions struct { metadata *C.char modelName *C.char timestamp *C.int64_t - codecDecode C.NemoFlowCodecDecodeFn - codecEncode C.NemoFlowCodecEncodeFn + codecDecode C.NemoRelayCodecDecodeFn + codecEncode C.NemoRelayCodecEncodeFn codecUserData unsafe.Pointer - codecFreeFn C.NemoFlowFreeFn + codecFreeFn C.NemoRelayFreeFn responseCodec *C.FfiCodecHandle responseCodecHandle *CodecHandle // prevents GC of the CodecHandle during FFI calls } @@ -880,10 +880,10 @@ func WithLLMModelName(name string) LLMCallOption { func WithLLMCodec(codec CodecFunc) LLMCallOption { return func(o *llmCallOptions) { id := registerClosure(&codec) - o.codecDecode = C.NemoFlowCodecDecodeFn(C.goCodecDecodeTrampoline) - o.codecEncode = C.NemoFlowCodecEncodeFn(C.goCodecEncodeTrampoline) + o.codecDecode = C.NemoRelayCodecDecodeFn(C.goCodecDecodeTrampoline) + o.codecEncode = C.NemoRelayCodecEncodeFn(C.goCodecEncodeTrampoline) o.codecUserData = id - o.codecFreeFn = C.NemoFlowFreeFn(C.goFreeTrampoline) + o.codecFreeFn = C.NemoRelayFreeFn(C.goFreeTrampoline) } } @@ -902,10 +902,10 @@ type CodecHandle struct { // [WithLLMResponseCodec] to enable structured request and response handling for // OpenAI Chat payloads. func NewOpenAIChatCodec() *CodecHandle { - h := &CodecHandle{ptr: C.nemo_flow_openai_chat_codec_new()} + h := &CodecHandle{ptr: C.nemo_relay_openai_chat_codec_new()} runtime.SetFinalizer(h, func(h *CodecHandle) { if h.ptr != nil { - C.nemo_flow_codec_free(h.ptr) + C.nemo_relay_codec_free(h.ptr) h.ptr = nil } }) @@ -918,10 +918,10 @@ func NewOpenAIChatCodec() *CodecHandle { // [WithLLMResponseCodec] to enable structured request and response handling for // OpenAI Responses payloads. func NewOpenAIResponsesCodec() *CodecHandle { - h := &CodecHandle{ptr: C.nemo_flow_openai_responses_codec_new()} + h := &CodecHandle{ptr: C.nemo_relay_openai_responses_codec_new()} runtime.SetFinalizer(h, func(h *CodecHandle) { if h.ptr != nil { - C.nemo_flow_codec_free(h.ptr) + C.nemo_relay_codec_free(h.ptr) h.ptr = nil } }) @@ -934,10 +934,10 @@ func NewOpenAIResponsesCodec() *CodecHandle { // [WithLLMResponseCodec] to enable structured request and response handling for // Anthropic Messages payloads. func NewAnthropicMessagesCodec() *CodecHandle { - h := &CodecHandle{ptr: C.nemo_flow_anthropic_messages_codec_new()} + h := &CodecHandle{ptr: C.nemo_relay_anthropic_messages_codec_new()} runtime.SetFinalizer(h, func(h *CodecHandle) { if h.ptr != nil { - C.nemo_flow_codec_free(h.ptr) + C.nemo_relay_codec_free(h.ptr) h.ptr = nil } }) @@ -1015,7 +1015,7 @@ func LlmCall(name string, request interface{}, opts ...LLMCallOption) (*LLMHandl defer C.free(unsafe.Pointer(cRequest)) var out *C.FfiLLMHandle - status := C.nemo_flow_llm_call(cName, cRequest, o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.modelName, o.timestamp, &out) + status := C.nemo_relay_llm_call(cName, cRequest, o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.modelName, o.timestamp, &out) if err := checkStatus(status); err != nil { return nil, err } @@ -1038,7 +1038,7 @@ func LlmCallEnd(handle *LLMHandle, response json.RawMessage, opts ...LLMCallOpti cResponse := C.CString(string(response)) defer C.free(unsafe.Pointer(cResponse)) - return checkStatus(C.nemo_flow_llm_call_end(handle.ptr, cResponse, o.data, o.metadata, o.timestamp)) + return checkStatus(C.nemo_relay_llm_call_end(handle.ptr, cResponse, o.data, o.metadata, o.timestamp)) } // LlmCallExecute runs a complete LLM call lifecycle through the full @@ -1070,11 +1070,11 @@ func LlmCallExecute(name string, request interface{}, fn LLMExecutionFunc, opts defer C.free(unsafe.Pointer(cRequest)) var out *C.char - status := C.nemo_flow_llm_call_execute( + status := C.nemo_relay_llm_call_execute( cName, cRequest, - C.NemoFlowLlmExecFn(C.goLlmExecTrampoline), + C.NemoRelayLlmExecFn(C.goLlmExecTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), o.parent, C.uint32_t(o.attributes), o.data, o.metadata, o.modelName, @@ -1088,7 +1088,7 @@ func LlmCallExecute(name string, request interface{}, fn LLMExecutionFunc, opts return nil, err } result := json.RawMessage(C.GoString(out)) - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) return result, nil } @@ -1136,11 +1136,11 @@ func LlmStreamCallExecute(name string, request interface{}, fn LLMExecutionFunc, cFinalizer := C.makeOptFinalizerCb(nil) var out *C.FfiStream - status := C.nemo_flow_llm_stream_call_execute( + status := C.nemo_relay_llm_stream_call_execute( cName, cRequest, - C.NemoFlowLlmExecFn(C.goLlmExecTrampoline), + C.NemoRelayLlmExecFn(C.goLlmExecTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), cCollector, cFinalizer, o.parent, C.uint32_t(o.attributes), @@ -1172,11 +1172,11 @@ func RegisterToolSanitizeRequestGuardrail(name string, priority int32, fn ToolSa id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_tool_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_register_tool_sanitize_request_guardrail( cName, C.int32_t(priority), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1186,7 +1186,7 @@ func RegisterToolSanitizeRequestGuardrail(name string, priority int32, fn ToolSa func DeregisterToolSanitizeRequestGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_tool_sanitize_request_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_tool_sanitize_request_guardrail(cName)) } // RegisterToolSanitizeResponseGuardrail registers a guardrail that sanitizes @@ -1197,11 +1197,11 @@ func RegisterToolSanitizeResponseGuardrail(name string, priority int32, fn ToolS id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_tool_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_register_tool_sanitize_response_guardrail( cName, C.int32_t(priority), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1211,7 +1211,7 @@ func RegisterToolSanitizeResponseGuardrail(name string, priority int32, fn ToolS func DeregisterToolSanitizeResponseGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_tool_sanitize_response_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_tool_sanitize_response_guardrail(cName)) } // RegisterToolConditionalExecutionGuardrail registers a guardrail that @@ -1224,11 +1224,11 @@ func RegisterToolConditionalExecutionGuardrail(name string, priority int32, fn T id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_tool_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_register_tool_conditional_execution_guardrail( cName, C.int32_t(priority), - C.NemoFlowToolConditionalFn(C.goToolConditionalTrampoline), + C.NemoRelayToolConditionalFn(C.goToolConditionalTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1238,7 +1238,7 @@ func RegisterToolConditionalExecutionGuardrail(name string, priority int32, fn T func DeregisterToolConditionalExecutionGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_tool_conditional_execution_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_tool_conditional_execution_guardrail(cName)) } // RegisterToolRequestIntercept registers an intercept that transforms tool @@ -1250,11 +1250,11 @@ func RegisterToolRequestIntercept(name string, priority int32, breakChain bool, id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_tool_request_intercept( + return checkStatus(C.nemo_relay_register_tool_request_intercept( cName, C.int32_t(priority), C._Bool(breakChain), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1263,7 +1263,7 @@ func RegisterToolRequestIntercept(name string, priority int32, breakChain bool, func DeregisterToolRequestIntercept(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_tool_request_intercept(cName)) + return checkStatus(C.nemo_relay_deregister_tool_request_intercept(cName)) } // RegisterToolExecutionIntercept registers an execution intercept following @@ -1274,11 +1274,11 @@ func RegisterToolExecutionIntercept(name string, priority int32, execFn ToolExec execID := registerClosure(execFn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_tool_execution_intercept( + return checkStatus(C.nemo_relay_register_tool_execution_intercept( cName, C.int32_t(priority), - C.NemoFlowToolExecInterceptCb(C.goToolExecInterceptTrampoline), + C.NemoRelayToolExecInterceptCb(C.goToolExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1287,7 +1287,7 @@ func RegisterToolExecutionIntercept(name string, priority int32, execFn ToolExec func DeregisterToolExecutionIntercept(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_tool_execution_intercept(cName)) + return checkStatus(C.nemo_relay_deregister_tool_execution_intercept(cName)) } // --------------------------------------------------------------------------- @@ -1302,11 +1302,11 @@ func RegisterLlmSanitizeRequestGuardrail(name string, priority int32, fn LLMRequ id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_register_llm_sanitize_request_guardrail( cName, C.int32_t(priority), - C.NemoFlowLlmRequestCb(C.goLlmRequestTrampoline), + C.NemoRelayLlmRequestCb(C.goLlmRequestTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1315,7 +1315,7 @@ func RegisterLlmSanitizeRequestGuardrail(name string, priority int32, fn LLMRequ func DeregisterLlmSanitizeRequestGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_sanitize_request_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_llm_sanitize_request_guardrail(cName)) } // RegisterLlmSanitizeResponseGuardrail registers a guardrail that sanitizes @@ -1326,11 +1326,11 @@ func RegisterLlmSanitizeResponseGuardrail(name string, priority int32, fn LLMRes id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_register_llm_sanitize_response_guardrail( cName, C.int32_t(priority), - C.NemoFlowLlmResponseFn(C.goLlmResponseTrampoline), + C.NemoRelayLlmResponseFn(C.goLlmResponseTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1339,7 +1339,7 @@ func RegisterLlmSanitizeResponseGuardrail(name string, priority int32, fn LLMRes func DeregisterLlmSanitizeResponseGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_sanitize_response_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_llm_sanitize_response_guardrail(cName)) } // RegisterLlmConditionalExecutionGuardrail registers a guardrail that @@ -1352,11 +1352,11 @@ func RegisterLlmConditionalExecutionGuardrail(name string, priority int32, fn LL id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_register_llm_conditional_execution_guardrail( cName, C.int32_t(priority), - C.NemoFlowLlmConditionalCb(C.goLlmConditionalTrampoline), + C.NemoRelayLlmConditionalCb(C.goLlmConditionalTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1365,7 +1365,7 @@ func RegisterLlmConditionalExecutionGuardrail(name string, priority int32, fn LL func DeregisterLlmConditionalExecutionGuardrail(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_conditional_execution_guardrail(cName)) + return checkStatus(C.nemo_relay_deregister_llm_conditional_execution_guardrail(cName)) } // RegisterLlmRequestIntercept registers an intercept that transforms the LLM @@ -1378,11 +1378,11 @@ func RegisterLlmRequestIntercept(name string, priority int32, breakChain bool, f id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_request_intercept( + return checkStatus(C.nemo_relay_register_llm_request_intercept( cName, C.int32_t(priority), C._Bool(breakChain), - C.NemoFlowLlmRequestInterceptCb(C.goLlmRequestInterceptTrampoline), + C.NemoRelayLlmRequestInterceptCb(C.goLlmRequestInterceptTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1391,7 +1391,7 @@ func RegisterLlmRequestIntercept(name string, priority int32, breakChain bool, f func DeregisterLlmRequestIntercept(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_request_intercept(cName)) + return checkStatus(C.nemo_relay_deregister_llm_request_intercept(cName)) } // RegisterLlmExecutionIntercept registers an execution intercept following @@ -1402,11 +1402,11 @@ func RegisterLlmExecutionIntercept(name string, priority int32, execFn LLMExecut execID := registerClosure(execFn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_execution_intercept( + return checkStatus(C.nemo_relay_register_llm_execution_intercept( cName, C.int32_t(priority), - C.NemoFlowLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), + C.NemoRelayLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1415,7 +1415,7 @@ func RegisterLlmExecutionIntercept(name string, priority int32, execFn LLMExecut func DeregisterLlmExecutionIntercept(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_execution_intercept(cName)) + return checkStatus(C.nemo_relay_deregister_llm_execution_intercept(cName)) } // RegisterLlmStreamExecutionIntercept registers an execution intercept for @@ -1427,11 +1427,11 @@ func RegisterLlmStreamExecutionIntercept(name string, priority int32, execFn LLM execID := registerClosure(execFn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_llm_stream_execution_intercept( + return checkStatus(C.nemo_relay_register_llm_stream_execution_intercept( cName, C.int32_t(priority), - C.NemoFlowLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), + C.NemoRelayLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1440,7 +1440,7 @@ func RegisterLlmStreamExecutionIntercept(name string, priority int32, execFn LLM func DeregisterLlmStreamExecutionIntercept(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_llm_stream_execution_intercept(cName)) + return checkStatus(C.nemo_relay_deregister_llm_stream_execution_intercept(cName)) } // --------------------------------------------------------------------------- @@ -1456,11 +1456,11 @@ func RegisterSubscriber(name string, fn EventSubscriberFunc) error { id := registerClosure(fn) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_register_subscriber( + return checkStatus(C.nemo_relay_register_subscriber( cName, - C.NemoFlowEventSubscriberFn(C.goEventSubscriberTrampoline), + C.NemoRelayEventSubscriberFn(C.goEventSubscriberTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -1469,7 +1469,7 @@ func RegisterSubscriber(name string, fn EventSubscriberFunc) error { func DeregisterSubscriber(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_deregister_subscriber(cName)) + return checkStatus(C.nemo_relay_deregister_subscriber(cName)) } // --------------------------------------------------------------------------- @@ -1491,32 +1491,32 @@ func NewScopeStack() (*ScopeStack, error) { // Close frees the scope stack. After calling Close, the ScopeStack must not be used. func (s *ScopeStack) Close() { if s.ptr != nil { - C.nemo_flow_scope_stack_free(s.ptr) + C.nemo_relay_scope_stack_free(s.ptr) s.ptr = nil } } // Run binds this scope stack to the current OS thread and executes fn. // The calling goroutine is locked to the OS thread for the duration of fn. -// All NeMo Flow scope operations within fn will use this scope stack. +// All NeMo Relay scope operations within fn will use this scope stack. // // This is the canonical way to propagate a scope stack to a worker goroutine. func (s *ScopeStack) Run(fn func()) { runtime.LockOSThread() var binding *C.FfiThreadScopeStackBinding - if err := checkStatus(C.nemo_flow_scope_stack_capture_thread(&binding)); err != nil { + if err := checkStatus(C.nemo_relay_scope_stack_capture_thread(&binding)); err != nil { runtime.UnlockOSThread() panic(err) } defer func() { - status := C.nemo_flow_scope_stack_restore_thread(binding) + status := C.nemo_relay_scope_stack_restore_thread(binding) if err := checkStatus(status); err != nil { runtime.UnlockOSThread() panic(err) } runtime.UnlockOSThread() }() - if err := checkStatus(C.nemo_flow_scope_stack_set_thread(s.ptr)); err != nil { + if err := checkStatus(C.nemo_relay_scope_stack_set_thread(s.ptr)); err != nil { panic(err) } fn() @@ -1529,7 +1529,7 @@ func (s *ScopeStack) Run(fn func()) { // This function must be called from a goroutine locked to an OS thread // (e.g. inside ScopeStack.Run) for the result to be meaningful. func ScopeStackActive() bool { - return bool(C.nemo_flow_scope_stack_active()) + return bool(C.nemo_relay_scope_stack_active()) } // --------------------------------------------------------------------------- @@ -1551,7 +1551,7 @@ func NewAtifExporter(sessionID, agentName, agentVersion, modelName string) (*Ati func (e *AtifExporter) Register(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_atif_exporter_register(e.ptr, cName) + status := C.nemo_relay_atif_exporter_register(e.ptr, cName) return checkStatus(status) } @@ -1559,30 +1559,30 @@ func (e *AtifExporter) Register(name string) error { func (e *AtifExporter) Deregister(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_atif_exporter_deregister(cName) + status := C.nemo_relay_atif_exporter_deregister(cName) return checkStatus(status) } // ExportJSON exports collected events as an ATIF trajectory JSON string. func (e *AtifExporter) ExportJSON() (json.RawMessage, error) { var cOut *C.char - status := C.nemo_flow_atif_exporter_export(e.ptr, &cOut) + status := C.nemo_relay_atif_exporter_export(e.ptr, &cOut) if err := checkStatus(status); err != nil { return nil, err } - defer C.nemo_flow_string_free(cOut) + defer C.nemo_relay_string_free(cOut) return json.RawMessage(C.GoString(cOut)), nil } // Clear removes all collected events. func (e *AtifExporter) Clear() { - C.nemo_flow_atif_exporter_clear(e.ptr) + C.nemo_relay_atif_exporter_clear(e.ptr) } // Close frees the exporter handle. func (e *AtifExporter) Close() { if e.ptr != nil { - C.nemo_flow_atif_exporter_free(e.ptr) + C.nemo_relay_atif_exporter_free(e.ptr) e.ptr = nil } } @@ -1615,7 +1615,7 @@ func NewAtofExporterConfig() AtofExporterConfig { } } -// AtofExporter writes raw NeMo Flow ATOF lifecycle events as JSONL. +// AtofExporter writes raw NeMo Relay ATOF lifecycle events as JSONL. type AtofExporter struct { ptr unsafe.Pointer } @@ -1628,11 +1628,11 @@ func NewAtofExporter(config AtofExporterConfig) (*AtofExporter, error) { // Path returns the JSONL output path. func (e *AtofExporter) Path() (string, error) { var cOut *C.char - status := C.nemo_flow_atof_exporter_path(e.ptr, &cOut) + status := C.nemo_relay_atof_exporter_path(e.ptr, &cOut) if err := checkStatus(status); err != nil { return "", err } - defer C.nemo_flow_string_free(cOut) + defer C.nemo_relay_string_free(cOut) return C.GoString(cOut), nil } @@ -1640,7 +1640,7 @@ func (e *AtofExporter) Path() (string, error) { func (e *AtofExporter) Register(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_atof_exporter_register(e.ptr, cName) + status := C.nemo_relay_atof_exporter_register(e.ptr, cName) return checkStatus(status) } @@ -1648,26 +1648,26 @@ func (e *AtofExporter) Register(name string) error { func (e *AtofExporter) Deregister(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_atof_exporter_deregister(cName) + status := C.nemo_relay_atof_exporter_deregister(cName) return checkStatus(status) } // ForceFlush flushes the output file. func (e *AtofExporter) ForceFlush() error { - status := C.nemo_flow_atof_exporter_force_flush(e.ptr) + status := C.nemo_relay_atof_exporter_force_flush(e.ptr) return checkStatus(status) } // Shutdown flushes the output file. func (e *AtofExporter) Shutdown() error { - status := C.nemo_flow_atof_exporter_shutdown(e.ptr) + status := C.nemo_relay_atof_exporter_shutdown(e.ptr) return checkStatus(status) } // Close frees the exporter handle. func (e *AtofExporter) Close() { if e.ptr != nil { - C.nemo_flow_atof_exporter_free(e.ptr) + C.nemo_relay_atof_exporter_free(e.ptr) e.ptr = nil } } @@ -1709,12 +1709,12 @@ func NewOpenTelemetryConfig() OpenTelemetryConfig { Headers: map[string]string{}, ResourceAttributes: map[string]string{}, ServiceName: defaultServiceName, - InstrumentationScope: "nemo-flow-otel", + InstrumentationScope: "nemo-relay-otel", Timeout: 3 * time.Second, } } -// OpenTelemetrySubscriber exports NeMo Flow lifecycle events to an OpenTelemetry server. +// OpenTelemetrySubscriber exports NeMo Relay lifecycle events to an OpenTelemetry server. type OpenTelemetrySubscriber struct { ptr unsafe.Pointer } @@ -1728,7 +1728,7 @@ func NewOpenTelemetrySubscriber(config OpenTelemetryConfig) (*OpenTelemetrySubsc config.ServiceName = defaultServiceName } if config.InstrumentationScope == "" { - config.InstrumentationScope = "nemo-flow-otel" + config.InstrumentationScope = "nemo-relay-otel" } if config.Timeout == 0 { config.Timeout = 3 * time.Second @@ -1782,7 +1782,7 @@ func NewOpenTelemetrySubscriber(config OpenTelemetryConfig) (*OpenTelemetrySubsc defer C.free(unsafe.Pointer(cInstrumentationScope)) var ptr unsafe.Pointer - status := C.nemo_flow_otel_subscriber_create( + status := C.nemo_relay_otel_subscriber_create( cTransport, cEndpoint, cHeadersJSON, @@ -1804,7 +1804,7 @@ func NewOpenTelemetrySubscriber(config OpenTelemetryConfig) (*OpenTelemetrySubsc func (s *OpenTelemetrySubscriber) Register(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_otel_subscriber_register(s.ptr, cName) + status := C.nemo_relay_otel_subscriber_register(s.ptr, cName) return checkStatus(status) } @@ -1812,26 +1812,26 @@ func (s *OpenTelemetrySubscriber) Register(name string) error { func (s *OpenTelemetrySubscriber) Deregister(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_otel_subscriber_deregister(cName) + status := C.nemo_relay_otel_subscriber_deregister(cName) return checkStatus(status) } // ForceFlush flushes finished spans through the underlying exporter. func (s *OpenTelemetrySubscriber) ForceFlush() error { - status := C.nemo_flow_otel_subscriber_force_flush(s.ptr) + status := C.nemo_relay_otel_subscriber_force_flush(s.ptr) return checkStatus(status) } // Shutdown shuts down the underlying tracer provider. func (s *OpenTelemetrySubscriber) Shutdown() error { - status := C.nemo_flow_otel_subscriber_shutdown(s.ptr) + status := C.nemo_relay_otel_subscriber_shutdown(s.ptr) return checkStatus(status) } // Close frees the subscriber handle. func (s *OpenTelemetrySubscriber) Close() { if s.ptr != nil { - C.nemo_flow_otel_subscriber_free(s.ptr) + C.nemo_relay_otel_subscriber_free(s.ptr) s.ptr = nil } } @@ -1873,12 +1873,12 @@ func NewOpenInferenceConfig() OpenInferenceConfig { Headers: map[string]string{}, ResourceAttributes: map[string]string{}, ServiceName: defaultServiceName, - InstrumentationScope: "nemo-flow-openinference", + InstrumentationScope: "nemo-relay-openinference", Timeout: 3 * time.Second, } } -// OpenInferenceSubscriber exports NeMo Flow lifecycle events with OpenInference semantics. +// OpenInferenceSubscriber exports NeMo Relay lifecycle events with OpenInference semantics. type OpenInferenceSubscriber struct { ptr unsafe.Pointer } @@ -1892,7 +1892,7 @@ func NewOpenInferenceSubscriber(config OpenInferenceConfig) (*OpenInferenceSubsc config.ServiceName = defaultServiceName } if config.InstrumentationScope == "" { - config.InstrumentationScope = "nemo-flow-openinference" + config.InstrumentationScope = "nemo-relay-openinference" } if config.Timeout == 0 { config.Timeout = 3 * time.Second @@ -1946,7 +1946,7 @@ func NewOpenInferenceSubscriber(config OpenInferenceConfig) (*OpenInferenceSubsc defer C.free(unsafe.Pointer(cInstrumentationScope)) var ptr unsafe.Pointer - status := C.nemo_flow_openinference_subscriber_create( + status := C.nemo_relay_openinference_subscriber_create( cTransport, cEndpoint, cHeadersJSON, @@ -1968,7 +1968,7 @@ func NewOpenInferenceSubscriber(config OpenInferenceConfig) (*OpenInferenceSubsc func (s *OpenInferenceSubscriber) Register(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_openinference_subscriber_register(s.ptr, cName) + status := C.nemo_relay_openinference_subscriber_register(s.ptr, cName) return checkStatus(status) } @@ -1976,26 +1976,26 @@ func (s *OpenInferenceSubscriber) Register(name string) error { func (s *OpenInferenceSubscriber) Deregister(name string) error { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - status := C.nemo_flow_openinference_subscriber_deregister(cName) + status := C.nemo_relay_openinference_subscriber_deregister(cName) return checkStatus(status) } // ForceFlush flushes finished spans through the underlying exporter. func (s *OpenInferenceSubscriber) ForceFlush() error { - status := C.nemo_flow_openinference_subscriber_force_flush(s.ptr) + status := C.nemo_relay_openinference_subscriber_force_flush(s.ptr) return checkStatus(status) } // Shutdown shuts down the underlying tracer provider. func (s *OpenInferenceSubscriber) Shutdown() error { - status := C.nemo_flow_openinference_subscriber_shutdown(s.ptr) + status := C.nemo_relay_openinference_subscriber_shutdown(s.ptr) return checkStatus(status) } // Close frees the subscriber handle. func (s *OpenInferenceSubscriber) Close() { if s.ptr != nil { - C.nemo_flow_openinference_subscriber_free(s.ptr) + C.nemo_relay_openinference_subscriber_free(s.ptr) s.ptr = nil } } @@ -2013,11 +2013,11 @@ func ScopeRegisterToolSanitizeRequestGuardrail(scopeUUID, name string, priority defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_tool_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_scope_register_tool_sanitize_request_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2028,7 +2028,7 @@ func ScopeDeregisterToolSanitizeRequestGuardrail(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_tool_sanitize_request_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_tool_sanitize_request_guardrail(cScopeUUID, cName)) } // ScopeRegisterToolSanitizeResponseGuardrail registers a scope-local guardrail @@ -2039,11 +2039,11 @@ func ScopeRegisterToolSanitizeResponseGuardrail(scopeUUID, name string, priority defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_tool_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_scope_register_tool_sanitize_response_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2054,7 +2054,7 @@ func ScopeDeregisterToolSanitizeResponseGuardrail(scopeUUID, name string) error defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_tool_sanitize_response_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_tool_sanitize_response_guardrail(cScopeUUID, cName)) } // ScopeRegisterToolConditionalExecutionGuardrail registers a scope-local @@ -2066,11 +2066,11 @@ func ScopeRegisterToolConditionalExecutionGuardrail(scopeUUID, name string, prio defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_tool_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_scope_register_tool_conditional_execution_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowToolConditionalFn(C.goToolConditionalTrampoline), + C.NemoRelayToolConditionalFn(C.goToolConditionalTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2081,7 +2081,7 @@ func ScopeDeregisterToolConditionalExecutionGuardrail(scopeUUID, name string) er defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_tool_conditional_execution_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_tool_conditional_execution_guardrail(cScopeUUID, cName)) } // ScopeRegisterToolRequestIntercept registers a scope-local intercept that @@ -2092,11 +2092,11 @@ func ScopeRegisterToolRequestIntercept(scopeUUID, name string, priority int32, b defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_tool_request_intercept( + return checkStatus(C.nemo_relay_scope_register_tool_request_intercept( cScopeUUID, cName, C.int32_t(priority), C._Bool(breakChain), - C.NemoFlowToolSanitizeFn(C.goToolSanitizeTrampoline), + C.NemoRelayToolSanitizeFn(C.goToolSanitizeTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2107,7 +2107,7 @@ func ScopeDeregisterToolRequestIntercept(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_tool_request_intercept(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_tool_request_intercept(cScopeUUID, cName)) } // ScopeRegisterToolExecutionIntercept registers a scope-local tool execution @@ -2118,11 +2118,11 @@ func ScopeRegisterToolExecutionIntercept(scopeUUID, name string, priority int32, defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_tool_execution_intercept( + return checkStatus(C.nemo_relay_scope_register_tool_execution_intercept( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowToolExecInterceptCb(C.goToolExecInterceptTrampoline), + C.NemoRelayToolExecInterceptCb(C.goToolExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2133,7 +2133,7 @@ func ScopeDeregisterToolExecutionIntercept(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_tool_execution_intercept(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_tool_execution_intercept(cScopeUUID, cName)) } // --------------------------------------------------------------------------- @@ -2148,11 +2148,11 @@ func ScopeRegisterLlmSanitizeRequestGuardrail(scopeUUID, name string, priority i defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_scope_register_llm_sanitize_request_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowLlmRequestCb(C.goLlmRequestTrampoline), + C.NemoRelayLlmRequestCb(C.goLlmRequestTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2163,7 +2163,7 @@ func ScopeDeregisterLlmSanitizeRequestGuardrail(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_sanitize_request_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_sanitize_request_guardrail(cScopeUUID, cName)) } // ScopeRegisterLlmSanitizeResponseGuardrail registers a scope-local guardrail @@ -2174,11 +2174,11 @@ func ScopeRegisterLlmSanitizeResponseGuardrail(scopeUUID, name string, priority defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_scope_register_llm_sanitize_response_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowLlmResponseFn(C.goLlmResponseTrampoline), + C.NemoRelayLlmResponseFn(C.goLlmResponseTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2189,7 +2189,7 @@ func ScopeDeregisterLlmSanitizeResponseGuardrail(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_sanitize_response_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_sanitize_response_guardrail(cScopeUUID, cName)) } // ScopeRegisterLlmConditionalExecutionGuardrail registers a scope-local @@ -2200,11 +2200,11 @@ func ScopeRegisterLlmConditionalExecutionGuardrail(scopeUUID, name string, prior defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_scope_register_llm_conditional_execution_guardrail( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowLlmConditionalCb(C.goLlmConditionalTrampoline), + C.NemoRelayLlmConditionalCb(C.goLlmConditionalTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2215,7 +2215,7 @@ func ScopeDeregisterLlmConditionalExecutionGuardrail(scopeUUID, name string) err defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_conditional_execution_guardrail(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_conditional_execution_guardrail(cScopeUUID, cName)) } // ScopeRegisterLlmRequestIntercept registers a scope-local intercept that @@ -2226,11 +2226,11 @@ func ScopeRegisterLlmRequestIntercept(scopeUUID, name string, priority int32, br defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_request_intercept( + return checkStatus(C.nemo_relay_scope_register_llm_request_intercept( cScopeUUID, cName, C.int32_t(priority), C._Bool(breakChain), - C.NemoFlowLlmRequestInterceptCb(C.goLlmRequestInterceptTrampoline), + C.NemoRelayLlmRequestInterceptCb(C.goLlmRequestInterceptTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2241,7 +2241,7 @@ func ScopeDeregisterLlmRequestIntercept(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_request_intercept(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_request_intercept(cScopeUUID, cName)) } // ScopeRegisterLlmExecutionIntercept registers a scope-local LLM execution @@ -2252,11 +2252,11 @@ func ScopeRegisterLlmExecutionIntercept(scopeUUID, name string, priority int32, defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_execution_intercept( + return checkStatus(C.nemo_relay_scope_register_llm_execution_intercept( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), + C.NemoRelayLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2267,7 +2267,7 @@ func ScopeDeregisterLlmExecutionIntercept(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_execution_intercept(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_execution_intercept(cScopeUUID, cName)) } // ScopeRegisterLlmStreamExecutionIntercept registers a scope-local streaming @@ -2278,11 +2278,11 @@ func ScopeRegisterLlmStreamExecutionIntercept(scopeUUID, name string, priority i defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_llm_stream_execution_intercept( + return checkStatus(C.nemo_relay_scope_register_llm_stream_execution_intercept( cScopeUUID, cName, C.int32_t(priority), - C.NemoFlowLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), + C.NemoRelayLlmExecInterceptCb(C.goLlmExecInterceptTrampoline), execID, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2293,7 +2293,7 @@ func ScopeDeregisterLlmStreamExecutionIntercept(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_llm_stream_execution_intercept(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_llm_stream_execution_intercept(cScopeUUID, cName)) } // --------------------------------------------------------------------------- @@ -2309,11 +2309,11 @@ func ScopeRegisterSubscriber(scopeUUID, name string, fn EventSubscriberFunc) err defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_register_subscriber( + return checkStatus(C.nemo_relay_scope_register_subscriber( cScopeUUID, cName, - C.NemoFlowEventSubscriberFn(C.goEventSubscriberTrampoline), + C.NemoRelayEventSubscriberFn(C.goEventSubscriberTrampoline), id, - C.NemoFlowFreeFn(C.goFreeTrampoline), + C.NemoRelayFreeFn(C.goFreeTrampoline), )) } @@ -2323,7 +2323,7 @@ func ScopeDeregisterSubscriber(scopeUUID, name string) error { defer C.free(unsafe.Pointer(cScopeUUID)) cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) - return checkStatus(C.nemo_flow_scope_deregister_subscriber(cScopeUUID, cName)) + return checkStatus(C.nemo_relay_scope_deregister_subscriber(cScopeUUID, cName)) } // --------------------------------------------------------------------------- @@ -2339,11 +2339,11 @@ func ToolRequestIntercepts(name string, args json.RawMessage) (json.RawMessage, defer C.free(unsafe.Pointer(cArgs)) var out *C.char - status := C.nemo_flow_tool_request_intercepts(cName, cArgs, &out) + status := C.nemo_relay_tool_request_intercepts(cName, cArgs, &out) if err := checkStatus(status); err != nil { return nil, err } - defer C.nemo_flow_string_free(out) + defer C.nemo_relay_string_free(out) return json.RawMessage(C.GoString(out)), nil } @@ -2356,7 +2356,7 @@ func ToolConditionalExecution(name string, args json.RawMessage) error { cArgs := C.CString(string(args)) defer C.free(unsafe.Pointer(cArgs)) - status := C.nemo_flow_tool_conditional_execution(cName, cArgs) + status := C.nemo_relay_tool_conditional_execution(cName, cArgs) return checkStatus(status) } @@ -2369,11 +2369,11 @@ func LlmRequestIntercepts(name string, request json.RawMessage) (json.RawMessage defer C.free(unsafe.Pointer(cRequest)) var out *C.char - status := C.nemo_flow_llm_request_intercepts(cName, cRequest, &out) + status := C.nemo_relay_llm_request_intercepts(cName, cRequest, &out) if err := checkStatus(status); err != nil { return nil, err } - defer C.nemo_flow_string_free(out) + defer C.nemo_relay_string_free(out) return json.RawMessage(C.GoString(out)), nil } @@ -2385,6 +2385,6 @@ func LlmConditionalExecution(request json.RawMessage) error { cRequest := C.CString(string(request)) defer C.free(unsafe.Pointer(cRequest)) - status := C.nemo_flow_llm_conditional_execution(cRequest) + status := C.nemo_relay_llm_conditional_execution(cRequest) return checkStatus(status) } diff --git a/go/nemo_flow/observability_plugin.go b/go/nemo_relay/observability_plugin.go similarity index 96% rename from go/nemo_flow/observability_plugin.go rename to go/nemo_relay/observability_plugin.go index fcc1e8b45..2b72b8d28 100644 --- a/go/nemo_flow/observability_plugin.go +++ b/go/nemo_relay/observability_plugin.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay // ObservabilityPluginKind is the top-level plugin kind used by the core observability component. const ObservabilityPluginKind = "observability" @@ -71,9 +71,9 @@ func NewObservabilityAtofConfig() ObservabilityAtofConfig { // NewObservabilityAtifConfig returns disabled ATIF settings with core defaults. func NewObservabilityAtifConfig() ObservabilityAtifConfig { return ObservabilityAtifConfig{ - AgentName: "NeMo Flow", + AgentName: "NeMo Relay", ModelName: "unknown", - FilenameTemplate: "nemo-flow-atif-{session_id}.json", + FilenameTemplate: "nemo-relay-atif-{session_id}.json", } } @@ -83,7 +83,7 @@ func NewObservabilityOtlpConfig() ObservabilityOtlpConfig { Transport: "http_binary", Headers: map[string]string{}, ResourceAttributes: map[string]string{}, - ServiceName: "nemo-flow", + ServiceName: "nemo-relay", TimeoutMillis: 3000, } } diff --git a/go/nemo_flow/observability_plugin_test.go b/go/nemo_relay/observability_plugin_test.go similarity index 96% rename from go/nemo_flow/observability_plugin_test.go rename to go/nemo_relay/observability_plugin_test.go index 8369db837..facb85d5f 100644 --- a/go/nemo_flow/observability_plugin_test.go +++ b/go/nemo_relay/observability_plugin_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" @@ -32,11 +32,11 @@ func TestObservabilityConfigHelpers(t *testing.T) { t.Fatalf("unexpected ATOF defaults: %#v", atof) } atif := NewObservabilityAtifConfig() - if atif.Enabled || atif.AgentName != "NeMo Flow" || atif.ModelName != "unknown" || atif.FilenameTemplate != "nemo-flow-atif-{session_id}.json" { + if atif.Enabled || atif.AgentName != "NeMo Relay" || atif.ModelName != "unknown" || atif.FilenameTemplate != "nemo-relay-atif-{session_id}.json" { t.Fatalf("unexpected ATIF defaults: %#v", atif) } otlp := NewObservabilityOtlpConfig() - if otlp.Enabled || otlp.Transport != "http_binary" || otlp.ServiceName != "nemo-flow" || otlp.TimeoutMillis != 3000 { + if otlp.Enabled || otlp.Transport != "http_binary" || otlp.ServiceName != "nemo-relay" || otlp.TimeoutMillis != 3000 { t.Fatalf("unexpected OTLP defaults: %#v", otlp) } @@ -206,7 +206,7 @@ func TestObservabilityAtifOpenAgentFlushesOnClear(t *testing.T) { if err := ClearPluginConfiguration(); err != nil { t.Fatalf(fatalErrorFormat, ClearPluginConfigurationFailed, err) } - path := filepath.Join(dir, "nemo-flow-atif-"+handle.UUID()+".json") + path := filepath.Join(dir, "nemo-relay-atif-"+handle.UUID()+".json") if _, err := os.Stat(path); err != nil { t.Fatalf("expected open-agent ATIF file at %s: %v", path, err) } diff --git a/go/nemo_flow/openinference_test.go b/go/nemo_relay/openinference_test.go similarity index 95% rename from go/nemo_flow/openinference_test.go rename to go/nemo_relay/openinference_test.go index fe06e81ad..c7350af26 100644 --- a/go/nemo_flow/openinference_test.go +++ b/go/nemo_relay/openinference_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "bytes" @@ -19,10 +19,10 @@ func TestNewOpenInferenceConfigDefaults(t *testing.T) { if config.Transport != OpenInferenceTransportHTTPBinary { t.Fatalf("expected default transport http_binary, got %q", config.Transport) } - if config.ServiceName != "nemo-flow" { - t.Fatalf("expected default service name nemo-flow, got %q", config.ServiceName) + if config.ServiceName != "nemo-relay" { + t.Fatalf("expected default service name nemo-relay, got %q", config.ServiceName) } - if config.InstrumentationScope != "nemo-flow-openinference" { + if config.InstrumentationScope != "nemo-relay-openinference" { t.Fatalf("expected default instrumentation scope, got %q", config.InstrumentationScope) } if config.Timeout != 3*time.Second { diff --git a/go/nemo_flow/otel_test.go b/go/nemo_relay/otel_test.go similarity index 95% rename from go/nemo_flow/otel_test.go rename to go/nemo_relay/otel_test.go index cb661df2c..f07bc2925 100644 --- a/go/nemo_flow/otel_test.go +++ b/go/nemo_relay/otel_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" @@ -18,10 +18,10 @@ func TestNewOpenTelemetryConfigDefaults(t *testing.T) { if config.Transport != OpenTelemetryTransportHTTPBinary { t.Fatalf("expected default transport http_binary, got %q", config.Transport) } - if config.ServiceName != "nemo-flow" { - t.Fatalf("expected default service name nemo-flow, got %q", config.ServiceName) + if config.ServiceName != "nemo-relay" { + t.Fatalf("expected default service name nemo-relay, got %q", config.ServiceName) } - if config.InstrumentationScope != "nemo-flow-otel" { + if config.InstrumentationScope != "nemo-relay-otel" { t.Fatalf("expected default instrumentation scope, got %q", config.InstrumentationScope) } if config.Timeout != 3*time.Second { diff --git a/go/nemo_flow/plugin.go b/go/nemo_relay/plugin.go similarity index 67% rename from go/nemo_flow/plugin.go rename to go/nemo_relay/plugin.go index e61c71a8c..c4a8affcf 100644 --- a/go/nemo_flow/plugin.go +++ b/go/nemo_relay/plugin.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay /* #include @@ -9,42 +9,42 @@ package nemo_flow typedef struct FfiPluginContext FfiPluginContext; -typedef void (*NemoFlowFreeFn)(void* user_data); -typedef char* (*NemoFlowPluginValidateCb)(void* user_data, const char* plugin_config_json); -typedef int32_t (*NemoFlowPluginRegisterCb)(void* user_data, const char* plugin_config_json, FfiPluginContext* ctx); -typedef void (*NemoFlowEventSubscriberFn)(void* user_data, const void* event); -typedef char* (*NemoFlowToolSanitizeFn)(void* user_data, const char* name, const char* args_json); -typedef char* (*NemoFlowToolConditionalFn)(void* user_data, const char* name, const char* args_json); -typedef void* (*NemoFlowLlmRequestCb)(void* user_data, const void* request); -typedef char* (*NemoFlowLlmResponseFn)(void* user_data, const char* response_json); -typedef char* (*NemoFlowLlmConditionalCb)(void* user_data, const void* request); -typedef int32_t (*NemoFlowLlmRequestInterceptCb)(void* user_data, const char* name, const void* request, const char* annotated_json, void** out_request, char** out_annotated_json); -typedef char* (*NemoFlowLlmExecNextFn)(const char* native_json, void* next_ctx); -typedef char* (*NemoFlowLlmExecInterceptCb)(void* user_data, const char* native_json, NemoFlowLlmExecNextFn next_fn, void* next_ctx); -typedef char* (*NemoFlowToolExecNextFn)(const char* args_json, void* next_ctx); -typedef char* (*NemoFlowToolExecInterceptCb)(void* user_data, const char* args_json, NemoFlowToolExecNextFn next_fn, void* next_ctx); - -extern int32_t nemo_flow_validate_plugin_config(const char* config_json, char** out_json); -extern int32_t nemo_flow_initialize_plugins(const char* config_json, char** out_json); -extern int32_t nemo_flow_clear_plugin_configuration(void); -extern int32_t nemo_flow_active_plugin_report_json(char** out_json); -extern int32_t nemo_flow_list_plugin_kinds_json(char** out_json); -extern int32_t nemo_flow_register_plugin(const char* plugin_kind, NemoFlowPluginValidateCb validate_cb, NemoFlowPluginRegisterCb register_cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_deregister_plugin(const char* plugin_kind); -extern void nemo_flow_string_free(char* ptr); - -extern int32_t nemo_flow_plugin_context_register_subscriber(FfiPluginContext* ctx, const char* name, NemoFlowEventSubscriberFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_tool_sanitize_request_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_tool_sanitize_response_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_tool_conditional_execution_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowToolConditionalFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_sanitize_request_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowLlmRequestCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_sanitize_response_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowLlmResponseFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_conditional_execution_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowLlmConditionalCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_request_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, _Bool break_chain, NemoFlowLlmRequestInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_tool_request_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, _Bool break_chain, NemoFlowToolSanitizeFn cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowLlmExecInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_llm_stream_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowLlmExecInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); -extern int32_t nemo_flow_plugin_context_register_tool_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoFlowToolExecInterceptCb cb, void* user_data, NemoFlowFreeFn free_fn); +typedef void (*NemoRelayFreeFn)(void* user_data); +typedef char* (*NemoRelayPluginValidateCb)(void* user_data, const char* plugin_config_json); +typedef int32_t (*NemoRelayPluginRegisterCb)(void* user_data, const char* plugin_config_json, FfiPluginContext* ctx); +typedef void (*NemoRelayEventSubscriberFn)(void* user_data, const void* event); +typedef char* (*NemoRelayToolSanitizeFn)(void* user_data, const char* name, const char* args_json); +typedef char* (*NemoRelayToolConditionalFn)(void* user_data, const char* name, const char* args_json); +typedef void* (*NemoRelayLlmRequestCb)(void* user_data, const void* request); +typedef char* (*NemoRelayLlmResponseFn)(void* user_data, const char* response_json); +typedef char* (*NemoRelayLlmConditionalCb)(void* user_data, const void* request); +typedef int32_t (*NemoRelayLlmRequestInterceptCb)(void* user_data, const char* name, const void* request, const char* annotated_json, void** out_request, char** out_annotated_json); +typedef char* (*NemoRelayLlmExecNextFn)(const char* native_json, void* next_ctx); +typedef char* (*NemoRelayLlmExecInterceptCb)(void* user_data, const char* native_json, NemoRelayLlmExecNextFn next_fn, void* next_ctx); +typedef char* (*NemoRelayToolExecNextFn)(const char* args_json, void* next_ctx); +typedef char* (*NemoRelayToolExecInterceptCb)(void* user_data, const char* args_json, NemoRelayToolExecNextFn next_fn, void* next_ctx); + +extern int32_t nemo_relay_validate_plugin_config(const char* config_json, char** out_json); +extern int32_t nemo_relay_initialize_plugins(const char* config_json, char** out_json); +extern int32_t nemo_relay_clear_plugin_configuration(void); +extern int32_t nemo_relay_active_plugin_report_json(char** out_json); +extern int32_t nemo_relay_list_plugin_kinds_json(char** out_json); +extern int32_t nemo_relay_register_plugin(const char* plugin_kind, NemoRelayPluginValidateCb validate_cb, NemoRelayPluginRegisterCb register_cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_deregister_plugin(const char* plugin_kind); +extern void nemo_relay_string_free(char* ptr); + +extern int32_t nemo_relay_plugin_context_register_subscriber(FfiPluginContext* ctx, const char* name, NemoRelayEventSubscriberFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_tool_sanitize_request_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_tool_sanitize_response_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_tool_conditional_execution_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayToolConditionalFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_sanitize_request_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayLlmRequestCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_sanitize_response_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayLlmResponseFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_conditional_execution_guardrail(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayLlmConditionalCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_request_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, _Bool break_chain, NemoRelayLlmRequestInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_tool_request_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, _Bool break_chain, NemoRelayToolSanitizeFn cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayLlmExecInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_llm_stream_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayLlmExecInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); +extern int32_t nemo_relay_plugin_context_register_tool_execution_intercept(FfiPluginContext* ctx, const char* name, int32_t priority, NemoRelayToolExecInterceptCb cb, void* user_data, NemoRelayFreeFn free_fn); extern char* goPluginValidateTrampoline(void*, const char*); extern int32_t goPluginRegisterTrampoline(void*, const char*, FfiPluginContext*); @@ -55,9 +55,9 @@ extern char* goToolConditionalTrampoline(void*, const char*, const char*); extern void* goLlmRequestTrampoline(void*, const void*); extern char* goLlmResponseTrampoline(void*, const char*); extern char* goLlmConditionalTrampoline(void*, const void*); -extern char* goLlmExecInterceptTrampoline(void*, const char*, NemoFlowLlmExecNextFn, void*); +extern char* goLlmExecInterceptTrampoline(void*, const char*, NemoRelayLlmExecNextFn, void*); extern int32_t goLlmRequestInterceptTrampoline(void*, const char*, const void*, const char*, void**, char**); -extern char* goToolExecInterceptTrampoline(void*, const char*, NemoFlowToolExecNextFn, void*); +extern char* goToolExecInterceptTrampoline(void*, const char*, NemoRelayToolExecNextFn, void*); */ import "C" @@ -85,9 +85,9 @@ var ( defer C.free(unsafe.Pointer(cConfig)) var out *C.char - status := C.nemo_flow_validate_plugin_config(cConfig, &out) + status := C.nemo_relay_validate_plugin_config(cConfig, &out) return checkedJSONString(int32(status), func() string { return C.GoString(out) }, func() { - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) }) } initializePluginsJSON = func(config PluginConfig) (string, error) { @@ -98,23 +98,23 @@ var ( defer C.free(unsafe.Pointer(cConfig)) var out *C.char - status := C.nemo_flow_initialize_plugins(cConfig, &out) + status := C.nemo_relay_initialize_plugins(cConfig, &out) return checkedJSONString(int32(status), func() string { return C.GoString(out) }, func() { - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) }) } activePluginReportJSON = func() (string, error) { var out *C.char - status := C.nemo_flow_active_plugin_report_json(&out) + status := C.nemo_relay_active_plugin_report_json(&out) return checkedJSONString(int32(status), func() string { return C.GoString(out) }, func() { - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) }) } listPluginKindsJSON = func() (string, error) { var out *C.char - status := C.nemo_flow_list_plugin_kinds_json(&out) + status := C.nemo_relay_list_plugin_kinds_json(&out) return checkedJSONString(int32(status), func() string { return C.GoString(out) }, func() { - C.nemo_flow_string_free(out) + C.nemo_relay_string_free(out) }) } ) @@ -262,7 +262,7 @@ func InitializePlugins(config PluginConfig) (ConfigReport, error) { // Registered plugin kinds remain available for future validation or // initialization. func ClearPluginConfiguration() error { - return checkStatus(C.nemo_flow_clear_plugin_configuration()) + return checkStatus(C.nemo_relay_clear_plugin_configuration()) } // ActivePluginReport returns the last successfully activated plugin report. @@ -303,12 +303,12 @@ func RegisterPlugin(pluginKind string, plugin Plugin) error { cPluginKind := C.CString(pluginKind) defer C.free(unsafe.Pointer(cPluginKind)) userData := registerClosure(plugin) - status := C.nemo_flow_register_plugin( + status := C.nemo_relay_register_plugin( cPluginKind, - (C.NemoFlowPluginValidateCb)(C.goPluginValidateTrampoline), - (C.NemoFlowPluginRegisterCb)(C.goPluginRegisterTrampoline), + (C.NemoRelayPluginValidateCb)(C.goPluginValidateTrampoline), + (C.NemoRelayPluginRegisterCb)(C.goPluginRegisterTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), ) return checkStatus(status) } @@ -320,7 +320,7 @@ func RegisterPlugin(pluginKind string, plugin Plugin) error { func DeregisterPlugin(pluginKind string) error { cPluginKind := C.CString(pluginKind) defer C.free(unsafe.Pointer(cPluginKind)) - return checkStatus(C.nemo_flow_deregister_plugin(cPluginKind)) + return checkStatus(C.nemo_relay_deregister_plugin(cPluginKind)) } // RegisterSubscriber registers an infallible event subscriber for this @@ -333,12 +333,12 @@ func (ctx *PluginContext) RegisterSubscriber(name string, fn EventSubscriberFunc cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_subscriber( + return checkStatus(C.nemo_relay_plugin_context_register_subscriber( ctx.ptr, cName, - (C.NemoFlowEventSubscriberFn)(C.goEventSubscriberTrampoline), + (C.NemoRelayEventSubscriberFn)(C.goEventSubscriberTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -350,13 +350,13 @@ func (ctx *PluginContext) RegisterToolSanitizeRequestGuardrail(name string, prio cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_tool_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_tool_sanitize_request_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowToolSanitizeFn)(C.goToolSanitizeTrampoline), + (C.NemoRelayToolSanitizeFn)(C.goToolSanitizeTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -368,13 +368,13 @@ func (ctx *PluginContext) RegisterToolSanitizeResponseGuardrail(name string, pri cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_tool_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_tool_sanitize_response_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowToolSanitizeFn)(C.goToolSanitizeTrampoline), + (C.NemoRelayToolSanitizeFn)(C.goToolSanitizeTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -386,13 +386,13 @@ func (ctx *PluginContext) RegisterToolConditionalExecutionGuardrail(name string, cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_tool_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_tool_conditional_execution_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowToolConditionalFn)(C.goToolConditionalTrampoline), + (C.NemoRelayToolConditionalFn)(C.goToolConditionalTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -404,13 +404,13 @@ func (ctx *PluginContext) RegisterLlmSanitizeRequestGuardrail(name string, prior cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_sanitize_request_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_llm_sanitize_request_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowLlmRequestCb)(C.goLlmRequestTrampoline), + (C.NemoRelayLlmRequestCb)(C.goLlmRequestTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -422,13 +422,13 @@ func (ctx *PluginContext) RegisterLlmSanitizeResponseGuardrail(name string, prio cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_sanitize_response_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_llm_sanitize_response_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowLlmResponseFn)(C.goLlmResponseTrampoline), + (C.NemoRelayLlmResponseFn)(C.goLlmResponseTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -440,13 +440,13 @@ func (ctx *PluginContext) RegisterLlmConditionalExecutionGuardrail(name string, cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_conditional_execution_guardrail( + return checkStatus(C.nemo_relay_plugin_context_register_llm_conditional_execution_guardrail( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowLlmConditionalCb)(C.goLlmConditionalTrampoline), + (C.NemoRelayLlmConditionalCb)(C.goLlmConditionalTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -461,14 +461,14 @@ func (ctx *PluginContext) RegisterLlmRequestIntercept(name string, priority int3 cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_request_intercept( + return checkStatus(C.nemo_relay_plugin_context_register_llm_request_intercept( ctx.ptr, cName, C.int32_t(priority), C._Bool(breakChain), - (C.NemoFlowLlmRequestInterceptCb)(C.goLlmRequestInterceptTrampoline), + (C.NemoRelayLlmRequestInterceptCb)(C.goLlmRequestInterceptTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -483,14 +483,14 @@ func (ctx *PluginContext) RegisterToolRequestIntercept(name string, priority int cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_tool_request_intercept( + return checkStatus(C.nemo_relay_plugin_context_register_tool_request_intercept( ctx.ptr, cName, C.int32_t(priority), C._Bool(breakChain), - (C.NemoFlowToolSanitizeFn)(C.goToolSanitizeTrampoline), + (C.NemoRelayToolSanitizeFn)(C.goToolSanitizeTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -502,13 +502,13 @@ func (ctx *PluginContext) RegisterLlmExecutionIntercept(name string, priority in cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_execution_intercept( + return checkStatus(C.nemo_relay_plugin_context_register_llm_execution_intercept( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowLlmExecInterceptCb)(C.goLlmExecInterceptTrampoline), + (C.NemoRelayLlmExecInterceptCb)(C.goLlmExecInterceptTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -520,13 +520,13 @@ func (ctx *PluginContext) RegisterLlmStreamExecutionIntercept(name string, prior cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_llm_stream_execution_intercept( + return checkStatus(C.nemo_relay_plugin_context_register_llm_stream_execution_intercept( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowLlmExecInterceptCb)(C.goLlmExecInterceptTrampoline), + (C.NemoRelayLlmExecInterceptCb)(C.goLlmExecInterceptTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } @@ -538,13 +538,13 @@ func (ctx *PluginContext) RegisterToolExecutionIntercept(name string, priority i cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) userData := registerClosure(fn) - return checkStatus(C.nemo_flow_plugin_context_register_tool_execution_intercept( + return checkStatus(C.nemo_relay_plugin_context_register_tool_execution_intercept( ctx.ptr, cName, C.int32_t(priority), - (C.NemoFlowToolExecInterceptCb)(C.goToolExecInterceptTrampoline), + (C.NemoRelayToolExecInterceptCb)(C.goToolExecInterceptTrampoline), userData, - (C.NemoFlowFreeFn)(C.goFreeTrampoline), + (C.NemoRelayFreeFn)(C.goFreeTrampoline), )) } diff --git a/go/nemo_flow/plugin_gap_test.go b/go/nemo_relay/plugin_gap_test.go similarity index 97% rename from go/nemo_flow/plugin_gap_test.go rename to go/nemo_relay/plugin_gap_test.go index 9e78cc2a7..cfdf32f3f 100644 --- a/go/nemo_flow/plugin_gap_test.go +++ b/go/nemo_relay/plugin_gap_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import "testing" diff --git a/go/nemo_flow/scope/error_coverage_test.go b/go/nemo_relay/scope/error_coverage_test.go similarity index 64% rename from go/nemo_flow/scope/error_coverage_test.go rename to go/nemo_relay/scope/error_coverage_test.go index b51afe45c..811093efe 100644 --- a/go/nemo_flow/scope/error_coverage_test.go +++ b/go/nemo_relay/scope/error_coverage_test.go @@ -7,28 +7,28 @@ import ( "encoding/json" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/scope" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/scope" ) func TestWithScopeCleanupNoopsWhenPushFails(t *testing.T) { for _, tc := range []struct { name string - opt nemo_flow.ScopeOption + opt nemo_relay.ScopeOption }{ - {name: "data", opt: nemo_flow.WithData(json.RawMessage("{"))}, - {name: "metadata", opt: nemo_flow.WithMetadata(json.RawMessage("{"))}, - {name: "input", opt: nemo_flow.WithInput(json.RawMessage("{"))}, + {name: "data", opt: nemo_relay.WithData(json.RawMessage("{"))}, + {name: "metadata", opt: nemo_relay.WithMetadata(json.RawMessage("{"))}, + {name: "input", opt: nemo_relay.WithInput(json.RawMessage("{"))}, } { - before, err := nemo_flow.GetHandle() + before, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle before failed: %v", err) } - cleanup := scope.WithScope("invalid_scope_"+tc.name, nemo_flow.ScopeTypeAgent, tc.opt) + cleanup := scope.WithScope("invalid_scope_"+tc.name, nemo_relay.ScopeTypeAgent, tc.opt) cleanup() - after, err := nemo_flow.GetHandle() + after, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle after WithScope failure failed: %v", err) } @@ -36,13 +36,13 @@ func TestWithScopeCleanupNoopsWhenPushFails(t *testing.T) { t.Fatalf("expected top of stack to remain %q after invalid %s, got %q", before.UUID(), tc.name, after.UUID()) } - handle, cleanupHandle := scope.WithScopeHandle("invalid_scope_"+tc.name, nemo_flow.ScopeTypeAgent, tc.opt) + handle, cleanupHandle := scope.WithScopeHandle("invalid_scope_"+tc.name, nemo_relay.ScopeTypeAgent, tc.opt) if handle != nil { t.Fatalf("expected nil handle on failed push for invalid %s, got %#v", tc.name, handle) } cleanupHandle() - afterHandle, err := nemo_flow.GetHandle() + afterHandle, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle after WithScopeHandle failure failed: %v", err) } diff --git a/go/nemo_flow/scope/scope.go b/go/nemo_relay/scope/scope.go similarity index 57% rename from go/nemo_flow/scope/scope.go rename to go/nemo_relay/scope/scope.go index f2f0d6a9c..3b5074c17 100644 --- a/go/nemo_flow/scope/scope.go +++ b/go/nemo_relay/scope/scope.go @@ -1,17 +1,17 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package scope provides shorthand access to NeMo Flow scope operations. +// Package scope provides shorthand access to NeMo Relay scope operations. // // It re-exports the core scope management functions (GetHandle, PushScope, // PopScope, EmitEvent) under shorter names for convenience. // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/scope" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/scope" // // // Push a new agent scope onto the stack. -// handle, err := scope.Push("my-agent", nemo_flow.ScopeTypeAgent) +// handle, err := scope.Push("my-agent", nemo_relay.ScopeTypeAgent) // if err != nil { // log.Fatal(err) // } @@ -22,49 +22,49 @@ package scope import ( - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) // GetHandle returns the handle for the scope currently at the top of the scope // stack. Returns an error if the scope stack is empty. This is a shorthand for -// [nemo_flow.GetHandle]. -func GetHandle() (*nemo_flow.ScopeHandle, error) { - return nemo_flow.GetHandle() +// [nemo_relay.GetHandle]. +func GetHandle() (*nemo_relay.ScopeHandle, error) { + return nemo_relay.GetHandle() } // Push creates a new scope and pushes it onto the hierarchical scope stack, // emitting a Start event to all registered subscribers. Use [Pop] to end the -// scope. Optional arguments, including [nemo_flow.WithScopeTimestamp], are -// forwarded to [nemo_flow.PushScope]. -func Push(name string, scopeType nemo_flow.ScopeType, opts ...nemo_flow.ScopeOption) (*nemo_flow.ScopeHandle, error) { - return nemo_flow.PushScope(name, scopeType, opts...) +// scope. Optional arguments, including [nemo_relay.WithScopeTimestamp], are +// forwarded to [nemo_relay.PushScope]. +func Push(name string, scopeType nemo_relay.ScopeType, opts ...nemo_relay.ScopeOption) (*nemo_relay.ScopeHandle, error) { + return nemo_relay.PushScope(name, scopeType, opts...) } // Pop removes the given scope from the scope stack and emits an End event to // all registered subscribers. Optional arguments, including -// [nemo_flow.WithScopeEndTimestamp], are forwarded to [nemo_flow.PopScope]. -func Pop(handle *nemo_flow.ScopeHandle, opts ...nemo_flow.ScopeEndOption) error { - return nemo_flow.PopScope(handle, opts...) +// [nemo_relay.WithScopeEndTimestamp], are forwarded to [nemo_relay.PopScope]. +func Pop(handle *nemo_relay.ScopeHandle, opts ...nemo_relay.ScopeEndOption) error { + return nemo_relay.PopScope(handle, opts...) } // Event emits an instantaneous Mark event within the current scope. This is a -// shorthand for [nemo_flow.EmitEvent]. Optional arguments, including -// [nemo_flow.WithEventTimestamp], are forwarded to [nemo_flow.EmitEvent]. -func Event(name string, opts ...nemo_flow.EventOption) error { - return nemo_flow.EmitEvent(name, opts...) +// shorthand for [nemo_relay.EmitEvent]. Optional arguments, including +// [nemo_relay.WithEventTimestamp], are forwarded to [nemo_relay.EmitEvent]. +func Event(name string, opts ...nemo_relay.EventOption) error { + return nemo_relay.EmitEvent(name, opts...) } // WithScope pushes a new scope and returns a cleanup function that pops it. // The cleanup function is safe to call even if the push failed (it becomes a // no-op). Use with defer for automatic scope cleanup: // -// defer scope.WithScope("name", nemo_flow.ScopeTypeAgent)() +// defer scope.WithScope("name", nemo_relay.ScopeTypeAgent)() // // Or capture the cleanup explicitly: // -// cleanup := scope.WithScope("name", nemo_flow.ScopeTypeAgent) +// cleanup := scope.WithScope("name", nemo_relay.ScopeTypeAgent) // defer cleanup() -func WithScope(name string, scopeType nemo_flow.ScopeType, opts ...nemo_flow.ScopeOption) func() { +func WithScope(name string, scopeType nemo_relay.ScopeType, opts ...nemo_relay.ScopeOption) func() { handle, err := Push(name, scopeType, opts...) if err != nil { return func() { @@ -81,12 +81,12 @@ func WithScope(name string, scopeType nemo_flow.ScopeType, opts ...nemo_flow.Sco // is a no-op. Use with defer for automatic scope cleanup when you also need // access to the scope handle: // -// handle, cleanup := scope.WithScopeHandle("name", nemo_flow.ScopeTypeAgent) +// handle, cleanup := scope.WithScopeHandle("name", nemo_relay.ScopeTypeAgent) // defer cleanup() // if handle != nil { // // use handle // } -func WithScopeHandle(name string, scopeType nemo_flow.ScopeType, opts ...nemo_flow.ScopeOption) (*nemo_flow.ScopeHandle, func()) { +func WithScopeHandle(name string, scopeType nemo_relay.ScopeType, opts ...nemo_relay.ScopeOption) (*nemo_relay.ScopeHandle, func()) { handle, err := Push(name, scopeType, opts...) if err != nil { return nil, func() { diff --git a/go/nemo_flow/scope/scope_test.go b/go/nemo_relay/scope/scope_test.go similarity index 75% rename from go/nemo_flow/scope/scope_test.go rename to go/nemo_relay/scope/scope_test.go index 9ae41c646..b7074af03 100644 --- a/go/nemo_flow/scope/scope_test.go +++ b/go/nemo_relay/scope/scope_test.go @@ -6,8 +6,8 @@ package scope_test import ( "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/scope" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/scope" ) const ( @@ -22,17 +22,17 @@ const ( func TestWithScopeNormalReturn(t *testing.T) { // Capture the current top-of-stack before pushing. - before, err := nemo_flow.GetHandle() + before, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle before: %v", err) } // WithScope pushes and returns a cleanup function. - cleanup := scope.WithScope("with_scope_test", nemo_flow.ScopeTypeAgent) + cleanup := scope.WithScope("with_scope_test", nemo_relay.ScopeTypeAgent) defer cleanup() // While inside the scope, the top-of-stack should be our new scope. - during, err := nemo_flow.GetHandle() + during, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle during: %v", err) } @@ -44,7 +44,7 @@ func TestWithScopeNormalReturn(t *testing.T) { cleanup() // After cleanup the scope should be popped. - after, err := nemo_flow.GetHandle() + after, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleAfterFailed, err) } @@ -54,15 +54,15 @@ func TestWithScopeNormalReturn(t *testing.T) { } func TestWithScopeDeferCleanup(t *testing.T) { - before, err := nemo_flow.GetHandle() + before, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleFailed, err) } func() { - defer scope.WithScope("deferred_scope", nemo_flow.ScopeTypeFunction)() + defer scope.WithScope("deferred_scope", nemo_relay.ScopeTypeFunction)() - current, err := nemo_flow.GetHandle() + current, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle inside: %v", err) } @@ -71,7 +71,7 @@ func TestWithScopeDeferCleanup(t *testing.T) { } }() - after, err := nemo_flow.GetHandle() + after, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleAfterFailed, err) } @@ -81,7 +81,7 @@ func TestWithScopeDeferCleanup(t *testing.T) { } func TestWithScopeCleanupOnPanic(t *testing.T) { - before, err := nemo_flow.GetHandle() + before, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleFailed, err) } @@ -92,10 +92,10 @@ func TestWithScopeCleanupOnPanic(t *testing.T) { t.Fatal("expected panic, got none") } }() - defer scope.WithScope("panic_scope", nemo_flow.ScopeTypeTool)() + defer scope.WithScope("panic_scope", nemo_relay.ScopeTypeTool)() // Verify the scope is pushed. - current, _ := nemo_flow.GetHandle() + current, _ := nemo_relay.GetHandle() if current.Name() != "panic_scope" { t.Fatalf("expected 'panic_scope', got '%s'", current.Name()) } @@ -104,7 +104,7 @@ func TestWithScopeCleanupOnPanic(t *testing.T) { }() // After recovering from panic, scope should be popped. - after, err := nemo_flow.GetHandle() + after, err := nemo_relay.GetHandle() if err != nil { t.Fatalf("GetHandle after panic: %v", err) } @@ -118,7 +118,7 @@ func TestWithScopeCleanupOnPanic(t *testing.T) { // ============================================================================ func TestWithScopeHandleNormalReturn(t *testing.T) { - handle, cleanup := scope.WithScopeHandle("handle_test", nemo_flow.ScopeTypeAgent) + handle, cleanup := scope.WithScopeHandle("handle_test", nemo_relay.ScopeTypeAgent) defer cleanup() if handle == nil { @@ -130,13 +130,13 @@ func TestWithScopeHandleNormalReturn(t *testing.T) { if handle.UUID() == "" { t.Fatal("expected non-empty UUID") } - if handle.Type() != nemo_flow.ScopeTypeAgent { + if handle.Type() != nemo_relay.ScopeTypeAgent { t.Fatalf("expected ScopeTypeAgent, got %d", handle.Type()) } } func TestWithScopeHandleCleanupOnPanic(t *testing.T) { - before, err := nemo_flow.GetHandle() + before, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleFailed, err) } @@ -147,7 +147,7 @@ func TestWithScopeHandleCleanupOnPanic(t *testing.T) { t.Fatal("expected panic") } }() - handle, cleanup := scope.WithScopeHandle("panic_handle", nemo_flow.ScopeTypeFunction) + handle, cleanup := scope.WithScopeHandle("panic_handle", nemo_relay.ScopeTypeFunction) defer cleanup() if handle == nil { @@ -157,7 +157,7 @@ func TestWithScopeHandleCleanupOnPanic(t *testing.T) { panic("test panic") }() - after, err := nemo_flow.GetHandle() + after, err := nemo_relay.GetHandle() if err != nil { t.Fatalf(getHandleAfterFailed, err) } @@ -169,43 +169,43 @@ func TestWithScopeHandleCleanupOnPanic(t *testing.T) { func TestWithScopeWithOptions(t *testing.T) { handle, cleanup := scope.WithScopeHandle( "opts_test", - nemo_flow.ScopeTypeFunction, - nemo_flow.WithScopeAttributes(nemo_flow.ScopeAttrParallel), + nemo_relay.ScopeTypeFunction, + nemo_relay.WithScopeAttributes(nemo_relay.ScopeAttrParallel), ) defer cleanup() if handle == nil { t.Fatal(expectedNonNilHandle) } - if handle.Attributes()&nemo_flow.ScopeAttrParallel == 0 { + if handle.Attributes()&nemo_relay.ScopeAttrParallel == 0 { t.Fatal("expected PARALLEL attribute to be set") } } func TestWithScopeNested(t *testing.T) { - before, _ := nemo_flow.GetHandle() + before, _ := nemo_relay.GetHandle() - h1, cleanup1 := scope.WithScopeHandle("outer", nemo_flow.ScopeTypeAgent) + h1, cleanup1 := scope.WithScopeHandle("outer", nemo_relay.ScopeTypeAgent) defer cleanup1() - h2, cleanup2 := scope.WithScopeHandle("inner", nemo_flow.ScopeTypeFunction) + h2, cleanup2 := scope.WithScopeHandle("inner", nemo_relay.ScopeTypeFunction) defer cleanup2() - current, _ := nemo_flow.GetHandle() + current, _ := nemo_relay.GetHandle() if current.Name() != "inner" { t.Fatalf("expected 'inner', got '%s'", current.Name()) } // Pop inner cleanup2() - current, _ = nemo_flow.GetHandle() + current, _ = nemo_relay.GetHandle() if current.Name() != "outer" { t.Fatalf("expected 'outer', got '%s'", current.Name()) } // Pop outer cleanup1() - current, _ = nemo_flow.GetHandle() + current, _ = nemo_relay.GetHandle() if current.UUID() != before.UUID() { t.Fatalf("expected root scope") } diff --git a/go/nemo_flow/scope/shorthand_test.go b/go/nemo_relay/scope/shorthand_test.go similarity index 78% rename from go/nemo_flow/scope/shorthand_test.go rename to go/nemo_relay/scope/shorthand_test.go index 36f760d66..a7ec9d12d 100644 --- a/go/nemo_flow/scope/shorthand_test.go +++ b/go/nemo_relay/scope/shorthand_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/scope" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/scope" ) const ( @@ -26,7 +26,7 @@ func TestScopeShorthands(t *testing.T) { var sawMark bool var mu sync.Mutex - if err := nemo_flow.RegisterSubscriber("scope_shortcuts_sub", func(event nemo_flow.Event) { + if err := nemo_relay.RegisterSubscriber("scope_shortcuts_sub", func(event nemo_relay.Event) { if event.Kind() == "mark" && event.Name() == "scope-mark" { mu.Lock() sawMark = true @@ -35,9 +35,9 @@ func TestScopeShorthands(t *testing.T) { }); err != nil { t.Fatalf("RegisterSubscriber failed: %v", err) } - defer nemo_flow.DeregisterSubscriber("scope_shortcuts_sub") + defer nemo_relay.DeregisterSubscriber("scope_shortcuts_sub") - handle, err := scope.Push("scope-shortcuts", nemo_flow.ScopeTypeFunction) + handle, err := scope.Push("scope-shortcuts", nemo_relay.ScopeTypeFunction) if err != nil { t.Fatalf("Push failed: %v", err) } @@ -75,7 +75,7 @@ func TestScopeShorthandsForwardTimestamps(t *testing.T) { time.Date(2026, 1, 2, 0, 0, 2, 323456000, time.UTC), } subscriberName := "scope_timestamp_sub_" + time.Now().Format("150405.000000") - if err := nemo_flow.RegisterSubscriber(subscriberName, func(event nemo_flow.Event) { + if err := nemo_relay.RegisterSubscriber(subscriberName, func(event nemo_relay.Event) { if event.Name() != scopeTimestampEventName && event.Name() != scopeTimestampMarkName { return } @@ -90,16 +90,16 @@ func TestScopeShorthandsForwardTimestamps(t *testing.T) { }); err != nil { t.Fatalf("RegisterSubscriber failed: %v", err) } - defer nemo_flow.DeregisterSubscriber(subscriberName) + defer nemo_relay.DeregisterSubscriber(subscriberName) - handle, err := scope.Push(scopeTimestampEventName, nemo_flow.ScopeTypeFunction, nemo_flow.WithScopeTimestamp(timestamps[0])) + handle, err := scope.Push(scopeTimestampEventName, nemo_relay.ScopeTypeFunction, nemo_relay.WithScopeTimestamp(timestamps[0])) if err != nil { t.Fatalf("Push failed: %v", err) } - if err := scope.Event(scopeTimestampMarkName, nemo_flow.WithEventTimestamp(timestamps[1])); err != nil { + if err := scope.Event(scopeTimestampMarkName, nemo_relay.WithEventTimestamp(timestamps[1])); err != nil { t.Fatalf("Event failed: %v", err) } - if err := scope.Pop(handle, nemo_flow.WithScopeEndTimestamp(timestamps[2])); err != nil { + if err := scope.Pop(handle, nemo_relay.WithScopeEndTimestamp(timestamps[2])); err != nil { t.Fatalf("Pop failed: %v", err) } diff --git a/go/nemo_flow/scope_local_test.go b/go/nemo_relay/scope_local_test.go similarity index 99% rename from go/nemo_flow/scope_local_test.go rename to go/nemo_relay/scope_local_test.go index 06ae04a00..b2dcef891 100644 --- a/go/nemo_flow/scope_local_test.go +++ b/go/nemo_relay/scope_local_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/scope_test.go b/go/nemo_relay/scope_test.go similarity index 99% rename from go/nemo_flow/scope_test.go rename to go/nemo_relay/scope_test.go index 89eadff9e..33744e61d 100644 --- a/go/nemo_flow/scope_test.go +++ b/go/nemo_relay/scope_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/stream.go b/go/nemo_relay/stream.go similarity index 89% rename from go/nemo_flow/stream.go rename to go/nemo_relay/stream.go index 2888e6284..46643055c 100644 --- a/go/nemo_flow/stream.go +++ b/go/nemo_relay/stream.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay /* #include @@ -9,9 +9,9 @@ package nemo_flow typedef struct FfiStream FfiStream; -extern int32_t nemo_flow_stream_next(FfiStream* stream, char** out_chunk); -extern void nemo_flow_stream_free(FfiStream* stream); -extern void nemo_flow_string_free(char* ptr); +extern int32_t nemo_relay_stream_next(FfiStream* stream, char** out_chunk); +extern void nemo_relay_stream_free(FfiStream* stream); +extern void nemo_relay_string_free(char* ptr); */ import "C" @@ -27,7 +27,7 @@ import ( // // Usage pattern: // -// stream, err := nemo_flow.LlmStreamCallExecute("chat", req, myExecFn, collector, finalizer) +// stream, err := nemo_relay.LlmStreamCallExecute("chat", req, myExecFn, collector, finalizer) // if err != nil { // log.Fatal(err) // } @@ -105,12 +105,12 @@ func (s *LlmStream) Next() (json.RawMessage, error) { } var chunk *C.char - rc := C.nemo_flow_stream_next(s.ptr, &chunk) + rc := C.nemo_relay_stream_next(s.ptr, &chunk) if rc == 1 { // Chunk available text := C.GoString(chunk) - C.nemo_flow_string_free(chunk) + C.nemo_relay_string_free(chunk) return llmStreamNextResult(int32(rc), json.RawMessage(text), s.collector, &s.finalizer) } return llmStreamNextResult(int32(rc), nil, s.collector, &s.finalizer) @@ -125,7 +125,7 @@ func (s *LlmStream) Next() (json.RawMessage, error) { // handle finalization if needed before closing early. func (s *LlmStream) Close() { if !s.closed && s.ptr != nil { - C.nemo_flow_stream_free(s.ptr) + C.nemo_relay_stream_free(s.ptr) s.ptr = nil s.closed = true s.collector = nil diff --git a/go/nemo_flow/subscribers/subscribers.go b/go/nemo_relay/subscribers/subscribers.go similarity index 60% rename from go/nemo_flow/subscribers/subscribers.go rename to go/nemo_relay/subscribers/subscribers.go index e9f4a83f8..26382c1a9 100644 --- a/go/nemo_flow/subscribers/subscribers.go +++ b/go/nemo_relay/subscribers/subscribers.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package subscribers provides shorthand access to NeMo Flow event subscriber +// Package subscribers provides shorthand access to NeMo Relay event subscriber // registration. // // Subscribers receive discriminated lifecycle events emitted by the runtime as @@ -10,10 +10,10 @@ // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/subscribers" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/subscribers" // // // Register a subscriber that logs every event. -// err := subscribers.Register("logger", func(event nemo_flow.Event) { +// err := subscribers.Register("logger", func(event nemo_relay.Event) { // fmt.Printf("[%s] %s: %s\n", event.Timestamp(), event.Kind(), event.Name()) // }) // @@ -22,35 +22,35 @@ package subscribers import ( - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) // Register registers a named event subscriber that will be called for every // lifecycle event emitted by the runtime. The name must be unique; // registering a duplicate returns an AlreadyExists error. The callback -// receives an owned [nemo_flow.Event] snapshot that is safe to retain after +// receives an owned [nemo_relay.Event] snapshot that is safe to retain after // the callback returns. This is a shorthand for -// [nemo_flow.RegisterSubscriber]. -func Register(name string, fn nemo_flow.EventSubscriberFunc) error { - return nemo_flow.RegisterSubscriber(name, fn) +// [nemo_relay.RegisterSubscriber]. +func Register(name string, fn nemo_relay.EventSubscriberFunc) error { + return nemo_relay.RegisterSubscriber(name, fn) } // Deregister removes a named event subscriber. Returns a NotFound error if no // subscriber with the given name is registered. This is a shorthand for -// [nemo_flow.DeregisterSubscriber]. +// [nemo_relay.DeregisterSubscriber]. func Deregister(name string) error { - return nemo_flow.DeregisterSubscriber(name) + return nemo_relay.DeregisterSubscriber(name) } // ScopeRegister registers a scope-local event subscriber that will be called // for lifecycle events within the given scope. This is a shorthand for -// [nemo_flow.ScopeRegisterSubscriber]. -func ScopeRegister(scopeUUID, name string, fn nemo_flow.EventSubscriberFunc) error { - return nemo_flow.ScopeRegisterSubscriber(scopeUUID, name, fn) +// [nemo_relay.ScopeRegisterSubscriber]. +func ScopeRegister(scopeUUID, name string, fn nemo_relay.EventSubscriberFunc) error { + return nemo_relay.ScopeRegisterSubscriber(scopeUUID, name, fn) } // ScopeDeregister removes a scope-local event subscriber by name. This is a -// shorthand for [nemo_flow.ScopeDeregisterSubscriber]. +// shorthand for [nemo_relay.ScopeDeregisterSubscriber]. func ScopeDeregister(scopeUUID, name string) error { - return nemo_flow.ScopeDeregisterSubscriber(scopeUUID, name) + return nemo_relay.ScopeDeregisterSubscriber(scopeUUID, name) } diff --git a/go/nemo_flow/subscribers/subscribers_test.go b/go/nemo_relay/subscribers/subscribers_test.go similarity index 73% rename from go/nemo_flow/subscribers/subscribers_test.go rename to go/nemo_relay/subscribers/subscribers_test.go index bf53f1cb7..9dcdc6da6 100644 --- a/go/nemo_flow/subscribers/subscribers_test.go +++ b/go/nemo_relay/subscribers/subscribers_test.go @@ -7,8 +7,8 @@ import ( "sync" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - subscriberspkg "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/subscribers" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + subscriberspkg "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/subscribers" ) func assertSeenStart(t *testing.T, seenStart bool) { @@ -18,12 +18,12 @@ func assertSeenStart(t *testing.T, seenStart bool) { } } -func countScopedMarks(t *testing.T, handle *nemo_flow.ScopeHandle) int { +func countScopedMarks(t *testing.T, handle *nemo_relay.ScopeHandle) int { t.Helper() var markCount int var mu sync.Mutex - if err := subscriberspkg.ScopeRegister(handle.UUID(), "subs_local", func(event nemo_flow.Event) { + if err := subscriberspkg.ScopeRegister(handle.UUID(), "subs_local", func(event nemo_relay.Event) { if event.Kind() == "mark" { mu.Lock() markCount++ @@ -33,13 +33,13 @@ func countScopedMarks(t *testing.T, handle *nemo_flow.ScopeHandle) int { t.Fatalf("ScopeRegister failed: %v", err) } - if err := nemo_flow.EmitEvent("first-mark"); err != nil { + if err := nemo_relay.EmitEvent("first-mark"); err != nil { t.Fatalf("EmitEvent failed: %v", err) } if err := subscriberspkg.ScopeDeregister(handle.UUID(), "subs_local"); err != nil { t.Fatalf("ScopeDeregister failed: %v", err) } - if err := nemo_flow.EmitEvent("second-mark"); err != nil { + if err := nemo_relay.EmitEvent("second-mark"); err != nil { t.Fatalf("EmitEvent failed: %v", err) } @@ -52,7 +52,7 @@ func TestSubscriberShorthands(t *testing.T) { var seenStart bool var mu sync.Mutex - if err := subscriberspkg.Register("subs_global", func(event nemo_flow.Event) { + if err := subscriberspkg.Register("subs_global", func(event nemo_relay.Event) { if event.Kind() == "scope" && event.ScopeCategory() == "start" { mu.Lock() seenStart = true @@ -62,11 +62,11 @@ func TestSubscriberShorthands(t *testing.T) { t.Fatalf("Register failed: %v", err) } - handle, err := nemo_flow.PushScope("subs_scope", nemo_flow.ScopeTypeAgent) + handle, err := nemo_relay.PushScope("subs_scope", nemo_relay.ScopeTypeAgent) if err != nil { t.Fatalf("PushScope failed: %v", err) } - if err := nemo_flow.PopScope(handle); err != nil { + if err := nemo_relay.PopScope(handle); err != nil { t.Fatalf("PopScope failed: %v", err) } if err := subscriberspkg.Deregister("subs_global"); err != nil { @@ -79,18 +79,18 @@ func TestSubscriberShorthands(t *testing.T) { } func TestScopeSubscriberShorthands(t *testing.T) { - stack, err := nemo_flow.NewScopeStack() + stack, err := nemo_relay.NewScopeStack() if err != nil { t.Fatalf("NewScopeStack failed: %v", err) } defer stack.Close() stack.Run(func() { - handle, err := nemo_flow.PushScope("subs_local_scope", nemo_flow.ScopeTypeAgent) + handle, err := nemo_relay.PushScope("subs_local_scope", nemo_relay.ScopeTypeAgent) if err != nil { t.Fatalf("PushScope failed: %v", err) } - defer nemo_flow.PopScope(handle) + defer nemo_relay.PopScope(handle) markCount := countScopedMarks(t, handle) if markCount != 1 { diff --git a/go/nemo_flow/test_hooks.go b/go/nemo_relay/test_hooks.go similarity index 92% rename from go/nemo_flow/test_hooks.go rename to go/nemo_relay/test_hooks.go index f7b7d24f2..44b3de37f 100644 --- a/go/nemo_flow/test_hooks.go +++ b/go/nemo_relay/test_hooks.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import "encoding/json" diff --git a/go/nemo_flow/timestamp_test.go b/go/nemo_relay/timestamp_test.go similarity index 99% rename from go/nemo_flow/timestamp_test.go rename to go/nemo_relay/timestamp_test.go index 54b8f32b4..b5d392517 100644 --- a/go/nemo_flow/timestamp_test.go +++ b/go/nemo_relay/timestamp_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/tools/tools.go b/go/nemo_relay/tools/tools.go similarity index 57% rename from go/nemo_flow/tools/tools.go rename to go/nemo_relay/tools/tools.go index 510941e36..b65cd5189 100644 --- a/go/nemo_flow/tools/tools.go +++ b/go/nemo_relay/tools/tools.go @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package tools provides shorthand access to NeMo Flow tool call operations. +// Package tools provides shorthand access to NeMo Relay tool call operations. // // It re-exports the core tool lifecycle functions (ToolCall, ToolCallEnd, // ToolCallExecute) under shorter names for convenience. // // Example usage: // -// import "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/tools" +// import "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/tools" // // // Execute a tool call with an inline function. // result, err := tools.Execute("search", json.RawMessage(`{"q":"hello"}`), @@ -22,41 +22,41 @@ package tools import ( "encoding/json" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" ) -// Call starts a tool call lifecycle and returns a [nemo_flow.ToolHandle], +// Call starts a tool call lifecycle and returns a [nemo_relay.ToolHandle], // emitting a Start event. End the call with [CallEnd]. This is a shorthand for -// [nemo_flow.ToolCall]. -func Call(name string, args json.RawMessage, opts ...nemo_flow.ToolCallOption) (*nemo_flow.ToolHandle, error) { - return nemo_flow.ToolCall(name, args, opts...) +// [nemo_relay.ToolCall]. +func Call(name string, args json.RawMessage, opts ...nemo_relay.ToolCallOption) (*nemo_relay.ToolHandle, error) { + return nemo_relay.ToolCall(name, args, opts...) } // CallEnd completes a tool call that was started with [Call], emitting an End -// event. This is a shorthand for [nemo_flow.ToolCallEnd]. -func CallEnd(handle *nemo_flow.ToolHandle, result json.RawMessage, opts ...nemo_flow.ToolCallOption) error { - return nemo_flow.ToolCallEnd(handle, result, opts...) +// event. This is a shorthand for [nemo_relay.ToolCallEnd]. +func CallEnd(handle *nemo_relay.ToolHandle, result json.RawMessage, opts ...nemo_relay.ToolCallOption) error { + return nemo_relay.ToolCallEnd(handle, result, opts...) } // Execute runs a complete tool call lifecycle with the full middleware pipeline // (conditional-execution guardrails, request intercepts, sanitize-request // guardrails, execution intercepts, fn, sanitize-response guardrails) and // returns the final result JSON. This is a shorthand for -// [nemo_flow.ToolCallExecute]. -func Execute(name string, args json.RawMessage, fn nemo_flow.ToolExecutionFunc, opts ...nemo_flow.ToolCallOption) (json.RawMessage, error) { - return nemo_flow.ToolCallExecute(name, args, fn, opts...) +// [nemo_relay.ToolCallExecute]. +func Execute(name string, args json.RawMessage, fn nemo_relay.ToolExecutionFunc, opts ...nemo_relay.ToolCallOption) (json.RawMessage, error) { + return nemo_relay.ToolCallExecute(name, args, fn, opts...) } // RequestIntercepts runs the registered tool request intercept chain on the // given arguments and returns the transformed arguments. This is a shorthand for -// [nemo_flow.ToolRequestIntercepts]. +// [nemo_relay.ToolRequestIntercepts]. func RequestIntercepts(name string, args json.RawMessage) (json.RawMessage, error) { - return nemo_flow.ToolRequestIntercepts(name, args) + return nemo_relay.ToolRequestIntercepts(name, args) } // ConditionalExecution runs the registered tool conditional execution guardrail // chain. Returns nil if all guardrails pass, or an error with the rejection -// reason if blocked. This is a shorthand for [nemo_flow.ToolConditionalExecution]. +// reason if blocked. This is a shorthand for [nemo_relay.ToolConditionalExecution]. func ConditionalExecution(name string, args json.RawMessage) error { - return nemo_flow.ToolConditionalExecution(name, args) + return nemo_relay.ToolConditionalExecution(name, args) } diff --git a/go/nemo_flow/tools/tools_shorthand_test.go b/go/nemo_relay/tools/tools_shorthand_test.go similarity index 83% rename from go/nemo_flow/tools/tools_shorthand_test.go rename to go/nemo_relay/tools/tools_shorthand_test.go index 34b098387..20767bf62 100644 --- a/go/nemo_flow/tools/tools_shorthand_test.go +++ b/go/nemo_relay/tools/tools_shorthand_test.go @@ -7,8 +7,8 @@ import ( "encoding/json" "testing" - "github.com/NVIDIA/NeMo-Flow/go/nemo_flow" - toolspkg "github.com/NVIDIA/NeMo-Flow/go/nemo_flow/tools" + "github.com/NVIDIA/NeMo-Relay/go/nemo_relay" + toolspkg "github.com/NVIDIA/NeMo-Relay/go/nemo_relay/tools" ) func TestToolShorthands(t *testing.T) { @@ -37,7 +37,7 @@ func TestToolShorthands(t *testing.T) { t.Fatalf("expected value=2, got %v", executed) } - if err := nemo_flow.RegisterToolRequestIntercept("tools_req_int", 1, false, + if err := nemo_relay.RegisterToolRequestIntercept("tools_req_int", 1, false, func(name string, args json.RawMessage) json.RawMessage { var payload map[string]interface{} _ = json.Unmarshal(args, &payload) @@ -49,7 +49,7 @@ func TestToolShorthands(t *testing.T) { t.Fatalf("RegisterToolRequestIntercept failed: %v", err) } t.Cleanup(func() { - _ = nemo_flow.DeregisterToolRequestIntercept("tools_req_int") + _ = nemo_relay.DeregisterToolRequestIntercept("tools_req_int") }) transformedArgs, err := toolspkg.RequestIntercepts("tools_req", json.RawMessage(`{"value": 3}`)) @@ -65,13 +65,13 @@ func TestToolShorthands(t *testing.T) { t.Fatalf("expected intercepted=true, got %v", intercepted) } - if err := nemo_flow.RegisterToolConditionalExecutionGuardrail("tools_cond", 1, + if err := nemo_relay.RegisterToolConditionalExecutionGuardrail("tools_cond", 1, func(name string, args json.RawMessage) *string { return nil }, ); err != nil { t.Fatalf("RegisterToolConditionalExecutionGuardrail failed: %v", err) } t.Cleanup(func() { - _ = nemo_flow.DeregisterToolConditionalExecutionGuardrail("tools_cond") + _ = nemo_relay.DeregisterToolConditionalExecutionGuardrail("tools_cond") }) if err := toolspkg.ConditionalExecution("tools_conditional", json.RawMessage(`{"value": 4}`)); err != nil { diff --git a/go/nemo_flow/tools_test.go b/go/nemo_relay/tools_test.go similarity index 99% rename from go/nemo_flow/tools_test.go rename to go/nemo_relay/tools_test.go index 18ea07925..f5e636c3c 100644 --- a/go/nemo_flow/tools_test.go +++ b/go/nemo_relay/tools_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" diff --git a/go/nemo_flow/top_level_coverage_test.go b/go/nemo_relay/top_level_coverage_test.go similarity index 99% rename from go/nemo_flow/top_level_coverage_test.go rename to go/nemo_relay/top_level_coverage_test.go index a3023fcf1..455d945f5 100644 --- a/go/nemo_flow/top_level_coverage_test.go +++ b/go/nemo_relay/top_level_coverage_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" @@ -30,7 +30,7 @@ func (p coveragePlugin) Register(pluginConfig map[string]any, ctx *PluginContext return p.register(pluginConfig, ctx) } -func TestTopLevelNemoFlowCoverage(t *testing.T) { +func TestTopLevelNemoRelayCoverage(t *testing.T) { assertScopeInputOutputCoverage(t) assertLlmStreamExecutionCoverage(t) assertCheckedValueFailureCoverage(t) diff --git a/go/nemo_flow/types.go b/go/nemo_relay/types.go similarity index 65% rename from go/nemo_flow/types.go rename to go/nemo_relay/types.go index fd7cd6a42..ca384790f 100644 --- a/go/nemo_flow/types.go +++ b/go/nemo_relay/types.go @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 // types.go defines the Go-side data types, opaque handle wrappers, and helper -// functions that correspond to the C FFI types exposed by nemo-flow-ffi. Each +// functions that correspond to the C FFI types exposed by nemo-relay-ffi. Each // handle struct wraps an opaque C pointer and uses a Go runtime finalizer to // free the underlying resource automatically when it is garbage-collected. -package nemo_flow +package nemo_relay /* #include @@ -23,69 +23,69 @@ typedef struct FfiEvent FfiEvent; typedef struct FfiStream FfiStream; // Accessors — ScopeHandle -extern char* nemo_flow_scope_handle_uuid(const FfiScopeHandle* ptr); -extern char* nemo_flow_scope_handle_name(const FfiScopeHandle* ptr); -extern int32_t nemo_flow_scope_handle_scope_type(const FfiScopeHandle* ptr); -extern uint32_t nemo_flow_scope_handle_attributes(const FfiScopeHandle* ptr); -extern char* nemo_flow_scope_handle_parent_uuid(const FfiScopeHandle* ptr); -extern char* nemo_flow_scope_handle_data(const FfiScopeHandle* ptr); -extern char* nemo_flow_scope_handle_metadata(const FfiScopeHandle* ptr); -extern void nemo_flow_scope_handle_free(FfiScopeHandle* ptr); +extern char* nemo_relay_scope_handle_uuid(const FfiScopeHandle* ptr); +extern char* nemo_relay_scope_handle_name(const FfiScopeHandle* ptr); +extern int32_t nemo_relay_scope_handle_scope_type(const FfiScopeHandle* ptr); +extern uint32_t nemo_relay_scope_handle_attributes(const FfiScopeHandle* ptr); +extern char* nemo_relay_scope_handle_parent_uuid(const FfiScopeHandle* ptr); +extern char* nemo_relay_scope_handle_data(const FfiScopeHandle* ptr); +extern char* nemo_relay_scope_handle_metadata(const FfiScopeHandle* ptr); +extern void nemo_relay_scope_handle_free(FfiScopeHandle* ptr); // Accessors — ToolHandle -extern char* nemo_flow_tool_handle_uuid(const FfiToolHandle* ptr); -extern char* nemo_flow_tool_handle_name(const FfiToolHandle* ptr); -extern uint32_t nemo_flow_tool_handle_attributes(const FfiToolHandle* ptr); -extern char* nemo_flow_tool_handle_parent_uuid(const FfiToolHandle* ptr); -extern void nemo_flow_tool_handle_free(FfiToolHandle* ptr); +extern char* nemo_relay_tool_handle_uuid(const FfiToolHandle* ptr); +extern char* nemo_relay_tool_handle_name(const FfiToolHandle* ptr); +extern uint32_t nemo_relay_tool_handle_attributes(const FfiToolHandle* ptr); +extern char* nemo_relay_tool_handle_parent_uuid(const FfiToolHandle* ptr); +extern void nemo_relay_tool_handle_free(FfiToolHandle* ptr); // Accessors — LLMHandle -extern char* nemo_flow_llm_handle_uuid(const FfiLLMHandle* ptr); -extern char* nemo_flow_llm_handle_name(const FfiLLMHandle* ptr); -extern uint32_t nemo_flow_llm_handle_attributes(const FfiLLMHandle* ptr); -extern char* nemo_flow_llm_handle_parent_uuid(const FfiLLMHandle* ptr); -extern void nemo_flow_llm_handle_free(FfiLLMHandle* ptr); +extern char* nemo_relay_llm_handle_uuid(const FfiLLMHandle* ptr); +extern char* nemo_relay_llm_handle_name(const FfiLLMHandle* ptr); +extern uint32_t nemo_relay_llm_handle_attributes(const FfiLLMHandle* ptr); +extern char* nemo_relay_llm_handle_parent_uuid(const FfiLLMHandle* ptr); +extern void nemo_relay_llm_handle_free(FfiLLMHandle* ptr); // LLMRequest -extern FfiLLMRequest* nemo_flow_llm_request_new(const char* headers_json, const char* content_json); -extern char* nemo_flow_llm_request_headers(const FfiLLMRequest* ptr); -extern char* nemo_flow_llm_request_content(const FfiLLMRequest* ptr); -extern void nemo_flow_llm_request_free(FfiLLMRequest* ptr); +extern FfiLLMRequest* nemo_relay_llm_request_new(const char* headers_json, const char* content_json); +extern char* nemo_relay_llm_request_headers(const FfiLLMRequest* ptr); +extern char* nemo_relay_llm_request_content(const FfiLLMRequest* ptr); +extern void nemo_relay_llm_request_free(FfiLLMRequest* ptr); // Event accessors -extern char* nemo_flow_event_uuid(const FfiEvent* ptr); -extern char* nemo_flow_event_name(const FfiEvent* ptr); -extern char* nemo_flow_event_kind(const FfiEvent* ptr); -extern char* nemo_flow_event_json(const FfiEvent* ptr); -extern char* nemo_flow_event_atof_version(const FfiEvent* ptr); -extern char* nemo_flow_event_scope_category(const FfiEvent* ptr); -extern char* nemo_flow_event_category(const FfiEvent* ptr); -extern uint32_t nemo_flow_event_attributes(const FfiEvent* ptr); -extern char* nemo_flow_event_attributes_json(const FfiEvent* ptr); -extern char* nemo_flow_event_category_profile(const FfiEvent* ptr); -extern char* nemo_flow_event_data(const FfiEvent* ptr); -extern char* nemo_flow_event_data_schema(const FfiEvent* ptr); -extern char* nemo_flow_event_metadata(const FfiEvent* ptr); -extern char* nemo_flow_event_timestamp(const FfiEvent* ptr); -extern char* nemo_flow_event_input(const void* ptr); -extern char* nemo_flow_event_output(const void* ptr); -extern char* nemo_flow_event_model_name(const void* ptr); -extern char* nemo_flow_event_tool_call_id(const void* ptr); -extern char* nemo_flow_event_parent_uuid(const void* ptr); -extern char* nemo_flow_event_scope_type(const void* ptr); -extern char* nemo_flow_event_annotated_request(const FfiEvent* ptr); -extern char* nemo_flow_event_annotated_response(const FfiEvent* ptr); -extern void nemo_flow_event_free(FfiEvent* ptr); +extern char* nemo_relay_event_uuid(const FfiEvent* ptr); +extern char* nemo_relay_event_name(const FfiEvent* ptr); +extern char* nemo_relay_event_kind(const FfiEvent* ptr); +extern char* nemo_relay_event_json(const FfiEvent* ptr); +extern char* nemo_relay_event_atof_version(const FfiEvent* ptr); +extern char* nemo_relay_event_scope_category(const FfiEvent* ptr); +extern char* nemo_relay_event_category(const FfiEvent* ptr); +extern uint32_t nemo_relay_event_attributes(const FfiEvent* ptr); +extern char* nemo_relay_event_attributes_json(const FfiEvent* ptr); +extern char* nemo_relay_event_category_profile(const FfiEvent* ptr); +extern char* nemo_relay_event_data(const FfiEvent* ptr); +extern char* nemo_relay_event_data_schema(const FfiEvent* ptr); +extern char* nemo_relay_event_metadata(const FfiEvent* ptr); +extern char* nemo_relay_event_timestamp(const FfiEvent* ptr); +extern char* nemo_relay_event_input(const void* ptr); +extern char* nemo_relay_event_output(const void* ptr); +extern char* nemo_relay_event_model_name(const void* ptr); +extern char* nemo_relay_event_tool_call_id(const void* ptr); +extern char* nemo_relay_event_parent_uuid(const void* ptr); +extern char* nemo_relay_event_scope_type(const void* ptr); +extern char* nemo_relay_event_annotated_request(const FfiEvent* ptr); +extern char* nemo_relay_event_annotated_response(const FfiEvent* ptr); +extern void nemo_relay_event_free(FfiEvent* ptr); // String free -extern void nemo_flow_string_free(char* ptr); +extern void nemo_relay_string_free(char* ptr); // Last error -extern const char* nemo_flow_last_error(); +extern const char* nemo_relay_last_error(); // Stream -extern void nemo_flow_stream_free(FfiStream* stream); -extern int32_t nemo_flow_stream_next(FfiStream* stream, char** out_chunk); +extern void nemo_relay_stream_free(FfiStream* stream); +extern int32_t nemo_relay_stream_next(FfiStream* stream, char** out_chunk); */ import "C" @@ -102,7 +102,7 @@ func newLLMRequestFromPtr(ptr unsafe.Pointer) *LLMRequest { r := &LLMRequest{ptr: (*C.FfiLLMRequest)(ptr)} runtime.SetFinalizer(r, func(r *LLMRequest) { if r.ptr != nil { - C.nemo_flow_llm_request_free(r.ptr) + C.nemo_relay_llm_request_free(r.ptr) r.ptr = nil } }) @@ -114,7 +114,7 @@ var newLLMRequestFunc = func(headersJSON, contentJSON string) *LLMRequest { cContent := C.CString(contentJSON) defer C.free(unsafe.Pointer(cHeaders)) defer C.free(unsafe.Pointer(cContent)) - return newLLMRequestFromPtr(unsafe.Pointer(C.nemo_flow_llm_request_new(cHeaders, cContent))) + return newLLMRequestFromPtr(unsafe.Pointer(C.nemo_relay_llm_request_new(cHeaders, cContent))) } // ScopeType represents the kind of execution scope. It mirrors the core Rust @@ -207,7 +207,7 @@ func newScopeHandle(ptr *C.FfiScopeHandle) *ScopeHandle { h := &ScopeHandle{ptr: ptr} runtime.SetFinalizer(h, func(h *ScopeHandle) { if h.ptr != nil { - C.nemo_flow_scope_handle_free(h.ptr) + C.nemo_relay_scope_handle_free(h.ptr) h.ptr = nil } }) @@ -215,35 +215,35 @@ func newScopeHandle(ptr *C.FfiScopeHandle) *ScopeHandle { } // UUID returns the unique identifier for this scope. -func (h *ScopeHandle) UUID() string { return goString(C.nemo_flow_scope_handle_uuid(h.ptr)) } +func (h *ScopeHandle) UUID() string { return goString(C.nemo_relay_scope_handle_uuid(h.ptr)) } // Name returns the human-readable name of this scope. -func (h *ScopeHandle) Name() string { return goString(C.nemo_flow_scope_handle_name(h.ptr)) } +func (h *ScopeHandle) Name() string { return goString(C.nemo_relay_scope_handle_name(h.ptr)) } // Type returns the ScopeType of this scope. func (h *ScopeHandle) Type() ScopeType { - return ScopeType(C.nemo_flow_scope_handle_scope_type(h.ptr)) + return ScopeType(C.nemo_relay_scope_handle_scope_type(h.ptr)) } // Attributes returns the attribute bitflags for this scope. func (h *ScopeHandle) Attributes() uint32 { - return uint32(C.nemo_flow_scope_handle_attributes(h.ptr)) + return uint32(C.nemo_relay_scope_handle_attributes(h.ptr)) } // ParentUUID returns the UUID of the parent scope, or an empty string if this // is a root scope. func (h *ScopeHandle) ParentUUID() string { - return goStringOpt(C.nemo_flow_scope_handle_parent_uuid(h.ptr)) + return goStringOpt(C.nemo_relay_scope_handle_parent_uuid(h.ptr)) } // Data returns the optional data JSON payload attached to this scope. func (h *ScopeHandle) Data() json.RawMessage { - return goJSONOpt(C.nemo_flow_scope_handle_data(h.ptr)) + return goJSONOpt(C.nemo_relay_scope_handle_data(h.ptr)) } // Metadata returns the optional metadata JSON payload attached to this scope. func (h *ScopeHandle) Metadata() json.RawMessage { - return goJSONOpt(C.nemo_flow_scope_handle_metadata(h.ptr)) + return goJSONOpt(C.nemo_relay_scope_handle_metadata(h.ptr)) } // ToolHandle wraps an opaque C pointer to a tool call handle. It is returned @@ -260,7 +260,7 @@ func newToolHandle(ptr *C.FfiToolHandle) *ToolHandle { h := &ToolHandle{ptr: ptr} runtime.SetFinalizer(h, func(h *ToolHandle) { if h.ptr != nil { - C.nemo_flow_tool_handle_free(h.ptr) + C.nemo_relay_tool_handle_free(h.ptr) h.ptr = nil } }) @@ -268,19 +268,19 @@ func newToolHandle(ptr *C.FfiToolHandle) *ToolHandle { } // UUID returns the unique identifier for this tool call. -func (h *ToolHandle) UUID() string { return goString(C.nemo_flow_tool_handle_uuid(h.ptr)) } +func (h *ToolHandle) UUID() string { return goString(C.nemo_relay_tool_handle_uuid(h.ptr)) } // Name returns the name of the tool being called. -func (h *ToolHandle) Name() string { return goString(C.nemo_flow_tool_handle_name(h.ptr)) } +func (h *ToolHandle) Name() string { return goString(C.nemo_relay_tool_handle_name(h.ptr)) } // Attributes returns the attribute bitflags for this tool call. func (h *ToolHandle) Attributes() uint32 { - return uint32(C.nemo_flow_tool_handle_attributes(h.ptr)) + return uint32(C.nemo_relay_tool_handle_attributes(h.ptr)) } // ParentUUID returns the UUID of the parent scope for this tool call. func (h *ToolHandle) ParentUUID() string { - return goStringOpt(C.nemo_flow_tool_handle_parent_uuid(h.ptr)) + return goStringOpt(C.nemo_relay_tool_handle_parent_uuid(h.ptr)) } // LLMHandle wraps an opaque C pointer to an LLM call handle. It is returned @@ -297,7 +297,7 @@ func newLLMHandle(ptr *C.FfiLLMHandle) *LLMHandle { h := &LLMHandle{ptr: ptr} runtime.SetFinalizer(h, func(h *LLMHandle) { if h.ptr != nil { - C.nemo_flow_llm_handle_free(h.ptr) + C.nemo_relay_llm_handle_free(h.ptr) h.ptr = nil } }) @@ -305,19 +305,19 @@ func newLLMHandle(ptr *C.FfiLLMHandle) *LLMHandle { } // UUID returns the unique identifier for this LLM call. -func (h *LLMHandle) UUID() string { return goString(C.nemo_flow_llm_handle_uuid(h.ptr)) } +func (h *LLMHandle) UUID() string { return goString(C.nemo_relay_llm_handle_uuid(h.ptr)) } // Name returns the name of the LLM being called. -func (h *LLMHandle) Name() string { return goString(C.nemo_flow_llm_handle_name(h.ptr)) } +func (h *LLMHandle) Name() string { return goString(C.nemo_relay_llm_handle_name(h.ptr)) } // Attributes returns the attribute bitflags for this LLM call. func (h *LLMHandle) Attributes() uint32 { - return uint32(C.nemo_flow_llm_handle_attributes(h.ptr)) + return uint32(C.nemo_relay_llm_handle_attributes(h.ptr)) } // ParentUUID returns the UUID of the parent scope for this LLM call. func (h *LLMHandle) ParentUUID() string { - return goStringOpt(C.nemo_flow_llm_handle_parent_uuid(h.ptr)) + return goStringOpt(C.nemo_relay_llm_handle_parent_uuid(h.ptr)) } // LLMRequest wraps an opaque C pointer to an LLM request. It contains the @@ -334,7 +334,7 @@ type LLMRequest struct { // // Example: // -// req := nemo_flow.NewLLMRequest( +// req := nemo_relay.NewLLMRequest( // map[string]interface{}{"Authorization": "Bearer tok"}, // map[string]interface{}{"model": "gpt-4", "messages": []interface{}{}}, // ) @@ -346,12 +346,12 @@ func NewLLMRequest(headers map[string]interface{}, content interface{}) *LLMRequ // Headers returns the request headers as a JSON object. func (r *LLMRequest) Headers() json.RawMessage { - return goJSONOpt(C.nemo_flow_llm_request_headers(r.ptr)) + return goJSONOpt(C.nemo_relay_llm_request_headers(r.ptr)) } // Content returns the request content as raw JSON. func (r *LLMRequest) Content() json.RawMessage { - return goJSONOpt(C.nemo_flow_llm_request_content(r.ptr)) + return goJSONOpt(C.nemo_relay_llm_request_content(r.ptr)) } // Event is the common interface implemented by ATOF lifecycle event variants. @@ -419,136 +419,136 @@ func (e eventBase) UUID() string { if e.snapshot != nil { return e.snapshot.uuid } - return goString(C.nemo_flow_event_uuid(e.ptr)) + return goString(C.nemo_relay_event_uuid(e.ptr)) } func (e eventBase) Name() string { if e.snapshot != nil { return e.snapshot.name } - return goStringOpt(C.nemo_flow_event_name(e.ptr)) + return goStringOpt(C.nemo_relay_event_name(e.ptr)) } func (e eventBase) Kind() string { if e.snapshot != nil { return e.snapshot.kind } - return goStringOpt(C.nemo_flow_event_kind(e.ptr)) + return goStringOpt(C.nemo_relay_event_kind(e.ptr)) } func (e eventBase) ATOFVersion() string { if e.snapshot != nil { return e.snapshot.atofVersion } - return goStringOpt(C.nemo_flow_event_atof_version(e.ptr)) + return goStringOpt(C.nemo_relay_event_atof_version(e.ptr)) } func (e eventBase) ScopeCategory() string { if e.snapshot != nil { return e.snapshot.scopeCategory } - return goStringOpt(C.nemo_flow_event_scope_category(e.ptr)) + return goStringOpt(C.nemo_relay_event_scope_category(e.ptr)) } func (e eventBase) Category() string { if e.snapshot != nil { return e.snapshot.category } - return goStringOpt(C.nemo_flow_event_category(e.ptr)) + return goStringOpt(C.nemo_relay_event_category(e.ptr)) } func (e eventBase) ScopeType() string { if e.snapshot != nil { return e.snapshot.scopeType } - return goStringOpt((*C.char)(C.nemo_flow_event_scope_type(unsafe.Pointer(e.ptr)))) + return goStringOpt((*C.char)(C.nemo_relay_event_scope_type(unsafe.Pointer(e.ptr)))) } func (e eventBase) Attributes() uint32 { if e.snapshot != nil { return e.snapshot.attributes } - return uint32(C.nemo_flow_event_attributes(e.ptr)) + return uint32(C.nemo_relay_event_attributes(e.ptr)) } func (e eventBase) AttributesJSON() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.attributesJSON) } - return goJSONOpt(C.nemo_flow_event_attributes_json(e.ptr)) + return goJSONOpt(C.nemo_relay_event_attributes_json(e.ptr)) } func (e eventBase) CategoryProfile() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.categoryProfile) } - return goJSONOpt(C.nemo_flow_event_category_profile(e.ptr)) + return goJSONOpt(C.nemo_relay_event_category_profile(e.ptr)) } func (e eventBase) Data() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.data) } - return goJSONOpt(C.nemo_flow_event_data(e.ptr)) + return goJSONOpt(C.nemo_relay_event_data(e.ptr)) } func (e eventBase) DataSchema() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.dataSchema) } - return goJSONOpt(C.nemo_flow_event_data_schema(e.ptr)) + return goJSONOpt(C.nemo_relay_event_data_schema(e.ptr)) } func (e eventBase) Metadata() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.metadata) } - return goJSONOpt(C.nemo_flow_event_metadata(e.ptr)) + return goJSONOpt(C.nemo_relay_event_metadata(e.ptr)) } func (e eventBase) Timestamp() string { if e.snapshot != nil { return e.snapshot.timestamp } - return goString(C.nemo_flow_event_timestamp(e.ptr)) + return goString(C.nemo_relay_event_timestamp(e.ptr)) } func (e eventBase) Input() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.input) } - return goJSONOpt((*C.char)(C.nemo_flow_event_input(unsafe.Pointer(e.ptr)))) + return goJSONOpt((*C.char)(C.nemo_relay_event_input(unsafe.Pointer(e.ptr)))) } func (e eventBase) Output() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.output) } - return goJSONOpt((*C.char)(C.nemo_flow_event_output(unsafe.Pointer(e.ptr)))) + return goJSONOpt((*C.char)(C.nemo_relay_event_output(unsafe.Pointer(e.ptr)))) } func (e eventBase) ModelName() string { if e.snapshot != nil { return e.snapshot.modelName } - return goStringOpt((*C.char)(C.nemo_flow_event_model_name(unsafe.Pointer(e.ptr)))) + return goStringOpt((*C.char)(C.nemo_relay_event_model_name(unsafe.Pointer(e.ptr)))) } func (e eventBase) ToolCallID() string { if e.snapshot != nil { return e.snapshot.toolCallID } - return goStringOpt((*C.char)(C.nemo_flow_event_tool_call_id(unsafe.Pointer(e.ptr)))) + return goStringOpt((*C.char)(C.nemo_relay_event_tool_call_id(unsafe.Pointer(e.ptr)))) } func (e eventBase) ParentUUID() string { if e.snapshot != nil { return e.snapshot.parentUUID } - return goStringOpt((*C.char)(C.nemo_flow_event_parent_uuid(unsafe.Pointer(e.ptr)))) + return goStringOpt((*C.char)(C.nemo_relay_event_parent_uuid(unsafe.Pointer(e.ptr)))) } func (e eventBase) AnnotatedRequest() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.annotatedRequest) } - return goJSONOpt(C.nemo_flow_event_annotated_request(e.ptr)) + return goJSONOpt(C.nemo_relay_event_annotated_request(e.ptr)) } func (e eventBase) AnnotatedResponse() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.annotatedResponse) } - return goJSONOpt(C.nemo_flow_event_annotated_response(e.ptr)) + return goJSONOpt(C.nemo_relay_event_annotated_response(e.ptr)) } func (e eventBase) JSON() json.RawMessage { if e.snapshot != nil { return cloneJSON(e.snapshot.eventJSON) } - return goJSONOpt(C.nemo_flow_event_json(e.ptr)) + return goJSONOpt(C.nemo_relay_event_json(e.ptr)) } func (e eventBase) MarshalJSON() ([]byte, error) { raw := e.JSON() @@ -567,28 +567,28 @@ type MarkEvent struct{ eventBase } func newEvent(ptr *C.FfiEvent) Event { base := eventBase{ snapshot: &eventSnapshot{ - kind: goStringOpt(C.nemo_flow_event_kind(ptr)), - atofVersion: goStringOpt(C.nemo_flow_event_atof_version(ptr)), - scopeCategory: goStringOpt(C.nemo_flow_event_scope_category(ptr)), - category: goStringOpt(C.nemo_flow_event_category(ptr)), - uuid: goString(C.nemo_flow_event_uuid(ptr)), - name: goStringOpt(C.nemo_flow_event_name(ptr)), - parentUUID: goStringOpt((*C.char)(C.nemo_flow_event_parent_uuid(unsafe.Pointer(ptr)))), - scopeType: goStringOpt((*C.char)(C.nemo_flow_event_scope_type(unsafe.Pointer(ptr)))), - attributes: uint32(C.nemo_flow_event_attributes(ptr)), - attributesJSON: goJSONOpt(C.nemo_flow_event_attributes_json(ptr)), - categoryProfile: goJSONOpt(C.nemo_flow_event_category_profile(ptr)), - data: goJSONOpt(C.nemo_flow_event_data(ptr)), - dataSchema: goJSONOpt(C.nemo_flow_event_data_schema(ptr)), - metadata: goJSONOpt(C.nemo_flow_event_metadata(ptr)), - timestamp: goString(C.nemo_flow_event_timestamp(ptr)), - input: goJSONOpt((*C.char)(C.nemo_flow_event_input(unsafe.Pointer(ptr)))), - output: goJSONOpt((*C.char)(C.nemo_flow_event_output(unsafe.Pointer(ptr)))), - modelName: goStringOpt((*C.char)(C.nemo_flow_event_model_name(unsafe.Pointer(ptr)))), - toolCallID: goStringOpt((*C.char)(C.nemo_flow_event_tool_call_id(unsafe.Pointer(ptr)))), - annotatedRequest: goJSONOpt(C.nemo_flow_event_annotated_request(ptr)), - annotatedResponse: goJSONOpt(C.nemo_flow_event_annotated_response(ptr)), - eventJSON: goJSONOpt(C.nemo_flow_event_json(ptr)), + kind: goStringOpt(C.nemo_relay_event_kind(ptr)), + atofVersion: goStringOpt(C.nemo_relay_event_atof_version(ptr)), + scopeCategory: goStringOpt(C.nemo_relay_event_scope_category(ptr)), + category: goStringOpt(C.nemo_relay_event_category(ptr)), + uuid: goString(C.nemo_relay_event_uuid(ptr)), + name: goStringOpt(C.nemo_relay_event_name(ptr)), + parentUUID: goStringOpt((*C.char)(C.nemo_relay_event_parent_uuid(unsafe.Pointer(ptr)))), + scopeType: goStringOpt((*C.char)(C.nemo_relay_event_scope_type(unsafe.Pointer(ptr)))), + attributes: uint32(C.nemo_relay_event_attributes(ptr)), + attributesJSON: goJSONOpt(C.nemo_relay_event_attributes_json(ptr)), + categoryProfile: goJSONOpt(C.nemo_relay_event_category_profile(ptr)), + data: goJSONOpt(C.nemo_relay_event_data(ptr)), + dataSchema: goJSONOpt(C.nemo_relay_event_data_schema(ptr)), + metadata: goJSONOpt(C.nemo_relay_event_metadata(ptr)), + timestamp: goString(C.nemo_relay_event_timestamp(ptr)), + input: goJSONOpt((*C.char)(C.nemo_relay_event_input(unsafe.Pointer(ptr)))), + output: goJSONOpt((*C.char)(C.nemo_relay_event_output(unsafe.Pointer(ptr)))), + modelName: goStringOpt((*C.char)(C.nemo_relay_event_model_name(unsafe.Pointer(ptr)))), + toolCallID: goStringOpt((*C.char)(C.nemo_relay_event_tool_call_id(unsafe.Pointer(ptr)))), + annotatedRequest: goJSONOpt(C.nemo_relay_event_annotated_request(ptr)), + annotatedResponse: goJSONOpt(C.nemo_relay_event_annotated_response(ptr)), + eventJSON: goJSONOpt(C.nemo_relay_event_json(ptr)), }, } switch base.Kind() { @@ -609,7 +609,7 @@ func goString(cstr *C.char) string { return "" } s := C.GoString(cstr) - C.nemo_flow_string_free(cstr) + C.nemo_relay_string_free(cstr) return s } @@ -624,7 +624,7 @@ func goJSONOpt(cstr *C.char) json.RawMessage { return nil } s := C.GoString(cstr) - C.nemo_flow_string_free(cstr) + C.nemo_relay_string_free(cstr) return json.RawMessage(s) } diff --git a/go/nemo_flow/types_test.go b/go/nemo_relay/types_test.go similarity index 99% rename from go/nemo_flow/types_test.go rename to go/nemo_relay/types_test.go index c320617b7..49cadf159 100644 --- a/go/nemo_flow/types_test.go +++ b/go/nemo_relay/types_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "testing" diff --git a/go/nemo_flow/wrapper_coverage_test.go b/go/nemo_relay/wrapper_coverage_test.go similarity index 98% rename from go/nemo_flow/wrapper_coverage_test.go rename to go/nemo_relay/wrapper_coverage_test.go index 88de7948a..70eb9dd26 100644 --- a/go/nemo_flow/wrapper_coverage_test.go +++ b/go/nemo_relay/wrapper_coverage_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package nemo_flow +package nemo_relay import ( "encoding/json" @@ -201,8 +201,8 @@ func TestWrapperHelpersCoverNilAndErrorPaths(t *testing.T) { if got := goJSONOpt(nil); got != nil { t.Fatalf("expected nil json for nil goJSONOpt, got %v", got) } - if err := lastError(); err == nil || !strings.Contains(err.Error(), "unknown nemo_flow error") { - t.Fatalf("expected unknown nemo_flow error fallback, got %v", err) + if err := lastError(); err == nil || !strings.Contains(err.Error(), "unknown nemo_relay error") { + t.Fatalf("expected unknown nemo_relay error fallback, got %v", err) } } diff --git a/integrations/coding-agents/README.md b/integrations/coding-agents/README.md index 56b6cc9f6..2b8cdaa6e 100644 --- a/integrations/coding-agents/README.md +++ b/integrations/coding-agents/README.md @@ -3,10 +3,10 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow Coding-Agent Observability Integrations +# NeMo Relay Coding-Agent Observability Integrations This directory contains hook integration bundles for coding agents that should -be observed by `nemo-flow`. +be observed by `nemo-relay`. The gateway combines two observability paths: @@ -16,7 +16,7 @@ The gateway combines two observability paths: provider traffic. Hook integrations preserve each coding agent's canonical hook payload. They do -not wrap the payload in a shared NeMo Flow envelope. Gateway-specific settings +not wrap the payload in a shared NeMo Relay envelope. Gateway-specific settings travel through the transparent wrapper, hook command arguments, HTTP headers, environment variables, or shared TOML config. @@ -25,57 +25,57 @@ environment variables, or shared TOML config. - `claude-code/` installs Claude Code hook entries targeting `POST /hooks/claude-code`. - `codex/` installs Codex hook entries targeting `POST /hooks/codex` and enables - `features.hooks = true`. Use `nemo-flow run` or a gateway provider alias + `features.hooks = true`. Use `nemo-relay run` or a gateway provider alias for Codex LLM gateway routing. - `cursor/` installs a Cursor `.cursor/hooks.json` bundle targeting `POST /hooks/cursor`. - Hermes does not require a static bundle in this directory. The setup wizard - (`nemo-flow config`) merges hook commands into `.hermes/config.yaml` when + (`nemo-relay config`) merges hook commands into `.hermes/config.yaml` when hermes is selected. - `hermes/` contains a native Hermes Python plugin prototype that writes ATIF from Hermes plugin middleware without running the gateway HTTP process. ## Transparent Setup -Build or install the gateway binary so `nemo-flow` is on `PATH`. +Build or install the gateway binary so `nemo-relay` is on `PATH`. Prefer the wrapper. It starts a gateway on a dynamic `127.0.0.1` port, injects temporary hook and gateway configuration, runs the agent, and shuts the gateway down when the agent exits. ```bash -nemo-flow run -- claude -nemo-flow run -- codex -nemo-flow run -- cursor-agent -nemo-flow run -- hermes +nemo-relay run -- claude +nemo-relay run -- codex +nemo-relay run -- cursor-agent +nemo-relay run -- hermes ``` Use `--agent claude|codex|cursor|hermes` when a wrapper hides the agent command name. Use `--dry-run --print` to inspect generated config without launching. -Use `nemo-flow doctor` to inspect environment, config, agent commands, hook +Use `nemo-relay doctor` to inspect environment, config, agent commands, hook readiness, observability outputs, and shell completions. Scope the report to one agent when troubleshooting launch readiness: ```bash -nemo-flow doctor -nemo-flow doctor codex -nemo-flow doctor hermes --json +nemo-relay doctor +nemo-relay doctor codex +nemo-relay doctor hermes --json ``` The command is read-only: it reports missing ATIF directories, hook files, and agent commands instead of creating or patching them. -Hermes transparent runs export the dynamic `NEMO_FLOW_GATEWAY_URL`, but Hermes +Hermes transparent runs export the dynamic `NEMO_RELAY_GATEWAY_URL`, but Hermes hooks must already be present in `.hermes/config.yaml` before they can call the -gateway. The setup wizard (`nemo-flow config`) writes that file for you when +gateway. The setup wizard (`nemo-relay config`) writes that file for you when you select hermes. -Shared TOML config is loaded from `/etc/nemo-flow/config.toml`, then nearest -project `.nemo-flow/config.toml`, then -`$XDG_CONFIG_HOME/nemo-flow/config.toml` or -`~/.config/nemo-flow/config.toml`. +Shared TOML config is loaded from `/etc/nemo-relay/config.toml`, then nearest +project `.nemo-relay/config.toml`, then +`$XDG_CONFIG_HOME/nemo-relay/config.toml` or +`~/.config/nemo-relay/config.toml`. ```toml [agents.codex] @@ -86,7 +86,7 @@ command = "hermes" ``` Observability exporters are configured in `plugins.toml`. Run -`nemo-flow plugins edit --project` to create `.nemo-flow/plugins.toml`, or +`nemo-relay plugins edit --project` to create `.nemo-relay/plugins.toml`, or write the plugin config directly: ```toml @@ -98,7 +98,7 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" [components.config.openinference] enabled = true @@ -107,8 +107,8 @@ endpoint = "http://127.0.0.1:4318/v1/traces" ## Hook Forwarding -Hooks call `nemo-flow hook-forward ` with the canonical hook payload on -stdin. The wrapper injects `NEMO_FLOW_GATEWAY_URL` so the same hook command +Hooks call `nemo-relay hook-forward ` with the canonical hook payload on +stdin. The wrapper injects `NEMO_RELAY_GATEWAY_URL` so the same hook command reaches the ephemeral per-run gateway; hermes hooks fall back to an embedded `--gateway-url` when running outside the wrapper. @@ -150,7 +150,7 @@ Run a coding-agent session that starts, uses one tool, and ends. Then confirm that ATIF was written: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` The gateway writes `.atif.json` when it receives a session-end hook diff --git a/integrations/coding-agents/claude-code/.claude-plugin/plugin.json b/integrations/coding-agents/claude-code/.claude-plugin/plugin.json index 3baf01628..236e60abf 100644 --- a/integrations/coding-agents/claude-code/.claude-plugin/plugin.json +++ b/integrations/coding-agents/claude-code/.claude-plugin/plugin.json @@ -1,16 +1,16 @@ { - "name": "nemo-flow-claude-code-observability", + "name": "nemo-relay-claude-code-observability", "version": "0.1.0", - "description": "Claude Code hooks that forward canonical lifecycle payloads to nemo-flow-sidecar.", + "description": "Claude Code hooks that forward canonical lifecycle payloads to nemo-relay-sidecar.", "author": { "name": "NVIDIA Corporation and Affiliates", - "url": "https://github.com/NVIDIA/NeMo-Flow" + "url": "https://github.com/NVIDIA/NeMo-Relay" }, - "homepage": "https://github.com/NVIDIA/NeMo-Flow", - "repository": "https://github.com/NVIDIA/NeMo-Flow", + "homepage": "https://github.com/NVIDIA/NeMo-Relay", + "repository": "https://github.com/NVIDIA/NeMo-Relay", "license": "Apache-2.0", "keywords": [ - "nemo-flow", + "nemo-relay", "claude-code", "hooks", "observability" diff --git a/integrations/coding-agents/claude-code/README.md b/integrations/coding-agents/claude-code/README.md index 67ab2df06..3380f656c 100644 --- a/integrations/coding-agents/claude-code/README.md +++ b/integrations/coding-agents/claude-code/README.md @@ -3,10 +3,10 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow Claude Code Observability +# NeMo Relay Claude Code Observability This package contains Claude Code hook entries that forward canonical Claude -Code hook JSON to `nemo-flow` at `/hooks/claude-code`. +Code hook JSON to `nemo-relay` at `/hooks/claude-code`. Claude Code is the supported Claude integration target. Claude application, Claude web, and Claude desktop sessions are unsupported unless they expose the @@ -16,7 +16,7 @@ same local hook and gateway controls as Claude Code. - `.claude-plugin/plugin.json` describes the Claude Code hook package. - `hooks/hooks.json` contains hook entries that run - `nemo-flow hook-forward claude`. + `nemo-relay hook-forward claude`. ## Captured Events @@ -28,12 +28,12 @@ provide private LLM correlation hints for gateway requests. ## Transparent Setup -Build or install the gateway binary so `nemo-flow` is on `PATH`. +Build or install the gateway binary so `nemo-relay` is on `PATH`. Run Claude Code through the wrapper: ```bash -nemo-flow run -- claude +nemo-relay run -- claude ``` The wrapper starts a per-invocation gateway on a dynamic localhost port, @@ -44,7 +44,7 @@ when Claude exits. Inspect the launch without starting Claude Code: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- claude @@ -52,16 +52,16 @@ nemo-flow run \ ## Shared Config -Use `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Use `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.claude] command = "claude" ``` -Configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -72,13 +72,13 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" ``` Then run: ```bash -nemo-flow run --agent claude +nemo-relay run --agent claude ``` ## Standalone Gateway @@ -87,7 +87,7 @@ Use the long-running gateway only when you do not want to launch Claude Code through the wrapper. Start the gateway in one terminal: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Launch Claude Code from another terminal with the gateway environment: @@ -106,7 +106,7 @@ Run a Claude Code session that starts, uses one simple tool, and ends. Confirm that ATIF was written: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` For a direct endpoint smoke test against a manually started gateway: @@ -114,14 +114,14 @@ For a direct endpoint smoke test against a manually started gateway: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-claude","hook_event_name":"SessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward claude --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward claude --fail-closed ``` If hooks arrive but LLM spans are missing, confirm the Claude Code process was -started by `nemo-flow run` or has `ANTHROPIC_BASE_URL` set to the +started by `nemo-relay run` or has `ANTHROPIC_BASE_URL` set to the gateway URL. If LLM spans are present but attached to the top-level agent instead of a -subagent, include `x-nemo-flow-subagent-id` on gateway requests or share +subagent, include `x-nemo-relay-subagent-id` on gateway requests or share `conversation_id`, `generation_id`, or `request_id` values between hook payloads and provider requests. diff --git a/integrations/coding-agents/claude-code/hooks/hooks.json b/integrations/coding-agents/claude-code/hooks/hooks.json index d8f0e8259..e8ec49335 100644 --- a/integrations/coding-agents/claude-code/hooks/hooks.json +++ b/integrations/coding-agents/claude-code/hooks/hooks.json @@ -5,7 +5,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -16,7 +16,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -28,7 +28,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -40,7 +40,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -52,7 +52,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -64,7 +64,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -75,7 +75,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -86,7 +86,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -97,7 +97,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -108,7 +108,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -119,7 +119,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -130,7 +130,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] @@ -141,7 +141,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward claude", + "command": "nemo-relay hook-forward claude", "timeout": 30 } ] diff --git a/integrations/coding-agents/codex/.codex-plugin/plugin.json b/integrations/coding-agents/codex/.codex-plugin/plugin.json index 77a2eb572..fefc0f801 100644 --- a/integrations/coding-agents/codex/.codex-plugin/plugin.json +++ b/integrations/coding-agents/codex/.codex-plugin/plugin.json @@ -1,31 +1,31 @@ { - "name": "nemo-flow-codex-observability", + "name": "nemo-relay-codex-observability", "version": "0.1.0", - "description": "Codex hooks that forward canonical lifecycle payloads to nemo-flow-sidecar.", + "description": "Codex hooks that forward canonical lifecycle payloads to nemo-relay-sidecar.", "author": { "name": "NVIDIA Corporation and Affiliates", - "url": "https://github.com/NVIDIA/NeMo-Flow" + "url": "https://github.com/NVIDIA/NeMo-Relay" }, - "homepage": "https://github.com/NVIDIA/NeMo-Flow", - "repository": "https://github.com/NVIDIA/NeMo-Flow", + "homepage": "https://github.com/NVIDIA/NeMo-Relay", + "repository": "https://github.com/NVIDIA/NeMo-Relay", "license": "Apache-2.0", "keywords": [ - "nemo-flow", + "nemo-relay", "codex", "hooks", "observability" ], "hooks": "../hooks/hooks.json", "interface": { - "displayName": "NeMo Flow Codex Observability", - "shortDescription": "Forward Codex lifecycle hooks to a local NeMo Flow sidecar.", - "longDescription": "Installs command hooks that preserve Codex hook payloads and forward them to nemo-flow-sidecar for agent, subagent, tool, and lifecycle observability. Full LLM capture also requires sidecar provider routing.", + "displayName": "NeMo Relay Codex Observability", + "shortDescription": "Forward Codex lifecycle hooks to a local NeMo Relay sidecar.", + "longDescription": "Installs command hooks that preserve Codex hook payloads and forward them to nemo-relay-sidecar for agent, subagent, tool, and lifecycle observability. Full LLM capture also requires sidecar provider routing.", "developerName": "NVIDIA", "category": "Coding", "capabilities": [ "Read" ], - "websiteURL": "https://github.com/NVIDIA/NeMo-Flow", + "websiteURL": "https://github.com/NVIDIA/NeMo-Relay", "brandColor": "#76B900" } } diff --git a/integrations/coding-agents/codex/README.md b/integrations/coding-agents/codex/README.md index fb6d6731f..20e47d2a1 100644 --- a/integrations/coding-agents/codex/README.md +++ b/integrations/coding-agents/codex/README.md @@ -3,10 +3,10 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow Codex Observability +# NeMo Relay Codex Observability This package contains Codex hook entries that forward canonical Codex hook JSON -to `nemo-flow` at `/hooks/codex`. +to `nemo-relay` at `/hooks/codex`. Codex CLI is fully supported for local sessions. Codex GUI or app sessions are supported only when they run locally and honor the same hook/plugin config and @@ -20,7 +20,7 @@ provider alias surface the gateway relies on). - `.codex-plugin/plugin.json` describes the Codex plugin package. - `hooks/hooks.json` contains hook entries that run - `nemo-flow hook-forward codex`. + `nemo-relay hook-forward codex`. ## Captured Events @@ -36,24 +36,24 @@ hook entries into `.codex/hooks.json`. ## Transparent Setup -Build or install the gateway binary so `nemo-flow` is on `PATH`. +Build or install the gateway binary so `nemo-relay` is on `PATH`. Run Codex through the wrapper: ```bash -nemo-flow run -- codex +nemo-relay run -- codex ``` The wrapper starts a per-invocation gateway on a dynamic localhost port, enables Codex hooks with CLI config overrides, injects hook commands that use -`NEMO_FLOW_GATEWAY_URL`, and points Codex at a temporary `nemo-flow-openai` +`NEMO_RELAY_GATEWAY_URL`, and points Codex at a temporary `nemo-relay-openai` provider alias that uses the gateway URL while preserving Codex's OpenAI auth path. Inspect the launch without starting Codex: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- codex @@ -61,16 +61,16 @@ nemo-flow run \ ## Shared Config -Use `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Use `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.codex] command = "codex" ``` -Configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -81,13 +81,13 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" ``` Then run: ```bash -nemo-flow run --agent codex +nemo-relay run --agent codex ``` ## Standalone Gateway @@ -96,17 +96,17 @@ Use the long-running gateway only when you do not want to launch Codex through the wrapper. Start the gateway manually: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Then configure local Codex to use a gateway provider alias instead of overriding the reserved built-in `openai` provider: ```toml -model_provider = "nemo-flow-openai" +model_provider = "nemo-relay-openai" -[model_providers.nemo-flow-openai] -name = "NeMo Flow OpenAI" +[model_providers.nemo-relay-openai] +name = "NeMo Relay OpenAI" base_url = "http://127.0.0.1:4040" wire_api = "responses" requires_openai_auth = true @@ -119,7 +119,7 @@ Run a Codex session that starts, uses one simple tool, and ends. Confirm that ATIF was written: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` For a direct endpoint smoke test against a manually started gateway: @@ -127,13 +127,13 @@ For a direct endpoint smoke test against a manually started gateway: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-codex","hook_event_name":"sessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward codex --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward codex --fail-closed ``` If hooks arrive but LLM spans are missing, confirm Codex was started by -`nemo-flow run` or that the active provider points to the gateway URL. +`nemo-relay run` or that the active provider points to the gateway URL. If LLM spans are present but attached to the top-level agent instead of a -subagent, include `x-nemo-flow-subagent-id` on gateway requests or share +subagent, include `x-nemo-relay-subagent-id` on gateway requests or share `conversation_id`, `generation_id`, or `request_id` values between hook payloads and provider requests. diff --git a/integrations/coding-agents/codex/hooks/hooks.json b/integrations/coding-agents/codex/hooks/hooks.json index ae1a1fce6..7f6e9b400 100644 --- a/integrations/coding-agents/codex/hooks/hooks.json +++ b/integrations/coding-agents/codex/hooks/hooks.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -29,7 +29,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -41,7 +41,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -53,7 +53,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -65,7 +65,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -76,7 +76,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -87,7 +87,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -98,7 +98,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -109,7 +109,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -120,7 +120,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -131,7 +131,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] @@ -142,7 +142,7 @@ "hooks": [ { "type": "command", - "command": "nemo-flow hook-forward codex", + "command": "nemo-relay hook-forward codex", "timeout": 30 } ] diff --git a/integrations/coding-agents/cursor/.cursor/hooks.json b/integrations/coding-agents/cursor/.cursor/hooks.json index c2dd52edf..07b463696 100644 --- a/integrations/coding-agents/cursor/.cursor/hooks.json +++ b/integrations/coding-agents/cursor/.cursor/hooks.json @@ -4,91 +4,91 @@ "hooks": { "sessionStart": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "beforeSubmitPrompt": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "preToolUse": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "beforeShellExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "beforeMCPExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "postToolUse": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "afterShellExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "afterMCPExecution": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "subagentStart": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "subagentStop": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "afterAgentResponse": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "afterAgentThought": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "preCompact": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "stop": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ], "sessionEnd": [ { - "command": "nemo-flow hook-forward cursor", + "command": "nemo-relay hook-forward cursor", "timeout": 30 } ] diff --git a/integrations/coding-agents/cursor/README.md b/integrations/coding-agents/cursor/README.md index edaf5d3bb..0735899dd 100644 --- a/integrations/coding-agents/cursor/README.md +++ b/integrations/coding-agents/cursor/README.md @@ -3,11 +3,11 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo Flow Cursor Observability +# NeMo Relay Cursor Observability This package is a Cursor hook bundle, not an official Cursor plugin package. It contains `.cursor/hooks.json` entries that forward canonical Cursor hook JSON to -`nemo-flow` at `/hooks/cursor`. +`nemo-relay` at `/hooks/cursor`. Cursor GUI or IDE sessions can provide agent, subagent, tool, shell, MCP, file, and response lifecycle events through `.cursor/hooks.json`. Complete LLM @@ -17,20 +17,20 @@ configuration. Cursor CLI builds require `.cursor/hooks.json` to set top-level `"version": 1` and use direct command entries such as -`{"command": "nemo-flow hook-forward cursor", "timeout": 30}`. The nested +`{"command": "nemo-relay hook-forward cursor", "timeout": 30}`. The nested `{"matcher": "*", "hooks": [...]}` group shape used by Claude Code and Codex does not fire in Cursor CLI. > [!WARNING] > Cursor CLI hook coverage is narrower than Cursor IDE hook coverage. Current > headless CLI builds can emit fewer hook events than Cursor IDE sessions. Treat -> missing CLI hook events as a Cursor CLI limitation after `nemo-flow doctor +> missing CLI hook events as a Cursor CLI limitation after `nemo-relay doctor > cursor` confirms the hook file uses the direct versioned shape. ## Files - `.cursor/hooks.json` contains hook entries that run - `nemo-flow hook-forward cursor`. + `nemo-relay hook-forward cursor`. ## Captured Events @@ -42,20 +42,20 @@ and `stop` as scope, tool, or mark events. `beforeSubmitPrompt`, hints for gateway requests. Tool events preserve shell and MCP payloads in metadata and attach to -`subagent.id`, `subagent_id`, or `x-nemo-flow-subagent-id` when one is present. +`subagent.id`, `subagent_id`, or `x-nemo-relay-subagent-id` when one is present. ## Transparent Setup -Build or install the gateway binary so `nemo-flow` is on `PATH`. +Build or install the gateway binary so `nemo-relay` is on `PATH`. Run Cursor through the wrapper: ```bash -nemo-flow run -- cursor-agent +nemo-relay run -- cursor-agent ``` The wrapper starts a per-invocation gateway on a dynamic localhost port, -temporarily merges NeMo Flow hooks into project `.cursor/hooks.json`, launches +temporarily merges NeMo Relay hooks into project `.cursor/hooks.json`, launches Cursor, and restores or removes the temporary hook file when Cursor exits. The temporary Cursor hook file is written with top-level `"version": 1` and direct command entries. @@ -63,7 +63,7 @@ command entries. Inspect the launch without starting Cursor: ```bash -nemo-flow run \ +nemo-relay run \ --dry-run \ --print \ -- cursor-agent @@ -71,8 +71,8 @@ nemo-flow run \ ## Shared Config -Use `.nemo-flow/config.toml` for project defaults or -`~/.config/nemo-flow/config.toml` for user defaults: +Use `.nemo-relay/config.toml` for project defaults or +`~/.config/nemo-relay/config.toml` for user defaults: ```toml [agents.cursor] @@ -80,8 +80,8 @@ command = "cursor-agent" patch_restore_hooks = true ``` -Configure observability with `nemo-flow plugins edit --project` or -`.nemo-flow/plugins.toml`: +Configure observability with `nemo-relay plugins edit --project` or +`.nemo-relay/plugins.toml`: ```toml version = 1 @@ -92,13 +92,13 @@ enabled = true [components.config.atif] enabled = true -output_directory = ".nemo-flow/atif" +output_directory = ".nemo-relay/atif" ``` Then run: ```bash -nemo-flow run --agent cursor +nemo-relay run --agent cursor ``` ## Standalone Gateway @@ -107,7 +107,7 @@ Use the long-running gateway only when you do not want to launch Cursor through the wrapper (e.g., the Cursor GUI). Start the gateway manually: ```bash -nemo-flow --bind 127.0.0.1:4040 +nemo-relay --bind 127.0.0.1:4040 ``` Then point Cursor provider traffic at `http://127.0.0.1:4040` where Cursor @@ -120,7 +120,7 @@ Run a Cursor session that starts, uses one simple tool, and ends. Confirm that ATIF was written: ```bash -ls .nemo-flow/atif +ls .nemo-relay/atif ``` For a direct endpoint smoke test against a manually started gateway: @@ -128,15 +128,15 @@ For a direct endpoint smoke test against a manually started gateway: ```bash curl -f http://127.0.0.1:4040/healthz printf '{"session_id":"smoke-cursor","hook_event_name":"sessionStart"}' \ - | NEMO_FLOW_GATEWAY_URL=http://127.0.0.1:4040 nemo-flow hook-forward cursor --fail-closed + | NEMO_RELAY_GATEWAY_URL=http://127.0.0.1:4040 nemo-relay hook-forward cursor --fail-closed ``` If Cursor CLI hooks do not fire for the active `cursor-agent` version, treat that CLI mode as hook-limited after confirming `.cursor/hooks.json` uses direct versioned entries. User-managed Cursor hook files can be checked with -`nemo-flow doctor cursor`. +`nemo-relay doctor cursor`. If LLM spans are present but attached to the top-level agent instead of a -subagent, include `x-nemo-flow-subagent-id` on gateway requests or share +subagent, include `x-nemo-relay-subagent-id` on gateway requests or share `conversation_id`, `generation_id`, or `request_id` values between hook payloads and provider requests. diff --git a/integrations/openclaw/README.md b/integrations/openclaw/README.md index f31ebe9e1..e86878e83 100644 --- a/integrations/openclaw/README.md +++ b/integrations/openclaw/README.md @@ -3,11 +3,11 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# nemo-flow-openclaw +# nemo-relay-openclaw -`nemo-flow-openclaw` is the NeMo Flow observability plugin package for -OpenClaw. It converts supported OpenClaw hook events into NeMo Flow sessions, -LLM spans, tool spans, and lifecycle marks that the generic NeMo Flow +`nemo-relay-openclaw` is the NeMo Relay observability plugin package for +OpenClaw. It converts supported OpenClaw hook events into NeMo Relay sessions, +LLM spans, tool spans, and lifecycle marks that the generic NeMo Relay observability component can export as ATIF JSON, OpenTelemetry spans, and OpenInference/Phoenix spans. The same generic plugin config path can initialize Adaptive components for hook-backed telemetry learning. @@ -15,12 +15,12 @@ Adaptive components for hook-backed telemetry learning. This public OpenClaw plugin package uses OpenClaw public hooks. It does not rewrite OpenClaw tool execution, provider routing, policy decisions, or model requests. For middleware-backed behavior that changes execution, use the -patch-based OpenClaw integration from the NeMo Flow repository. +patch-based OpenClaw integration from the NeMo Relay repository. ## Why Use It? - Observe OpenClaw sessions without patching OpenClaw. -- Export OpenClaw activity into NeMo Flow observability formats. +- Export OpenClaw activity into NeMo Relay observability formats. - Preserve OpenClaw's agent, tool, and LLM lifecycle context where public hooks expose enough data. - Keep ambiguous LLM timing attribution visible through diagnostic marks instead @@ -28,45 +28,45 @@ patch-based OpenClaw integration from the NeMo Flow repository. ## What You Get -- OpenClaw plugin ID `nemo-flow`. -- Generic NeMo Flow plugin initialization through `config.plugins`. +- OpenClaw plugin ID `nemo-relay`. +- Generic NeMo Relay plugin initialization through `config.plugins`. - ATIF JSON export through the built-in `observability` component. - Adaptive plugin initialization through `config.plugins`. - Optional OpenTelemetry OTLP export. - Optional OpenInference/Phoenix OTLP export. - Bounded LLM replay correlation across supported OpenClaw hooks. - Tool span replay with conservative privacy defaults. -- Admin-scoped `nemoFlow.status` gateway health method. +- Admin-scoped `nemoRelay.status` gateway health method. ## Installation Install the package directly in a Node.js/OpenClaw environment: ```bash -npm install nemo-flow-openclaw +npm install nemo-relay-openclaw ``` For OpenClaw-managed installation, use the OpenClaw CLI: ```bash -openclaw plugins install npm:nemo-flow-openclaw +openclaw plugins install npm:nemo-relay-openclaw openclaw gateway restart ``` -OpenClaw uses the package `nemo-flow-openclaw` for installation and the plugin -manifest ID `nemo-flow` for configuration. +OpenClaw uses the package `nemo-relay-openclaw` for installation and the plugin +manifest ID `nemo-relay` for configuration. ## Configure the Plugin -Enable the `nemo-flow` plugin ID, grant conversation hook access, and place the -OpenClaw plugin configuration under `plugins.entries["nemo-flow"].config`: +Enable the `nemo-relay` plugin ID, grant conversation hook access, and place the +OpenClaw plugin configuration under `plugins.entries["nemo-relay"].config`: ```json { "plugins": { - "allow": ["nemo-flow"], + "allow": ["nemo-relay"], "entries": { - "nemo-flow": { + "nemo-relay": { "enabled": true, "hooks": { "allowConversationAccess": true @@ -85,19 +85,19 @@ OpenClaw plugin configuration under `plugins.entries["nemo-flow"].config`: "atif": { "enabled": true, "agent_name": "openclaw", - "output_directory": "./nemo-flow-atif" + "output_directory": "./nemo-relay-atif" }, "opentelemetry": { "enabled": false, "transport": "http_binary", "endpoint": "http://localhost:4318/v1/traces", - "service_name": "openclaw-nemo-flow" + "service_name": "openclaw-nemo-relay" }, "openinference": { "enabled": false, "transport": "http_binary", "endpoint": "http://localhost:6006/v1/traces", - "service_name": "openclaw-nemo-flow" + "service_name": "openclaw-nemo-relay" } } }, @@ -143,14 +143,14 @@ you point them at a collector or Phoenix endpoint. Remove exporter sections you do not use, or set their `enabled` fields to `false`. - `plugins.allow` controls OpenClaw plugin trust and loading. -- `plugins.entries["nemo-flow"].enabled` controls whether OpenClaw starts this +- `plugins.entries["nemo-relay"].enabled` controls whether OpenClaw starts this plugin entry. - `hooks.allowConversationAccess` lets trusted non-bundled plugins receive conversation-sensitive hook payloads such as LLM prompts, LLM responses, agent finalization messages, and tool payloads. -- `config.enabled` disables or enables the NeMo Flow OpenClaw wrapper without +- `config.enabled` disables or enables the NeMo Relay OpenClaw wrapper without removing the plugin entry. `config.backend` currently supports only `hooks`. -- `config.plugins` is the generic NeMo Flow plugin configuration document. Use +- `config.plugins` is the generic NeMo Relay plugin configuration document. Use this object to configure built-in components such as `observability` and `adaptive`. - `config.plugins.components[].config.atif` writes ATIF trajectory JSON files. @@ -162,7 +162,7 @@ do not use, or set their `enabled` fields to `false`. is `true`. - `config.plugins.components[]` entries with `kind: "adaptive"` initialize the Adaptive plugin. In hook-backed OpenClaw mode, adaptive telemetry can consume - replayed NeMo Flow events, while request-rewrite features such as adaptive + replayed NeMo Relay events, while request-rewrite features such as adaptive hints require a managed execution path. - `config.capture` controls prompt, response, tool argument, and tool result capture. Tool arguments and tool results are stripped by default because they @@ -172,17 +172,17 @@ do not use, or set their `enabled` fields to `false`. keeps correlation records for 600 seconds, and keeps at most 32 records per correlation key. -Fields inside `config.plugins` are NeMo Flow generic plugin configuration, so +Fields inside `config.plugins` are NeMo Relay generic plugin configuration, so they use `snake_case` regardless of language. For the full exporter field list, -see the NeMo Flow Observability Plugin schema in the top-level NeMo Flow -documentation at [nvidia.github.io/NeMo-Flow](https://nvidia.github.io/NeMo-Flow/). +see the NeMo Relay Observability Plugin schema in the top-level NeMo Relay +documentation at [nvidia.github.io/NeMo-Relay](https://nvidia.github.io/NeMo-Relay/). ## Verify the Integration Inspect the plugin runtime: ```bash -openclaw plugins inspect nemo-flow --runtime --json +openclaw plugins inspect nemo-relay --runtime --json ``` Run an OpenClaw session with the plugin enabled, then verify the configured @@ -195,16 +195,16 @@ sink: endpoint. The plugin also registers the `operator.admin` scoped gateway method -`nemoFlow.status`. If your CLI is already paired with admin-capable gateway +`nemoRelay.status`. If your CLI is already paired with admin-capable gateway access, run: ```bash -openclaw gateway call nemoFlow.status --json +openclaw gateway call nemoRelay.status --json ``` ## Current Limits -The plugin maps supported OpenClaw hook events into NeMo Flow telemetry without +The plugin maps supported OpenClaw hook events into NeMo Relay telemetry without changing OpenClaw execution behavior. It does not change OpenClaw tool execution, provider routing, policy decisions, @@ -219,8 +219,8 @@ latency. ## Troubleshooting If the plugin does not load, verify the package was installed with -`openclaw plugins install`, `plugins.allow` includes `nemo-flow`, -`plugins.entries["nemo-flow"].enabled` is not disabled, and the gateway was +`openclaw plugins install`, `plugins.allow` includes `nemo-relay`, +`plugins.entries["nemo-relay"].enabled` is not disabled, and the gateway was restarted after configuration changes. If conversation payloads are missing, verify @@ -239,9 +239,9 @@ Run these commands from the repository root: ```bash npm ci --ignore-scripts -npm run build --workspace=nemo-flow-openclaw -npm run typecheck --workspace=nemo-flow-openclaw -npm test --workspace=nemo-flow-openclaw +npm run build --workspace=nemo-relay-openclaw +npm run typecheck --workspace=nemo-relay-openclaw +npm test --workspace=nemo-relay-openclaw ``` The CI-equivalent repo recipe is: @@ -253,18 +253,18 @@ just --set ci true test-openclaw Check the package payload before changing package metadata or entrypoints: ```bash -npm run pack:check --workspace=nemo-flow-openclaw +npm run pack:check --workspace=nemo-relay-openclaw ``` -`npm run build --workspace=nemo-flow-openclaw` emits production files under +`npm run build --workspace=nemo-relay-openclaw` emits production files under `integrations/openclaw/dist/`. Tests compile to `integrations/openclaw/.test-dist/` from the sibling `integrations/openclaw/test/` directory so test artifacts do not enter the installable package or production source tree. -The optional live smoke test requires a working installed `nemo-flow-node` +The optional live smoke test requires a working installed `nemo-relay-node` binding: ```bash -npm run test:live --workspace=nemo-flow-openclaw +npm run test:live --workspace=nemo-relay-openclaw ``` diff --git a/integrations/openclaw/index.ts b/integrations/openclaw/index.ts index 380cef708..123a5d1e6 100644 --- a/integrations/openclaw/index.ts +++ b/integrations/openclaw/index.ts @@ -7,20 +7,17 @@ * This file should stay small: it declares the public plugin metadata and hands * registration to the runtime-state module, where lifecycle and hook wiring live. */ -import { - definePluginEntry, - type OpenClawPluginApi, -} from "openclaw/plugin-sdk/plugin-entry"; +import { definePluginEntry, type OpenClawPluginApi } from 'openclaw/plugin-sdk/plugin-entry'; -import { nemoFlowConfigSchema } from "./src/config.js"; -import { registerNemoFlowPlugin } from "./src/runtime-state.js"; +import { nemoRelayConfigSchema } from './src/config.js'; +import { registerNemoRelayPlugin } from './src/runtime-state.js'; export default definePluginEntry({ - id: "nemo-flow", - name: "NeMo Flow Observability", - description: "ATIF, OpenInference, and OpenTelemetry telemetry through NeMo Flow", - configSchema: nemoFlowConfigSchema, + id: 'nemo-relay', + name: 'NeMo Relay Observability', + description: 'ATIF, OpenInference, and OpenTelemetry telemetry through NeMo Relay', + configSchema: nemoRelayConfigSchema, register(api: OpenClawPluginApi) { - registerNemoFlowPlugin(api); + registerNemoRelayPlugin(api); }, }); diff --git a/integrations/openclaw/openclaw.plugin.json b/integrations/openclaw/openclaw.plugin.json index b497b87c3..d27396093 100644 --- a/integrations/openclaw/openclaw.plugin.json +++ b/integrations/openclaw/openclaw.plugin.json @@ -1,14 +1,12 @@ { - "id": "nemo-flow", - "name": "NeMo Flow Observability", - "description": "ATIF, OpenInference, and OpenTelemetry telemetry through NeMo Flow.", + "id": "nemo-relay", + "name": "NeMo Relay Observability", + "description": "ATIF, OpenInference, and OpenTelemetry telemetry through NeMo Relay.", "activation": { "onStartup": true }, "contracts": { - "agentToolCallMiddleware": [ - "pi" - ] + "agentToolCallMiddleware": ["pi"] }, "configSchema": { "type": "object", @@ -17,19 +15,17 @@ "enabled": { "type": "boolean", "default": true, - "description": "Enables the NeMo Flow OpenClaw hook replay plugin." + "description": "Enables the NeMo Relay OpenClaw hook replay plugin." }, "backend": { "type": "string", - "enum": [ - "hooks" - ], + "enum": ["hooks"], "default": "hooks", "description": "Hook replay backend implementation. Only the hook-backed backend is supported." }, "plugins": { - "$ref": "#/$defs/nemoFlowPluginConfig", - "description": "Generic NeMo Flow plugin configuration document. Use the observability component to configure ATIF, OpenTelemetry, and OpenInference exporters." + "$ref": "#/$defs/nemoRelayPluginConfig", + "description": "Generic NeMo Relay plugin configuration document. Use the observability component to configure ATIF, OpenTelemetry, and OpenInference exporters." }, "capture": { "type": "object", @@ -85,14 +81,14 @@ } }, "$defs": { - "nemoFlowPluginConfig": { + "nemoRelayPluginConfig": { "type": "object", "additionalProperties": true, "properties": { "version": { "type": "integer", "default": 1, - "description": "NeMo Flow generic plugin config version." + "description": "NeMo Relay generic plugin config version." }, "components": { "type": "array", @@ -100,7 +96,7 @@ "$ref": "#/$defs/pluginComponent" }, "default": [], - "description": "NeMo Flow plugin components to validate and initialize." + "description": "NeMo Relay plugin components to validate and initialize." }, "policy": { "$ref": "#/$defs/pluginPolicy", @@ -114,14 +110,12 @@ }, "pluginComponent": { "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "additionalProperties": false, "properties": { "kind": { "type": "string", - "description": "Registered NeMo Flow plugin kind." + "description": "Registered NeMo Relay plugin kind." }, "enabled": { "type": "boolean", @@ -152,13 +146,9 @@ }, "unsupportedBehavior": { "type": "string", - "enum": [ - "ignore", - "warn", - "error" - ] + "enum": ["ignore", "warn", "error"] } }, - "description": "Configuration for the NeMo Flow OpenClaw hook replay plugin." + "description": "Configuration for the NeMo Relay OpenClaw hook replay plugin." } } diff --git a/integrations/openclaw/package.json b/integrations/openclaw/package.json index a94efe1b4..e70fa8ef2 100644 --- a/integrations/openclaw/package.json +++ b/integrations/openclaw/package.json @@ -1,11 +1,11 @@ { - "name": "nemo-flow-openclaw", + "name": "nemo-relay-openclaw", "version": "0.3.0", - "description": "NeMo Flow-authored observability plugin for OpenClaw.", + "description": "NeMo Relay-authored observability plugin for OpenClaw.", "type": "module", "repository": { "type": "git", - "url": "https://github.com/NVIDIA/NeMo-Flow", + "url": "https://github.com/NVIDIA/NeMo-Relay", "directory": "integrations/openclaw" }, "main": "./dist/index.js", @@ -63,7 +63,7 @@ "openclaw": ">=2026.5.12" }, "dependencies": { - "nemo-flow-node": "0.3.0" + "nemo-relay-node": "0.3.0" }, "devDependencies": { "@types/node": "^20.19.0", diff --git a/integrations/openclaw/scripts/build-test.mjs b/integrations/openclaw/scripts/build-test.mjs index f247966be..b5ad519a0 100644 --- a/integrations/openclaw/scripts/build-test.mjs +++ b/integrations/openclaw/scripts/build-test.mjs @@ -9,21 +9,21 @@ * Tests compile to .test-dist so generated test artifacts stay out of the * installable package and production dist directory. */ -import { spawnSync } from "node:child_process"; -import { rmSync } from "node:fs"; -import { createRequire } from "node:module"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import { spawnSync } from 'node:child_process'; +import { rmSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const require = createRequire(import.meta.url); -const tsc = require.resolve("typescript/bin/tsc"); +const tsc = require.resolve('typescript/bin/tsc'); -rmSync(path.join(packageRoot, ".test-dist"), { recursive: true, force: true }); +rmSync(path.join(packageRoot, '.test-dist'), { recursive: true, force: true }); -const result = spawnSync(process.execPath, [tsc, "-p", "tsconfig.test.json"], { +const result = spawnSync(process.execPath, [tsc, '-p', 'tsconfig.test.json'], { cwd: packageRoot, - stdio: "inherit", + stdio: 'inherit', }); process.exit(result.status ?? 1); diff --git a/integrations/openclaw/scripts/build.mjs b/integrations/openclaw/scripts/build.mjs index eaf172376..a6d1e7893 100644 --- a/integrations/openclaw/scripts/build.mjs +++ b/integrations/openclaw/scripts/build.mjs @@ -9,21 +9,21 @@ * The script removes stale output and invokes the workspace TypeScript compiler * directly so npm lifecycle behavior stays predictable in CI and local builds. */ -import { spawnSync } from "node:child_process"; -import { rmSync } from "node:fs"; -import { createRequire } from "node:module"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import { spawnSync } from 'node:child_process'; +import { rmSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const require = createRequire(import.meta.url); -const tsc = require.resolve("typescript/bin/tsc"); +const tsc = require.resolve('typescript/bin/tsc'); -rmSync(path.join(packageRoot, "dist"), { recursive: true, force: true }); +rmSync(path.join(packageRoot, 'dist'), { recursive: true, force: true }); -const result = spawnSync(process.execPath, [tsc, "-p", "tsconfig.build.json"], { +const result = spawnSync(process.execPath, [tsc, '-p', 'tsconfig.build.json'], { cwd: packageRoot, - stdio: "inherit", + stdio: 'inherit', }); process.exit(result.status ?? 1); diff --git a/integrations/openclaw/scripts/check-pack-payload.mjs b/integrations/openclaw/scripts/check-pack-payload.mjs index 01322662f..12716ae63 100644 --- a/integrations/openclaw/scripts/check-pack-payload.mjs +++ b/integrations/openclaw/scripts/check-pack-payload.mjs @@ -10,13 +10,13 @@ * generated dist files, and OpenClaw manifest entries must be packed, while * tests, maps, and test build output must stay out of the package. */ -import { spawnSync } from "node:child_process"; -import { readdirSync, readFileSync, statSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import { spawnSync } from 'node:child_process'; +import { readdirSync, readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -const npm = process.platform === "win32" ? "npm.cmd" : "npm"; +const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const npmExecPath = process.env.npm_execpath; /** Fail the pack check with a precise validation message. */ @@ -30,15 +30,15 @@ function assert(condition, message) { function run(command, args, options = {}) { const result = spawnSync(command, args, { cwd: packageRoot, - encoding: "utf8", + encoding: 'utf8', ...options, }); if (result.status !== 0) { if (result.error) { process.stderr.write(`${result.error.message}\n`); } - process.stderr.write(result.stderr ?? ""); - throw new Error(`${command} ${args.join(" ")} failed`); + process.stderr.write(result.stderr ?? ''); + throw new Error(`${command} ${args.join(' ')} failed`); } return result; } @@ -49,18 +49,18 @@ function runNpm(args, options = {}) { return run(process.execPath, [npmExecPath, ...args], options); } return run(npm, args, { - shell: process.platform === "win32", + shell: process.platform === 'win32', ...options, }); } /** Normalize npm pack paths to POSIX style without a leading ./ prefix. */ function normalizePackagePath(value) { - return value.replace(/^\.\//, "").replaceAll("\\", "/"); + return value.replace(/^\.\//, '').replaceAll('\\', '/'); } /** Recursively list files below a package-local directory. */ -function walkFiles(root, prefix = "") { +function walkFiles(root, prefix = '') { const absoluteRoot = path.join(packageRoot, root, prefix); const output = []; for (const entry of readdirSync(absoluteRoot)) { @@ -75,31 +75,29 @@ function walkFiles(root, prefix = "") { return output.sort(); } -runNpm(["run", "build"], { stdio: "inherit" }); +runNpm(['run', 'build'], { stdio: 'inherit' }); -const pack = runNpm(["pack", "--dry-run", "--json", "--ignore-scripts"]); +const pack = runNpm(['pack', '--dry-run', '--json', '--ignore-scripts']); const packInfo = JSON.parse(pack.stdout)[0]; -assert(packInfo, "npm pack did not return package metadata"); +assert(packInfo, 'npm pack did not return package metadata'); -const productionSources = walkFiles("src").filter( - (file) => file.endsWith(".ts") && !file.endsWith(".test.ts"), -); +const productionSources = walkFiles('src').filter((file) => file.endsWith('.ts') && !file.endsWith('.test.ts')); const packedFiles = new Set(packInfo.files.map((file) => normalizePackagePath(file.path))); -const packageJson = JSON.parse(readFileSync(path.join(packageRoot, "package.json"), "utf8")); +const packageJson = JSON.parse(readFileSync(path.join(packageRoot, 'package.json'), 'utf8')); const declaredFiles = new Set(packageJson.files ?? []); assert( - packageJson.repository?.url === "https://github.com/NVIDIA/NeMo-Flow", + packageJson.repository?.url === 'https://github.com/NVIDIA/NeMo-Relay', 'package repository.url must match the GitHub Actions provenance source repository', ); assert( - packageJson.repository?.directory === "integrations/openclaw", - "package repository.directory must identify the OpenClaw workspace", + packageJson.repository?.directory === 'integrations/openclaw', + 'package repository.directory must identify the OpenClaw workspace', ); for (const entry of declaredFiles) { assert( - !(entry.startsWith("src/") && entry.includes("*")), + !(entry.startsWith('src/') && entry.includes('*')), `package files should explicitly allowlist production sources, not ${entry}`, ); } @@ -110,12 +108,12 @@ for (const source of productionSources) { } const requiredFiles = [ - "package.json", - "README.md", - "index.ts", - "openclaw.plugin.json", - "dist/index.js", - "dist/index.d.ts", + 'package.json', + 'README.md', + 'index.ts', + 'openclaw.plugin.json', + 'dist/index.js', + 'dist/index.d.ts', ]; for (const file of requiredFiles) { @@ -132,24 +130,24 @@ for (const entry of packageJson.openclaw?.runtimeExtensions ?? []) { assert(packedFiles.has(file), `openclaw.runtimeExtensions entry ${entry} is not packed`); } -assert(packageJson.openclaw?.compat?.pluginApi, "openclaw.compat.pluginApi is required"); -assert(packageJson.openclaw?.compat?.minGatewayVersion, "openclaw.compat.minGatewayVersion is required"); -assert(packageJson.openclaw?.build?.openclawVersion, "openclaw.build.openclawVersion is required"); -assert(packageJson.openclaw?.build?.pluginSdkVersion, "openclaw.build.pluginSdkVersion is required"); +assert(packageJson.openclaw?.compat?.pluginApi, 'openclaw.compat.pluginApi is required'); +assert(packageJson.openclaw?.compat?.minGatewayVersion, 'openclaw.compat.minGatewayVersion is required'); +assert(packageJson.openclaw?.build?.openclawVersion, 'openclaw.build.openclawVersion is required'); +assert(packageJson.openclaw?.build?.pluginSdkVersion, 'openclaw.build.pluginSdkVersion is required'); for (const file of packedFiles) { - assert(!file.startsWith("test/"), `packed package includes test artifact ${file}`); - assert(!file.startsWith(".test-dist/"), `packed package includes test output ${file}`); - assert(!file.endsWith(".map"), `packed package includes source/declaration map ${file}`); + assert(!file.startsWith('test/'), `packed package includes test artifact ${file}`); + assert(!file.startsWith('.test-dist/'), `packed package includes test output ${file}`); + assert(!file.endsWith('.map'), `packed package includes source/declaration map ${file}`); } -const builtDistFiles = new Set(walkFiles("dist")); +const builtDistFiles = new Set(walkFiles('dist')); for (const file of builtDistFiles) { assert(packedFiles.has(file), `built dist file ${file} is not packed`); } for (const file of packedFiles) { - if (file.startsWith("dist/")) { + if (file.startsWith('dist/')) { assert(builtDistFiles.has(file), `packed dist file ${file} was not produced by the fresh build`); } } diff --git a/integrations/openclaw/scripts/test-live.mjs b/integrations/openclaw/scripts/test-live.mjs index 4407cce60..4ea8225bb 100644 --- a/integrations/openclaw/scripts/test-live.mjs +++ b/integrations/openclaw/scripts/test-live.mjs @@ -3,19 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { spawnSync } from "node:child_process"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const result = spawnSync(process.execPath, ["--test", ".test-dist/test/live-smoke.test.js"], { +const result = spawnSync(process.execPath, ['--test', '.test-dist/test/live-smoke.test.js'], { cwd: packageRoot, env: { ...process.env, - NEMO_FLOW_OPENCLAW_LIVE_SMOKE: "1", + NEMO_RELAY_OPENCLAW_LIVE_SMOKE: '1', }, - stdio: "inherit", + stdio: 'inherit', }); process.exit(result.status ?? 1); diff --git a/integrations/openclaw/src/config.ts b/integrations/openclaw/src/config.ts index a38f9d0c2..f4998d1ed 100644 --- a/integrations/openclaw/src/config.ts +++ b/integrations/openclaw/src/config.ts @@ -7,11 +7,11 @@ * Keep defaults and validation here so runtime code can consume one normalized * config shape and avoid repeating defensive checks around optional plugin JSON. */ -import type { OpenClawPluginConfigSchema } from "openclaw/plugin-sdk/plugin-entry"; +import type { OpenClawPluginConfigSchema } from 'openclaw/plugin-sdk/plugin-entry'; -import manifest from "../openclaw.plugin.json" with { type: "json" }; +import manifest from '../openclaw.plugin.json' with { type: 'json' }; -export type BackendKind = "hooks"; +export type BackendKind = 'hooks'; export type CaptureConfig = { includePrompts: boolean; @@ -26,30 +26,30 @@ export type CorrelationConfig = { maxRecordsPerKey: number; }; -export type NemoFlowPluginHostConfig = { +export type NemoRelayPluginHostConfig = { version: number; components: unknown[]; [key: string]: unknown; }; -export type NemoFlowHookBackendConfig = { +export type NemoRelayHookBackendConfig = { enabled: boolean; backend: BackendKind; - plugins: NemoFlowPluginHostConfig; + plugins: NemoRelayPluginHostConfig; capture: CaptureConfig; correlation: CorrelationConfig; }; -const DEFAULT_PLUGIN_HOST_CONFIG: NemoFlowPluginHostConfig = { +const DEFAULT_PLUGIN_HOST_CONFIG: NemoRelayPluginHostConfig = { version: 1, components: [], }; -export const NEMO_FLOW_OPENCLAW_JSON_SCHEMA = manifest.configSchema; +export const NEMO_RELAY_OPENCLAW_JSON_SCHEMA = manifest.configSchema; -export const DEFAULT_CONFIG: NemoFlowHookBackendConfig = { +export const DEFAULT_CONFIG: NemoRelayHookBackendConfig = { enabled: true, - backend: "hooks", + backend: 'hooks', plugins: DEFAULT_PLUGIN_HOST_CONFIG, capture: { includePrompts: true, @@ -64,7 +64,7 @@ export const DEFAULT_CONFIG: NemoFlowHookBackendConfig = { }, }; -export const nemoFlowConfigSchema = { +export const nemoRelayConfigSchema = { safeParse(value: unknown) { try { return { success: true, data: parseConfig(value) }; @@ -82,66 +82,64 @@ export const nemoFlowConfigSchema = { }; } }, - jsonSchema: NEMO_FLOW_OPENCLAW_JSON_SCHEMA, + jsonSchema: NEMO_RELAY_OPENCLAW_JSON_SCHEMA, } satisfies OpenClawPluginConfigSchema; /** Parse OpenClaw plugin JSON into the normalized hook backend config. */ -export function parseConfig(value: unknown): NemoFlowHookBackendConfig { - const raw = asRecord(value, "config", true); +export function parseConfig(value: unknown): NemoRelayHookBackendConfig { + const raw = asRecord(value, 'config', true); rejectRemovedFields(raw); - rejectUnknownFields(raw, "config", ["enabled", "backend", "plugins", "capture", "correlation"]); - const backend = optionalString(raw.backend, "backend") ?? DEFAULT_CONFIG.backend; + rejectUnknownFields(raw, 'config', ['enabled', 'backend', 'plugins', 'capture', 'correlation']); + const backend = optionalString(raw.backend, 'backend') ?? DEFAULT_CONFIG.backend; - if (backend !== "hooks") { - throw new Error(`unsupported nemo-flow backend: ${backend}`); + if (backend !== 'hooks') { + throw new Error(`unsupported nemo-relay backend: ${backend}`); } - const capture = asRecord(raw.capture, "capture", true); - const correlation = asRecord(raw.correlation, "correlation", true); + const capture = asRecord(raw.capture, 'capture', true); + const correlation = asRecord(raw.correlation, 'correlation', true); return { - enabled: optionalBoolean(raw.enabled, "enabled") ?? DEFAULT_CONFIG.enabled, + enabled: optionalBoolean(raw.enabled, 'enabled') ?? DEFAULT_CONFIG.enabled, backend, plugins: parsePluginHostConfig(raw.plugins), capture: { includePrompts: - optionalBoolean(capture.includePrompts, "capture.includePrompts") ?? - DEFAULT_CONFIG.capture.includePrompts, + optionalBoolean(capture.includePrompts, 'capture.includePrompts') ?? DEFAULT_CONFIG.capture.includePrompts, includeResponses: - optionalBoolean(capture.includeResponses, "capture.includeResponses") ?? + optionalBoolean(capture.includeResponses, 'capture.includeResponses') ?? DEFAULT_CONFIG.capture.includeResponses, stripToolArgs: - optionalBoolean(capture.stripToolArgs, "capture.stripToolArgs") ?? - DEFAULT_CONFIG.capture.stripToolArgs, + optionalBoolean(capture.stripToolArgs, 'capture.stripToolArgs') ?? DEFAULT_CONFIG.capture.stripToolArgs, stripToolResults: - optionalBoolean(capture.stripToolResults, "capture.stripToolResults") ?? + optionalBoolean(capture.stripToolResults, 'capture.stripToolResults') ?? DEFAULT_CONFIG.capture.stripToolResults, }, correlation: { llmOutputGraceMs: - optionalNonNegativeInteger(correlation.llmOutputGraceMs, "correlation.llmOutputGraceMs") ?? + optionalNonNegativeInteger(correlation.llmOutputGraceMs, 'correlation.llmOutputGraceMs') ?? DEFAULT_CONFIG.correlation.llmOutputGraceMs, recordTtlMs: - optionalNonNegativeInteger(correlation.recordTtlMs, "correlation.recordTtlMs") ?? + optionalNonNegativeInteger(correlation.recordTtlMs, 'correlation.recordTtlMs') ?? DEFAULT_CONFIG.correlation.recordTtlMs, maxRecordsPerKey: - optionalPositiveInteger(correlation.maxRecordsPerKey, "correlation.maxRecordsPerKey") ?? + optionalPositiveInteger(correlation.maxRecordsPerKey, 'correlation.maxRecordsPerKey') ?? DEFAULT_CONFIG.correlation.maxRecordsPerKey, }, }; } -/** Normalize the optional generic NeMo Flow plugin-host config embedded in OpenClaw config. */ -function parsePluginHostConfig(value: unknown): NemoFlowPluginHostConfig { +/** Normalize the optional generic NeMo Relay plugin-host config embedded in OpenClaw config. */ +function parsePluginHostConfig(value: unknown): NemoRelayPluginHostConfig { if (value === undefined) { return clonePluginHostConfig(DEFAULT_PLUGIN_HOST_CONFIG); } - const record = asRecord(value, "plugins", false); - const version = optionalNumber(record.version, "plugins.version") ?? 1; + const record = asRecord(value, 'plugins', false); + const version = optionalNumber(record.version, 'plugins.version') ?? 1; const components = record.components === undefined ? [] : record.components; if (!Array.isArray(components)) { - throw new Error("plugins.components must be an array"); + throw new Error('plugins.components must be an array'); } return { @@ -152,7 +150,7 @@ function parsePluginHostConfig(value: unknown): NemoFlowPluginHostConfig { } /** Clone the mutable plugin-host component list before putting it in runtime state. */ -function clonePluginHostConfig(config: NemoFlowPluginHostConfig): NemoFlowPluginHostConfig { +function clonePluginHostConfig(config: NemoRelayPluginHostConfig): NemoRelayPluginHostConfig { return { ...config, components: [...config.components], @@ -164,7 +162,7 @@ function asRecord(value: unknown, path: string, optional: boolean): Record; } throw new Error(`${path} must be an object`); @@ -172,15 +170,15 @@ function asRecord(value: unknown, path: string, optional: boolean): Record): void { - if (raw.nemoFlow !== undefined) { - throw new Error("nemoFlow.pluginConfig was removed; use top-level plugins instead"); + if (raw.nemoRelay !== undefined) { + throw new Error('nemoRelay.pluginConfig was removed; use top-level plugins instead'); } if (raw.atif !== undefined) { - throw new Error("atif was removed; configure plugins.components[].config.atif on the observability component"); + throw new Error('atif was removed; configure plugins.components[].config.atif on the observability component'); } if (raw.telemetry !== undefined) { throw new Error( - "telemetry was removed; configure plugins.components[].config.opentelemetry or openinference on the observability component", + 'telemetry was removed; configure plugins.components[].config.opentelemetry or openinference on the observability component', ); } } @@ -200,7 +198,7 @@ function optionalBoolean(value: unknown, path: string): boolean | undefined { if (value === undefined) { return undefined; } - if (typeof value !== "boolean") { + if (typeof value !== 'boolean') { throw new Error(`${path} must be a boolean`); } return value; @@ -211,7 +209,7 @@ function optionalNumber(value: unknown, path: string): number | undefined { if (value === undefined) { return undefined; } - if (typeof value !== "number" || !Number.isFinite(value)) { + if (typeof value !== 'number' || !Number.isFinite(value)) { throw new Error(`${path} must be a finite number`); } return value; @@ -246,7 +244,7 @@ function optionalString(value: unknown, path: string): string | undefined { if (value === undefined) { return undefined; } - if (typeof value !== "string") { + if (typeof value !== 'string') { throw new Error(`${path} must be a string`); } return value; diff --git a/integrations/openclaw/src/health.ts b/integrations/openclaw/src/health.ts index 910210a32..0a99c48e3 100644 --- a/integrations/openclaw/src/health.ts +++ b/integrations/openclaw/src/health.ts @@ -7,31 +7,31 @@ * Runtime state owns status transitions; this file turns that state into a * stable, JSON-friendly status payload for operators and tests. */ -import type { NemoFlowHookBackendConfig } from "./config.js"; -import type { HookReplayBackendState } from "./hook-replay/session.js"; +import type { NemoRelayHookBackendConfig } from './config.js'; +import type { HookReplayBackendState } from './hook-replay/session.js'; export type HookReplayBackendStatus = - | { state: "not_initialized"; reason?: string } - | { state: "disabled"; reason?: string } - | { state: "ready" } - | { state: "degraded"; reason: string } - | { state: "stopping" } - | { state: "stopped"; reason?: string }; + | { state: 'not_initialized'; reason?: string } + | { state: 'disabled'; reason?: string } + | { state: 'ready' } + | { state: 'degraded'; reason: string } + | { state: 'stopping' } + | { state: 'stopped'; reason?: string }; -export type OutputHealthState = "enabled" | "disabled" | "degraded"; +export type OutputHealthState = 'enabled' | 'disabled' | 'degraded'; -export type NemoFlowHealthSnapshot = { - id: "nemo-flow"; - backend: "hooks"; +export type NemoRelayHealthSnapshot = { + id: 'nemo-relay'; + backend: 'hooks'; status: HookReplayBackendStatus; initializedPluginHost: boolean; - state: HookReplayBackendStatus["state"]; + state: HookReplayBackendStatus['state']; outputs: { atif: OutputHealthState; otel: OutputHealthState; openInference: OutputHealthState; }; - counters: HookReplayBackendState["counters"]; + counters: HookReplayBackendState['counters']; lastError?: string; }; @@ -40,15 +40,15 @@ export function createHealthSnapshot(params: { status: HookReplayBackendStatus; initializedPluginHost: boolean; pluginHostOutputsHealthy: boolean; - config: NemoFlowHookBackendConfig; - counters?: HookReplayBackendState["counters"]; -}): NemoFlowHealthSnapshot { - const lastError = "reason" in params.status ? params.status.reason : undefined; + config: NemoRelayHookBackendConfig; + counters?: HookReplayBackendState['counters']; +}): NemoRelayHealthSnapshot { + const lastError = 'reason' in params.status ? params.status.reason : undefined; const outputs = configuredObservabilityOutputs(params.config); - const pluginHostFailed = params.status.state === "degraded" && !params.pluginHostOutputsHealthy; + const pluginHostFailed = params.status.state === 'degraded' && !params.pluginHostOutputsHealthy; return { - id: "nemo-flow", - backend: "hooks", + id: 'nemo-relay', + backend: 'hooks', status: params.status, initializedPluginHost: params.initializedPluginHost, state: params.status.state, @@ -64,13 +64,13 @@ export function createHealthSnapshot(params: { function outputHealth(enabled: boolean, pluginHostFailed: boolean): OutputHealthState { if (!enabled) { - return "disabled"; + return 'disabled'; } - return pluginHostFailed ? "degraded" : "enabled"; + return pluginHostFailed ? 'degraded' : 'enabled'; } /** Inspect generic PluginConfig components for configured observability outputs. */ -function configuredObservabilityOutputs(config: NemoFlowHookBackendConfig): { +function configuredObservabilityOutputs(config: NemoRelayHookBackendConfig): { atif: boolean; otel: boolean; openInference: boolean; @@ -79,7 +79,7 @@ function configuredObservabilityOutputs(config: NemoFlowHookBackendConfig): { for (const component of config.plugins.components) { const record = asRecord(component); - if (record?.kind !== "observability" || record.enabled === false) { + if (record?.kind !== 'observability' || record.enabled === false) { continue; } @@ -98,14 +98,14 @@ function sectionEnabled(value: unknown): boolean { } function asRecord(value: unknown): Record | undefined { - if (value !== null && typeof value === "object" && !Array.isArray(value)) { + if (value !== null && typeof value === 'object' && !Array.isArray(value)) { return value as Record; } return undefined; } /** Provide zero counters before hook replay has initialized. */ -function emptyCounters(): HookReplayBackendState["counters"] { +function emptyCounters(): HookReplayBackendState['counters'] { return { llmSpansReplayed: 0, toolSpansReplayed: 0, diff --git a/integrations/openclaw/src/hook-replay/correlation.ts b/integrations/openclaw/src/hook-replay/correlation.ts index a7256ff17..883c2b4a6 100644 --- a/integrations/openclaw/src/hook-replay/correlation.ts +++ b/integrations/openclaw/src/hook-replay/correlation.ts @@ -27,7 +27,7 @@ export type TimestampedRecord = { /** Serialize correlation tuple parts while preserving empty or missing fields as null. */ export function tupleKey(parts: unknown[]): string { - return JSON.stringify(parts.map((part) => (typeof part === "string" && part.length > 0 ? part : null))); + return JSON.stringify(parts.map((part) => (typeof part === 'string' && part.length > 0 ? part : null))); } /** Build the best available key for pairing public llm_input and llm_output hooks. */ @@ -59,7 +59,7 @@ export function evictExpiredRecords( } } -/** Return wall-clock microseconds for NeMo Flow span APIs. */ +/** Return wall-clock microseconds for NeMo Relay span APIs. */ export function nowMicros(): number { return Date.now() * 1000; } diff --git a/integrations/openclaw/src/hook-replay/llm.ts b/integrations/openclaw/src/hook-replay/llm.ts index 7ec19a757..8a3ea32b2 100644 --- a/integrations/openclaw/src/hook-replay/llm.ts +++ b/integrations/openclaw/src/hook-replay/llm.ts @@ -6,12 +6,12 @@ * * OpenClaw currently exposes public hooks for request snapshots, assistant * outputs, message writes, and model-call timing as separate event streams. This - * module correlates those signals into NeMo Flow LLM spans while staying on the + * module correlates those signals into NeMo Relay LLM spans while staying on the * public plugin API. The reconstruction is intentionally best-effort until * OpenClaw exposes a first-class provider-call lifecycle hook with a stable * call id, request, response, usage, and timing in one contract. */ -import type { NemoFlowHookBackendConfig } from "../config.js"; +import type { NemoRelayHookBackendConfig } from '../config.js'; import type { PluginHookAgentContext, PluginHookAgentEndEvent, @@ -21,9 +21,9 @@ import type { PluginHookLlmOutputEvent, PluginHookModelCallEndedEvent, PluginHookModelCallStartedEvent, -} from "../openclaw-hook-types.js"; -import type { JsonObject as JsonRecord, JsonValue } from "nemo-flow-node/typed"; -import { emitMark, toJsonRecord, toJsonValue } from "./marks.js"; +} from '../openclaw-hook-types.js'; +import type { JsonObject as JsonRecord, JsonValue } from 'nemo-relay-node/typed'; +import { emitMark, toJsonRecord, toJsonValue } from './marks.js'; import { evictExpiredCorrelationRecords, ensureSession, @@ -34,14 +34,8 @@ import { type PendingLlmOutputRecord, type SessionManager, type SessionState, -} from "./session.js"; -import { - llmKey, - modelTimingKey, - modelTimingLlmKey, - nowMicros, - startMicrosFromDuration, -} from "./correlation.js"; +} from './session.js'; +import { llmKey, modelTimingKey, modelTimingLlmKey, nowMicros, startMicrosFromDuration } from './correlation.js'; /** * Store one OpenClaw llm_input snapshot and replay it immediately if the matching @@ -58,7 +52,7 @@ export function recordLlmInput( sessionKey: ctx.sessionKey, runId: event.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { return; @@ -79,7 +73,11 @@ export function recordLlmInput( const input = createInputRecord(session, event); insertBoundedRecord(manager.state.llmInputs, key, input, manager.config.correlation.maxRecordsPerKey); - const pending = shiftOldest(manager.state.llmOutputsPendingInput, key, (record) => record.sessionKey === session.sessionId); + const pending = shiftOldest( + manager.state.llmOutputsPendingInput, + key, + (record) => record.sessionKey === session.sessionId, + ); if (!pending) { return; } @@ -112,7 +110,7 @@ export function recordLlmOutput( sessionKey: ctx.sessionKey, runId: event.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { return; @@ -172,7 +170,7 @@ export function recordBeforeMessageWrite( } const message = isRecord(event.message) ? event.message : undefined; - if (!message || typeof message.role !== "string") { + if (!message || typeof message.role !== 'string') { return; } const recordedMessage = toJsonValue(message); @@ -184,12 +182,12 @@ export function recordBeforeMessageWrite( session.messageWrites = [...historyMessages]; } - if (message.role === "assistant") { - const provider = stringField(message, "provider"); - const model = stringField(message, "model"); + if (message.role === 'assistant') { + const provider = stringField(message, 'provider'); + const model = stringField(message, 'model'); const assistantTexts = extractTextBlocks(message); const assistantToolCalls = snapshotMessages(extractToolCalls(message)); - const usage = "usage" in message ? toJsonValue(message.usage) : undefined; + const usage = 'usage' in message ? toJsonValue(message.usage) : undefined; if (provider && model && (assistantTexts.length > 0 || assistantToolCalls.length > 0 || usage !== undefined)) { session.assistantMessageWrites ??= []; session.assistantMessageWrites.push({ @@ -199,7 +197,7 @@ export function recordBeforeMessageWrite( assistantTexts, assistantToolCalls, historyMessages, - prompt: "", + prompt: '', observedAtMs: Date.now(), replayed: false, ...(usage === undefined ? {} : { usage }), @@ -230,7 +228,7 @@ export function recordModelCallStarted( sessionKey: event.sessionKey ?? ctx.sessionKey, runId: event.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', timestamp: nowMs * 1000, }); if (!session) { @@ -271,7 +269,7 @@ export function recordModelCallEnded( sessionKey: event.sessionKey ?? ctx.sessionKey, runId: event.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', timestamp: startMicros, }); if (!session) { @@ -304,7 +302,12 @@ export function recordModelCallEnded( } insertBoundedRecord( manager.state.modelTimingsByLlmKey, - modelTimingLlmKey({ sessionId: session.sessionId, runId: event.runId, provider: event.provider, model: event.model }), + modelTimingLlmKey({ + sessionId: session.sessionId, + runId: event.runId, + provider: event.provider, + model: event.model, + }), record, manager.config.correlation.maxRecordsPerKey, ); @@ -389,7 +392,7 @@ export function emitUnpairedModelCallTimingMarks(manager: SessionManager, sessio if (record.sessionKey !== session.sessionId || record.consumed || record.endedAtMs !== undefined) { continue; } - emitModelTimingMark(manager, session, "openclaw.model_call_timing_unpaired", record); + emitModelTimingMark(manager, session, 'openclaw.model_call_timing_unpaired', record); record.consumed = true; } } @@ -407,19 +410,19 @@ export function emitUnpairedModelCallTimingMarks(manager: SessionManager, sessio if (unpairedEnded.length === 1) { const [record] = unpairedEnded; if (record) { - emitModelTimingMark(manager, session, "openclaw.model_call_timing_unpaired", record); + emitModelTimingMark(manager, session, 'openclaw.model_call_timing_unpaired', record); } } else if (unpairedEnded.length > 1) { emitModelTimingSummaryMark(manager, session, unpairedEnded); } } -/** Build the request payload passed to NeMo Flow for a replayed LLM span. */ +/** Build the request payload passed to NeMo Relay for a replayed LLM span. */ export function buildReplayLlmRequest( input: LlmInputRecord, output: PluginHookLlmOutputEvent, - config: NemoFlowHookBackendConfig, - source = "openclaw.hooks", + config: NemoRelayHookBackendConfig, + source = 'openclaw.hooks', ): JsonValue { const messages = config.capture.includePrompts && Array.isArray(input.historyMessages) @@ -441,16 +444,16 @@ export function buildReplayLlmRequest( }); } -/** Build the response payload passed to NeMo Flow for a replayed LLM span. */ +/** Build the response payload passed to NeMo Relay for a replayed LLM span. */ export function buildReplayLlmResponse( event: PluginHookLlmOutputEvent, timing: ModelCallRecord | undefined, - config: NemoFlowHookBackendConfig, + config: NemoRelayHookBackendConfig, ): JsonValue { const usage = mapUsage(event.usage); const assistantToolCallNames = toolCallNames(event.assistantToolCalls); return toJsonValue({ - role: "assistant", + role: 'assistant', content: config.capture.includeResponses ? responseContent(event.assistantTexts, assistantToolCallNames) : undefined, @@ -473,11 +476,7 @@ export function buildReplayLlmResponse( } /** Replay an output whose matching input never arrived before the grace timeout. */ -function replayExpiredPendingOutput( - manager: SessionManager, - key: string, - record: PendingLlmOutputRecord, -): void { +function replayExpiredPendingOutput(manager: SessionManager, key: string, record: PendingLlmOutputRecord): void { try { if (!removeRecord(manager.state.llmOutputsPendingInput, key, record)) { return; @@ -501,21 +500,21 @@ function replayExpiredPendingOutput( manager.state.counters.replayErrors += 1; manager.logBoundedWarn( `llm_grace_timer_failed:${key}`, - `nemo-flow failed to replay pending llm_output after grace timer: ${error instanceof Error ? error.message : String(error)}`, + `nemo-relay failed to replay pending llm_output after grace timer: ${error instanceof Error ? error.message : String(error)}`, ); } } -/** Emit the actual NeMo Flow LLM span from correlated request, output, and timing data. */ +/** Emit the actual NeMo Relay LLM span from correlated request, output, and timing data. */ function replayLlmOutput(params: { manager: SessionManager; event: PluginHookLlmOutputEvent; ctx: PluginHookAgentContext; input: LlmInputRecord; timing?: ModelCallRecord | undefined; - source?: "openclaw.llm_output" | "openclaw.before_message_write" | undefined; + source?: 'openclaw.llm_output' | 'openclaw.before_message_write' | undefined; }): void { - const { manager, event, ctx, input, timing, source = "openclaw.llm_output" } = params; + const { manager, event, ctx, input, timing, source = 'openclaw.llm_output' } = params; const observedEndMicros = nowMicros(); const endMicros = timing?.endedAtMs === undefined ? observedEndMicros : timing.endedAtMs * 1000; const observedStartMicros = Math.min(input.observedAtMs * 1000, endMicros); @@ -528,7 +527,7 @@ function replayLlmOutput(params: { sessionKey: ctx.sessionKey, runId: event.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', timestamp: startMicros, }); if (!session) { @@ -544,10 +543,10 @@ function replayLlmOutput(params: { provider: event.provider, model: event.model, callId: timing?.callId, - correlation: source === "openclaw.before_message_write" ? "fifo_model_call_timing" : undefined, + correlation: source === 'openclaw.before_message_write' ? 'fifo_model_call_timing' : undefined, }); - manager.emitCapturedUnderSession("llm_output", session, () => { + manager.emitCapturedUnderSession('llm_output', session, () => { const handle = manager.nf.llmCall( event.provider, request, @@ -561,7 +560,7 @@ function replayLlmOutput(params: { manager.nf.llmCallEnd(handle, response, null, metadata, endMicros); manager.state.counters.llmSpansReplayed += 1; }); - if (source === "openclaw.llm_output") { + if (source === 'openclaw.llm_output') { incrementHookLlmOutputReplayCount(session, event.runId, manager.config.correlation.maxRecordsPerKey); } } @@ -614,7 +613,7 @@ function replayAssistantMessageWrites( placeholderRequest: true, }, timing, - source: "openclaw.before_message_write", + source: 'openclaw.before_message_write', }); record.replayed = true; replayed += 1; @@ -687,12 +686,12 @@ function emitModelTimingAmbiguousMark( event: PluginHookLlmOutputEvent, candidateCount: number, ): void { - manager.emitCapturedUnderSession("model_call_timing_ambiguous", session, () => { + manager.emitCapturedUnderSession('model_call_timing_ambiguous', session, () => { emitMark({ nf: manager.nf, state: manager.state, session, - name: "openclaw.model_call_timing_ambiguous", + name: 'openclaw.model_call_timing_ambiguous', data: toJsonRecord({ runId: event.runId, sessionId: event.sessionId, @@ -739,17 +738,13 @@ function emitModelTimingMark( } /** Emit a compact summary when multiple timing records cannot be paired safely. */ -function emitModelTimingSummaryMark( - manager: SessionManager, - session: SessionState, - records: ModelCallRecord[], -): void { - manager.emitCapturedUnderSession("model_call_timing_unmatched", session, () => { +function emitModelTimingSummaryMark(manager: SessionManager, session: SessionState, records: ModelCallRecord[]): void { + manager.emitCapturedUnderSession('model_call_timing_unmatched', session, () => { emitMark({ nf: manager.nf, state: manager.state, session, - name: "openclaw.model_call_timing_unmatched", + name: 'openclaw.model_call_timing_unmatched', data: toJsonRecord({ count: records.length, sampleCallIds: records.slice(0, 5).map((record) => record.callId), @@ -794,7 +789,7 @@ function placeholderInputRecord(record: PendingLlmOutputRecord): LlmInputRecord runId: record.runId, provider: record.provider, model: record.model, - prompt: "", + prompt: '', historyMessages: [], imagesCount: 0, observedAtMs: Date.now(), @@ -808,23 +803,23 @@ function appendPromptIfMissing(historyMessages: unknown[], prompt: string): unkn return historyMessages; } const last = historyMessages.at(-1); - if (isRecord(last) && last.role === "user" && extractTextBlocks(last).join("\n") === prompt) { + if (isRecord(last) && last.role === 'user' && extractTextBlocks(last).join('\n') === prompt) { return historyMessages; } - return [...historyMessages, { role: "user", content: prompt }]; + return [...historyMessages, { role: 'user', content: prompt }]; } /** Apply prompt-capture privacy settings to one historical message. */ -function sanitizePromptMessage(message: unknown, config: NemoFlowHookBackendConfig): unknown { +function sanitizePromptMessage(message: unknown, config: NemoRelayHookBackendConfig): unknown { if (!isRecord(message)) { return message; } let sanitized: Record = { ...message }; - if ((sanitized.role === "tool" || sanitized.role === "toolResult") && config.capture.stripToolResults) { + if ((sanitized.role === 'tool' || sanitized.role === 'toolResult') && config.capture.stripToolResults) { sanitized = { ...sanitized, content: { stripped: true } }; } - if (sanitized.role === "assistant" && config.capture.stripToolArgs) { + if (sanitized.role === 'assistant' && config.capture.stripToolArgs) { sanitized = stripAssistantToolArgs(sanitized); } else if (Array.isArray(sanitized.content)) { sanitized = { ...sanitized, content: sanitized.content.map(stripLargeAssistantContentFields) }; @@ -855,7 +850,7 @@ function stripToolCallArgs(value: unknown): unknown { return value; } const stripped: Record = { ...value }; - for (const key of ["args", "arguments", "input", "params"]) { + for (const key of ['args', 'arguments', 'input', 'params']) { if (stripped[key] !== undefined) { stripped[key] = { stripped: true }; } @@ -868,8 +863,8 @@ function stripLargeAssistantContentFields(value: unknown): unknown { if (!isRecord(value)) { return value; } - if (value.type === "thinking") { - return { type: "thinking", stripped: true }; + if (value.type === 'thinking') { + return { type: 'thinking', stripped: true }; } const stripped: Record = { ...value }; if (stripped.thinking !== undefined) { @@ -883,12 +878,12 @@ function stripLargeAssistantContentFields(value: unknown): unknown { /** Choose the user-visible LLM output text, falling back to tool-call names. */ function responseContent(assistantTexts: string[], assistantToolCallNames: string[]): string | undefined { - const text = assistantTexts.join("\n").trim(); + const text = assistantTexts.join('\n').trim(); if (text.length > 0) { return text; } if (assistantToolCallNames.length > 0) { - return `tool calls: ${assistantToolCallNames.join(", ")}`; + return `tool calls: ${assistantToolCallNames.join(', ')}`; } return undefined; } @@ -897,10 +892,10 @@ function responseContent(assistantTexts: string[], assistantToolCallNames: strin function lastAssistantText(messages: unknown[]): string | undefined { for (let index = messages.length - 1; index >= 0; index -= 1) { const message = messages[index]; - if (!isRecord(message) || message.role !== "assistant") { + if (!isRecord(message) || message.role !== 'assistant') { continue; } - const text = extractTextBlocks(message).join("\n").trim(); + const text = extractTextBlocks(message).join('\n').trim(); if (text.length > 0) { return text; } @@ -918,14 +913,14 @@ function finalOutputFromAgentEnd( if (lastText) { return toJsonRecord({ content: lastText, - source: "openclaw.agent_end", + source: 'openclaw.agent_end', runId, success: event.success, }); } if (event.error) { return toJsonRecord({ - source: "openclaw.agent_end", + source: 'openclaw.agent_end', runId, success: event.success, error: event.error, @@ -937,7 +932,7 @@ function finalOutputFromAgentEnd( /** Extract textual content blocks from OpenClaw/OpenAI/Anthropic-like messages. */ function extractTextBlocks(message: Record): string[] { const content = message.content; - if (typeof content === "string" && content.length > 0) { + if (typeof content === 'string' && content.length > 0) { return [content]; } if (!Array.isArray(content)) { @@ -945,9 +940,9 @@ function extractTextBlocks(message: Record): string[] { } const texts: string[] = []; for (const item of content) { - if (typeof item === "string") { + if (typeof item === 'string') { texts.push(item); - } else if (isRecord(item) && typeof item.text === "string") { + } else if (isRecord(item) && typeof item.text === 'string') { texts.push(item.text); } } @@ -966,18 +961,16 @@ function extractToolCalls(message: Record): unknown[] { if (!Array.isArray(content)) { return []; } - return content.filter( - (item) => isToolCallLike(item), - ); + return content.filter((item) => isToolCallLike(item)); } /** Identify likely tool-call content blocks across provider-specific shapes. */ function isToolCallLike(value: unknown): boolean { return ( isRecord(value) && - (value.type === "toolCall" || - value.type === "tool_use" || - value.type === "tool-call" || + (value.type === 'toolCall' || + value.type === 'tool_use' || + value.type === 'tool-call' || value.toolName !== undefined || value.name !== undefined) ); @@ -994,9 +987,7 @@ function toolCallNames(toolCalls: unknown[] | undefined): string[] { continue; } const name = - stringField(toolCall, "name") ?? - stringField(toolCall, "toolName") ?? - stringField(toolCall, "functionName"); + stringField(toolCall, 'name') ?? stringField(toolCall, 'toolName') ?? stringField(toolCall, 'functionName'); if (name) { names.push(name); } @@ -1005,12 +996,12 @@ function toolCallNames(toolCalls: unknown[] | undefined): string[] { } /** Convert stored message-write usage back into the llm_output usage contract. */ -function mapHookUsage(usage: unknown): PluginHookLlmOutputEvent["usage"] | undefined { +function mapHookUsage(usage: unknown): PluginHookLlmOutputEvent['usage'] | undefined { const mapped = mapUsage(usage); if (!mapped) { return undefined; } - const hookUsage: NonNullable = {}; + const hookUsage: NonNullable = {}; if (mapped.prompt_tokens !== undefined) { hookUsage.input = mapped.prompt_tokens; } @@ -1104,10 +1095,10 @@ function findCurrentPromptIndex(messages: unknown[], prompt: string): number | u } for (let index = messages.length - 1; index >= 0; index -= 1) { const message = messages[index]; - if (!isRecord(message) || message.role !== "user") { + if (!isRecord(message) || message.role !== 'user') { continue; } - if (extractTextBlocks(message).join("\n") === prompt) { + if (extractTextBlocks(message).join('\n') === prompt) { return index; } } @@ -1166,16 +1157,16 @@ function mapUsage(usage: unknown): Record | undefined { return undefined; } const mapped: Record = {}; - const input = numberField(usage, "input") ?? numberField(usage, "prompt_tokens"); - const output = numberField(usage, "output") ?? numberField(usage, "completion_tokens"); - const cacheRead = numberField(usage, "cacheRead") ?? numberField(usage, "cache_read_tokens"); - const cacheWrite = numberField(usage, "cacheWrite") ?? numberField(usage, "cache_write_tokens"); - const total = numberField(usage, "total") ?? numberField(usage, "totalTokens") ?? numberField(usage, "total_tokens"); + const input = numberField(usage, 'input') ?? numberField(usage, 'prompt_tokens'); + const output = numberField(usage, 'output') ?? numberField(usage, 'completion_tokens'); + const cacheRead = numberField(usage, 'cacheRead') ?? numberField(usage, 'cache_read_tokens'); + const cacheWrite = numberField(usage, 'cacheWrite') ?? numberField(usage, 'cache_write_tokens'); + const total = numberField(usage, 'total') ?? numberField(usage, 'totalTokens') ?? numberField(usage, 'total_tokens'); const totalCanIncludeCompletion = total === undefined || output === undefined || total >= output; const prompt = total !== undefined && output !== undefined && totalCanIncludeCompletion ? total - output : input; const totalCanIncludePrompt = total === undefined || prompt === undefined || total >= prompt; const normalizedTotal = totalCanIncludeCompletion && totalCanIncludePrompt ? total : undefined; - const costTotal = isRecord(usage.cost) ? numberField(usage.cost, "total") : numberField(usage, "cost_usd"); + const costTotal = isRecord(usage.cost) ? numberField(usage.cost, 'total') : numberField(usage, 'cost_usd'); if (prompt !== undefined) { mapped.prompt_tokens = prompt; } @@ -1203,13 +1194,13 @@ function mapUsage(usage: unknown): Record | undefined { /** Read a non-empty string field from a generic hook record. */ function stringField(record: Record, key: string): string | undefined { const value = record[key]; - return typeof value === "string" && value.length > 0 ? value : undefined; + return typeof value === 'string' && value.length > 0 ? value : undefined; } /** Read a finite numeric field from a generic hook record. */ function numberField(record: Record, key: string): number | undefined { const value = record[key]; - return typeof value === "number" && Number.isFinite(value) ? value : undefined; + return typeof value === 'number' && Number.isFinite(value) ? value : undefined; } /** Copy model_call_ended details into a retained timing record. */ @@ -1229,7 +1220,10 @@ function applyModelCallEnd(record: ModelCallRecord, event: PluginHookModelCallEn } /** Find the newest started-but-not-ended timing record for a session. */ -function latestUnendedRecord(records: ModelCallRecord[] | undefined, session: SessionState): ModelCallRecord | undefined { +function latestUnendedRecord( + records: ModelCallRecord[] | undefined, + session: SessionState, +): ModelCallRecord | undefined { if (!records) { return undefined; } @@ -1304,5 +1298,5 @@ function evictExpiredReplayRecords(manager: SessionManager): void { /** Narrow unknown values to plain records for payload traversal. */ function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); + return typeof value === 'object' && value !== null && !Array.isArray(value); } diff --git a/integrations/openclaw/src/hook-replay/marks.ts b/integrations/openclaw/src/hook-replay/marks.ts index c54861144..2677017db 100644 --- a/integrations/openclaw/src/hook-replay/marks.ts +++ b/integrations/openclaw/src/hook-replay/marks.ts @@ -6,16 +6,16 @@ * * Hook payloads can contain undefined values, circular objects, errors, and * prototype-sensitive keys. This module normalizes them before they cross the - * NeMo Flow NAPI boundary. + * NeMo Relay NAPI boundary. */ -import type { PluginHookAfterToolCallEvent } from "../openclaw-hook-types.js"; -import type { JsonObject as JsonRecord, JsonValue } from "nemo-flow-node/typed"; -import type { HookReplayBackendState, SessionState } from "./session.js"; -import type { NemoFlowRuntimeModule } from "../modules.js"; +import type { PluginHookAfterToolCallEvent } from '../openclaw-hook-types.js'; +import type { JsonObject as JsonRecord, JsonValue } from 'nemo-relay-node/typed'; +import type { HookReplayBackendState, SessionState } from './session.js'; +import type { NemoRelayRuntimeModule } from '../modules.js'; -/** Emit a NeMo Flow event under an existing OpenClaw session root span. */ +/** Emit a NeMo Relay event under an existing OpenClaw session root span. */ export function emitMark(params: { - nf: NemoFlowRuntimeModule; + nf: NemoRelayRuntimeModule; state: HookReplayBackendState; session: SessionState; name: string; @@ -37,7 +37,7 @@ export function blockedToolDetails( context?: { runId?: string | undefined }, ): JsonRecord | undefined { const details = resultDetails(event.result); - if (details?.status !== "blocked") { + if (details?.status !== 'blocked') { return undefined; } @@ -46,7 +46,7 @@ export function blockedToolDetails( toolCallId: event.toolCallId, runId: event.runId ?? context?.runId, blocked: true, - deniedReason: typeof details.deniedReason === "string" ? details.deniedReason : undefined, + deniedReason: typeof details.deniedReason === 'string' ? details.deniedReason : undefined, durationMs: event.durationMs, }); } @@ -91,7 +91,7 @@ function stripUndefined(input: Record, seen: WeakSet): for (const [key, value] of Object.entries(input)) { if (value !== undefined) { const normalized = normalizeJsonValue(value, seen); - if (key === "__proto__") { + if (key === '__proto__') { Object.defineProperty(output, key, { configurable: true, enumerable: true, @@ -108,15 +108,15 @@ function stripUndefined(input: Record, seen: WeakSet): /** Normalize any hook value into JSON, replacing cycles and unsupported primitives. */ function normalizeJsonValue(value: unknown, seen: WeakSet): JsonValue { - if (value === null || typeof value === "string" || typeof value === "boolean") { + if (value === null || typeof value === 'string' || typeof value === 'boolean') { return value; } - if (typeof value === "number") { + if (typeof value === 'number') { return Number.isFinite(value) ? value : null; } if (Array.isArray(value)) { if (seen.has(value)) { - return "[Circular]"; + return '[Circular]'; } seen.add(value); const out = value.map((item) => normalizeJsonValue(item, seen)); @@ -125,7 +125,7 @@ function normalizeJsonValue(value: unknown, seen: WeakSet): JsonValue { } if (isRecord(value)) { if (seen.has(value)) { - return "[Circular]"; + return '[Circular]'; } seen.add(value); const out = stripUndefined(value, seen); @@ -137,5 +137,5 @@ function normalizeJsonValue(value: unknown, seen: WeakSet): JsonValue { /** Narrow unknown values to plain records for payload traversal. */ function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); + return typeof value === 'object' && value !== null && !Array.isArray(value); } diff --git a/integrations/openclaw/src/hook-replay/session.ts b/integrations/openclaw/src/hook-replay/session.ts index 26af9c523..f0984725a 100644 --- a/integrations/openclaw/src/hook-replay/session.ts +++ b/integrations/openclaw/src/hook-replay/session.ts @@ -8,16 +8,16 @@ * requester key, or child key depending on the hook. This module canonicalizes * those identifiers and owns the root `openclaw.session` scope lifecycle. */ -import type { NemoFlowHookBackendConfig } from "../config.js"; -import { evictExpiredRecords, tupleKey as tupleKeyFromCorrelation } from "./correlation.js"; +import type { NemoRelayHookBackendConfig } from '../config.js'; +import { evictExpiredRecords, tupleKey as tupleKeyFromCorrelation } from './correlation.js'; import type { PluginHookAgentContext, PluginHookLlmOutputEvent, PluginHookModelCallEndedEvent, -} from "../openclaw-hook-types.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; -import type { JsonObject as JsonRecord } from "nemo-flow-node/typed"; -import type { NemoFlowRuntimeModule } from "../modules.js"; +} from '../openclaw-hook-types.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; +import type { JsonObject as JsonRecord } from 'nemo-relay-node/typed'; +import type { NemoRelayRuntimeModule } from '../modules.js'; export type SessionLookupInput = { sessionId?: string | undefined; @@ -29,7 +29,7 @@ export type SessionLookupInput = { export type EnsureSessionInput = SessionLookupInput & { agentId?: string | undefined; - source: "session_start" | "lazy_session"; + source: 'session_start' | 'lazy_session'; resumedFrom?: string | undefined; timestamp?: number | undefined; }; @@ -38,7 +38,7 @@ export type SessionState = { sessionId: string; sessionKey?: string; agentId?: string; - source: "session_start" | "lazy_session"; + source: 'session_start' | 'lazy_session'; resumedFrom?: string; finalOutput?: JsonRecord; trajectoryReplayedRuns?: Set; @@ -49,8 +49,8 @@ export type SessionState = { >; messageWrites?: unknown[]; assistantMessageWrites?: AssistantMessageRecord[]; - stack: ReturnType; - rootHandle?: ReturnType; + stack: ReturnType; + rootHandle?: ReturnType; }; export type PendingLlmOutputRecord = { @@ -106,9 +106,9 @@ export type ModelCallRecord = { startedAtMs?: number | undefined; endedAtMs?: number | undefined; durationMs?: number | undefined; - outcome?: PluginHookModelCallEndedEvent["outcome"] | undefined; + outcome?: PluginHookModelCallEndedEvent['outcome'] | undefined; errorCategory?: string | undefined; - failureKind?: PluginHookModelCallEndedEvent["failureKind"] | undefined; + failureKind?: PluginHookModelCallEndedEvent['failureKind'] | undefined; requestPayloadBytes?: number | undefined; responseStreamBytes?: number | undefined; timeToFirstByteMs?: number | undefined; @@ -135,16 +135,13 @@ export type HookReplayBackendState = { }; export type SessionManager = { - nf: NemoFlowRuntimeModule; - config: NemoFlowHookBackendConfig; + nf: NemoRelayRuntimeModule; + config: NemoRelayHookBackendConfig; logger: PluginLogger; state: HookReplayBackendState; agentVersion: string; emitCapturedUnderSession: (label: string, session: SessionState, emit: () => void) => void; - replayPendingLlmOutputsForSession: ( - session: SessionState, - options: { allowPlaceholderRequest: boolean }, - ) => void; + replayPendingLlmOutputsForSession: (session: SessionState, options: { allowPlaceholderRequest: boolean }) => void; emitUnpairedModelCallTimingMarks: (session: SessionState) => void; logBoundedWarn: (key: string, message: string) => void; }; @@ -152,22 +149,19 @@ export type SessionManager = { /** Return all keys that may identify an existing OpenClaw session. */ export function lookupSessionKeys(input: SessionLookupInput): string[] { return [input.sessionId, input.sessionKey, input.requesterSessionKey, input.childSessionKey, input.runId].filter( - (value): value is string => typeof value === "string" && value.length > 0, + (value): value is string => typeof value === 'string' && value.length > 0, ); } /** Return keys that should alias to a canonical session once it is known. */ export function aliasSessionKeys(input: SessionLookupInput): string[] { return [input.sessionId, input.sessionKey, input.requesterSessionKey, input.runId].filter( - (value): value is string => typeof value === "string" && value.length > 0, + (value): value is string => typeof value === 'string' && value.length > 0, ); } /** Resolve a hook's session identity to the canonical session id used in replay state. */ -export function resolveSessionKey( - state: HookReplayBackendState, - input: SessionLookupInput, -): string | undefined { +export function resolveSessionKey(state: HookReplayBackendState, input: SessionLookupInput): string | undefined { for (const key of lookupSessionKeys(input)) { const canonical = state.sessionAliases.get(key); if (canonical) { @@ -213,7 +207,7 @@ export function ensureSession(manager: SessionManager, input: EnsureSessionInput const key = resolveSessionKey(manager.state, input); if (!key) { manager.state.counters.skippedEvents += 1; - manager.logBoundedWarn("missing-session-key", "nemo-flow skipped replay because no session/run key was available"); + manager.logBoundedWarn('missing-session-key', 'nemo-relay skipped replay because no session/run key was available'); return undefined; } @@ -269,12 +263,12 @@ export function closeSessionRoot( rootOutput: JsonRecord = summary, timestamp?: number, ): void { - manager.emitCapturedUnderSession("session_end", session, () => { + manager.emitCapturedUnderSession('session_end', session, () => { if (!session.rootHandle) { return; } - manager.nf.event("openclaw.session_end", session.rootHandle, summary, null, timestamp ?? null); + manager.nf.event('openclaw.session_end', session.rootHandle, summary, null, timestamp ?? null); manager.state.counters.marksEmitted += 1; manager.nf.popScope(session.rootHandle, rootOutput, timestamp ?? null); delete session.rootHandle; @@ -287,12 +281,7 @@ export function deleteSession(state: HookReplayBackendState, session: SessionSta } /** Insert a correlation record while bounding retained entries per key. */ -export function insertBoundedRecord( - map: Map, - key: string, - record: T, - maxRecordsPerKey: number, -): void { +export function insertBoundedRecord(map: Map, key: string, record: T, maxRecordsPerKey: number): void { const records = map.get(key) ?? []; records.push(record); while (records.length > maxRecordsPerKey) { @@ -314,7 +303,7 @@ export function evictExpiredCorrelationRecords(state: HookReplayBackendState, no evictExpiredRecords(state.modelTimingsByLlmKey, nowMs, ttlMs); } -/** Open the root NeMo Flow scope for one OpenClaw session and emit session_start. */ +/** Open the root NeMo Relay scope for one OpenClaw session and emit session_start. */ function openSessionRoot(manager: SessionManager, session: SessionState, input: EnsureSessionInput): void { const data: JsonRecord = { sessionId: session.sessionId, @@ -325,9 +314,9 @@ function openSessionRoot(manager: SessionManager, session: SessionState, input: ...(session.resumedFrom === undefined ? {} : { resumedFrom: session.resumedFrom }), }; - manager.emitCapturedUnderSession("session_start", session, () => { + manager.emitCapturedUnderSession('session_start', session, () => { session.rootHandle = manager.nf.pushScope( - "openclaw.session", + 'openclaw.session', agentScopeType(manager.nf), null, null, @@ -336,7 +325,7 @@ function openSessionRoot(manager: SessionManager, session: SessionState, input: null, input.timestamp ?? null, ); - manager.nf.event("openclaw.session_start", session.rootHandle, data, null, input.timestamp ?? null); + manager.nf.event('openclaw.session_start', session.rootHandle, data, null, input.timestamp ?? null); manager.state.counters.marksEmitted += 1; }); } @@ -380,11 +369,7 @@ function evictFromRecordMap(map: Map, - nowMs: number, - ttlMs: number, -): void { +function evictExpiredPendingLlmOutputs(map: Map, nowMs: number, ttlMs: number): void { for (const [key, records] of map) { const retained: PendingLlmOutputRecord[] = []; for (const record of records) { @@ -406,6 +391,6 @@ function evictExpiredPendingLlmOutputs( } /** Resolve the runtime's Agent scope enum while tolerating older Node bindings. */ -function agentScopeType(nf: NemoFlowRuntimeModule): Parameters[1] { - return (nf.ScopeType?.Agent ?? 0) as Parameters[1]; +function agentScopeType(nf: NemoRelayRuntimeModule): Parameters[1] { + return (nf.ScopeType?.Agent ?? 0) as Parameters[1]; } diff --git a/integrations/openclaw/src/hook-replay/tool.ts b/integrations/openclaw/src/hook-replay/tool.ts index 43aec3b17..f60a1a481 100644 --- a/integrations/openclaw/src/hook-replay/tool.ts +++ b/integrations/openclaw/src/hook-replay/tool.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Tool-call replay from OpenClaw hooks into NeMo Flow spans. + * Tool-call replay from OpenClaw hooks into NeMo Relay spans. * * Tool payloads can be large or sensitive, so this module applies capture policy * before exporting arguments/results while keeping enough metadata for debugging. @@ -11,12 +11,12 @@ import type { PluginHookAfterToolCallEvent, PluginHookBeforeToolCallEvent, PluginHookToolContext, -} from "../openclaw-hook-types.js"; -import { blockedToolDetails, emitMark, errorToJson, toJsonRecord, toJsonValue } from "./marks.js"; -import { ensureSession, type SessionManager } from "./session.js"; -import { nowMicros, startMicrosFromDuration } from "./correlation.js"; +} from '../openclaw-hook-types.js'; +import { blockedToolDetails, emitMark, errorToJson, toJsonRecord, toJsonValue } from './marks.js'; +import { ensureSession, type SessionManager } from './session.js'; +import { nowMicros, startMicrosFromDuration } from './correlation.js'; -/** Run NeMo Flow tool conditional-execution guardrails before OpenClaw executes a tool. */ +/** Run NeMo Relay tool conditional-execution guardrails before OpenClaw executes a tool. */ export async function guardBeforeToolCall( manager: SessionManager, event: PluginHookBeforeToolCallEvent, @@ -27,7 +27,7 @@ export async function guardBeforeToolCall( sessionKey: ctx.sessionKey, runId: event.runId ?? ctx.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); const args = toJsonValue(event.params ?? {}); @@ -44,7 +44,7 @@ export async function guardBeforeToolCall( } } -/** Convert one OpenClaw after_tool_call event into a NeMo Flow tool span or blocked-tool mark. */ +/** Convert one OpenClaw after_tool_call event into a NeMo Relay tool span or blocked-tool mark. */ export function replayAfterToolCall( manager: SessionManager, event: PluginHookAfterToolCallEvent, @@ -55,17 +55,17 @@ export function replayAfterToolCall( sessionKey: ctx.sessionKey, runId: event.runId ?? ctx.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); const blockedDetails = blockedToolDetails(event, { runId: event.runId ?? ctx.runId }); if (session && blockedDetails) { - manager.emitCapturedUnderSession("openclaw.tool_blocked", session, () => { + manager.emitCapturedUnderSession('openclaw.tool_blocked', session, () => { emitMark({ nf: manager.nf, state: manager.state, session, - name: "openclaw.tool_blocked", + name: 'openclaw.tool_blocked', data: blockedDetails, }); }); @@ -78,7 +78,7 @@ export function replayAfterToolCall( const endMicros = nowMicros(); const metadata = toJsonRecord({ - source: "openclaw.after_tool_call", + source: 'openclaw.after_tool_call', runId: event.runId ?? ctx.runId, sessionId: ctx.sessionId, sessionKey: ctx.sessionKey, @@ -90,11 +90,11 @@ export function replayAfterToolCall( ? { stripped: true, argKeys: - event.params && typeof event.params === "object" && !Array.isArray(event.params) + event.params && typeof event.params === 'object' && !Array.isArray(event.params) ? Object.keys(event.params) : undefined, } - : event.params ?? {}, + : (event.params ?? {}), ); const endPayload = toJsonValue( manager.config.capture.stripToolResults @@ -104,7 +104,7 @@ export function replayAfterToolCall( : { ...toolDisplayPayload(event, false), result: event.result ?? null }, ); - manager.emitCapturedUnderSession("after_tool_call", session, () => { + manager.emitCapturedUnderSession('after_tool_call', session, () => { const handle = manager.nf.toolCall( event.toolName, argsPayload, @@ -124,7 +124,7 @@ export function replayAfterToolCall( function toolDisplayPayload(event: PluginHookAfterToolCallEvent, stripped: boolean): Record { const hasError = Boolean(event.error); return { - content: `Tool ${event.toolName} ${hasError ? "failed" : "completed"}.`, + content: `Tool ${event.toolName} ${hasError ? 'failed' : 'completed'}.`, openclaw: { toolName: event.toolName, toolCallId: event.toolCallId, @@ -138,5 +138,5 @@ function toolDisplayPayload(event: PluginHookAfterToolCallEvent, stripped: boole /** Include result keys as a low-noise hint when full tool results are stripped. */ function resultKeys(result: unknown): string[] | undefined { - return result && typeof result === "object" && !Array.isArray(result) ? Object.keys(result) : undefined; + return result && typeof result === 'object' && !Array.isArray(result) ? Object.keys(result) : undefined; } diff --git a/integrations/openclaw/src/hooks-backend.ts b/integrations/openclaw/src/hooks-backend.ts index ae129a92c..b1526ba6e 100644 --- a/integrations/openclaw/src/hooks-backend.ts +++ b/integrations/openclaw/src/hooks-backend.ts @@ -8,9 +8,9 @@ * subagent events. This class routes each event to focused replay modules and * owns fail-open behavior so observability never breaks the agent runtime. */ -import type { NemoFlowHookBackendConfig } from "./config.js"; -import { emitMark, toJsonRecord } from "./hook-replay/marks.js"; -import { llmKey } from "./hook-replay/correlation.js"; +import type { NemoRelayHookBackendConfig } from './config.js'; +import { emitMark, toJsonRecord } from './hook-replay/marks.js'; +import { llmKey } from './hook-replay/correlation.js'; import { emitUnpairedModelCallTimingMarks, recordBeforeMessageWrite, @@ -20,8 +20,8 @@ import { recordModelCallStarted, replayAgentEndMessages, replayPendingLlmOutputsForSession, -} from "./hook-replay/llm.js"; -import { guardBeforeToolCall, replayAfterToolCall } from "./hook-replay/tool.js"; +} from './hook-replay/llm.js'; +import { guardBeforeToolCall, replayAfterToolCall } from './hook-replay/tool.js'; import { createHookReplayState, drainSession, @@ -32,8 +32,8 @@ import { type HookReplayBackendState, type SessionLookupInput, type SessionState, -} from "./hook-replay/session.js"; -import type { NemoFlowRuntimeModule } from "./modules.js"; +} from './hook-replay/session.js'; +import type { NemoRelayRuntimeModule } from './modules.js'; import type { PluginHookAfterToolCallEvent, PluginHookAgentContext, @@ -55,21 +55,21 @@ import type { PluginHookSubagentEndedEvent, PluginHookSubagentSpawnedEvent, PluginHookToolContext, -} from "./openclaw-hook-types.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; -import type { JsonObject as JsonRecord } from "nemo-flow-node/typed"; +} from './openclaw-hook-types.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; +import type { JsonObject as JsonRecord } from 'nemo-relay-node/typed'; export type HookReplayBackendOptions = { - nf: NemoFlowRuntimeModule; - config: NemoFlowHookBackendConfig; + nf: NemoRelayRuntimeModule; + config: NemoRelayHookBackendConfig; logger: PluginLogger; agentVersion: string; }; -/** Replays OpenClaw public hook events into NeMo Flow scopes, spans, and marks. */ +/** Replays OpenClaw public hook events into NeMo Relay scopes, spans, and marks. */ export class HookReplayBackend { - private readonly nf: NemoFlowRuntimeModule; - private readonly config: NemoFlowHookBackendConfig; + private readonly nf: NemoRelayRuntimeModule; + private readonly config: NemoRelayHookBackendConfig; private readonly logger: PluginLogger; private readonly agentVersion: string; private readonly stateValue = createHookReplayState(); @@ -99,7 +99,7 @@ export class HookReplayBackend { sessionId: event.sessionId, sessionKey: event.sessionKey ?? ctx.sessionKey, agentId: ctx.agentId, - source: "session_start", + source: 'session_start', resumedFrom: event.resumedFrom, }); @@ -112,7 +112,7 @@ export class HookReplayBackend { sessionId: event.sessionId, sessionKey: event.sessionKey ?? ctx.sessionKey, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { @@ -142,7 +142,7 @@ export class HookReplayBackend { recordModelCallEnded(this.sessionManager(), event, ctx); } - /** Replay a finished OpenClaw tool call as a NeMo Flow tool span or blocked mark. */ + /** Replay a finished OpenClaw tool call as a NeMo Relay tool span or blocked mark. */ onAfterToolCall(event: PluginHookAfterToolCallEvent, ctx: PluginHookToolContext): void { replayAfterToolCall(this.sessionManager(), event, ctx); } @@ -164,7 +164,7 @@ export class HookReplayBackend { sessionKey: ctx.sessionKey, runId: event.runId ?? ctx.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { @@ -172,12 +172,12 @@ export class HookReplayBackend { } const finalOutput = replayAgentEndMessages(this.sessionManager(), event, ctx, session); - if (finalOutput && (!session.finalOutput || "content" in finalOutput)) { + if (finalOutput && (!session.finalOutput || 'content' in finalOutput)) { session.finalOutput = finalOutput; } this.emitSessionMark( - "openclaw.agent_end", + 'openclaw.agent_end', session, toJsonRecord({ runId: event.runId ?? ctx.runId, @@ -196,23 +196,23 @@ export class HookReplayBackend { sessionKey: event.sessionKey ?? ctx.sessionKey, runId: event.runId ?? ctx.runId, agentId: ctx.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { return; } - if (typeof event.lastAssistantMessage === "string" && event.lastAssistantMessage.length > 0) { + if (typeof event.lastAssistantMessage === 'string' && event.lastAssistantMessage.length > 0) { session.finalOutput = toJsonRecord({ content: event.lastAssistantMessage, - source: "openclaw.before_agent_finalize", + source: 'openclaw.before_agent_finalize', runId: event.runId ?? ctx.runId, }); } this.emitSessionMark( - "openclaw.before_agent_finalize", + 'openclaw.before_agent_finalize', session, toJsonRecord({ runId: event.runId ?? ctx.runId, @@ -232,13 +232,13 @@ export class HookReplayBackend { const session = this.ensureSession({ requesterSessionKey: ctx.requesterSessionKey, - source: "lazy_session", + source: 'lazy_session', }) ?? this.ensureSession({ childSessionKey: ctx.childSessionKey ?? event.childSessionKey, runId: ctx.runId ?? event.runId, agentId: event.agentId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { @@ -246,7 +246,7 @@ export class HookReplayBackend { } this.emitSessionMark( - "openclaw.subagent_spawned", + 'openclaw.subagent_spawned', session, toJsonRecord({ runId: event.runId, @@ -264,12 +264,12 @@ export class HookReplayBackend { const session = this.ensureSession({ requesterSessionKey: ctx.requesterSessionKey, - source: "lazy_session", + source: 'lazy_session', }) ?? this.ensureSession({ childSessionKey: ctx.childSessionKey ?? event.targetSessionKey, runId: ctx.runId ?? event.runId, - source: "lazy_session", + source: 'lazy_session', }); if (!session) { @@ -277,7 +277,7 @@ export class HookReplayBackend { } this.emitSessionMark( - "openclaw.subagent_ended", + 'openclaw.subagent_ended', session, toJsonRecord({ runId: event.runId ?? ctx.runId, @@ -295,7 +295,7 @@ export class HookReplayBackend { /** Drain all active sessions when the OpenClaw gateway is stopping. */ async drainForGatewayStop(reason?: string): Promise { - await this.closeAllSessions({ reason: reason ?? "gateway_stop" }); + await this.closeAllSessions({ reason: reason ?? 'gateway_stop' }); } /** Close one session selected by a runtime lifecycle cleanup hook. */ @@ -326,24 +326,20 @@ export class HookReplayBackend { this.stateValue.counters.replayErrors += 1; this.logBoundedWarn( `safe-replay:${label}`, - `nemo-flow replay failed: label=${label} session=${session?.sessionId ?? "unknown"} error=${toMessage(error)}`, + `nemo-relay replay failed: label=${label} session=${session?.sessionId ?? 'unknown'} error=${toMessage(error)}`, ); } } /** Async variant of safeReplay for hooks that need export or cleanup awaits. */ - async safeReplayAsync( - label: string, - session: SessionState | undefined, - emit: () => Promise, - ): Promise { + async safeReplayAsync(label: string, session: SessionState | undefined, emit: () => Promise): Promise { try { await emit(); } catch (error) { this.stateValue.counters.replayErrors += 1; this.logBoundedWarn( `safe-replay:${label}`, - `nemo-flow async replay failed: label=${label} session=${session?.sessionId ?? "unknown"} error=${toMessage(error)}`, + `nemo-relay async replay failed: label=${label} session=${session?.sessionId ?? 'unknown'} error=${toMessage(error)}`, ); } } diff --git a/integrations/openclaw/src/modules.ts b/integrations/openclaw/src/modules.ts index 2f9f1455b..7127aedd3 100644 --- a/integrations/openclaw/src/modules.ts +++ b/integrations/openclaw/src/modules.ts @@ -2,76 +2,78 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Dynamic module loading boundary for NeMo Flow Node bindings. + * Dynamic module loading boundary for NeMo Relay Node bindings. * * Keeping imports behind this loader lets the plugin register in OpenClaw even * when the native binding is unavailable, then degrade only at runtime start. */ -import type * as NemoFlowRuntime from "nemo-flow-node"; -import type * as NemoFlowAdaptive from "nemo-flow-node/adaptive"; -import type * as NemoFlowPluginHost from "nemo-flow-node/plugin"; +import type * as NemoRelayRuntime from 'nemo-relay-node'; +import type * as NemoRelayAdaptive from 'nemo-relay-node/adaptive'; +import type * as NemoRelayPluginHost from 'nemo-relay-node/plugin'; -type NemoFlowRuntimeKeys = - | "ScopeType" - | "createScopeStack" - | "currentScopeStack" - | "setThreadScopeStack" - | "pushScope" - | "popScope" - | "event" - | "llmCall" - | "llmCallEnd" - | "toolCall" - | "toolCallEnd" - | "toolConditionalExecution"; +type NemoRelayRuntimeKeys = + | 'ScopeType' + | 'createScopeStack' + | 'currentScopeStack' + | 'setThreadScopeStack' + | 'pushScope' + | 'popScope' + | 'event' + | 'llmCall' + | 'llmCallEnd' + | 'toolCall' + | 'toolCallEnd' + | 'toolConditionalExecution'; -type NemoFlowPluginHostKeys = "defaultConfig" | "validate" | "initialize" | "clear"; -type NemoFlowAdaptiveKeys = "ADAPTIVE_PLUGIN_KIND" | "ComponentSpec"; +type NemoRelayPluginHostKeys = 'defaultConfig' | 'validate' | 'initialize' | 'clear'; +type NemoRelayAdaptiveKeys = 'ADAPTIVE_PLUGIN_KIND' | 'ComponentSpec'; -export type ConfigDiagnostic = NemoFlowPluginHost.ConfigDiagnostic; -export type ConfigReport = NemoFlowPluginHost.ConfigReport; +export type ConfigDiagnostic = NemoRelayPluginHost.ConfigDiagnostic; +export type ConfigReport = NemoRelayPluginHost.ConfigReport; /** - * @internal Package-owned subset of the dynamically imported `nemo-flow-node` + * @internal Package-owned subset of the dynamically imported `nemo-relay-node` * namespace used by this integration. */ -export type NemoFlowRuntimeModule = Omit, "ScopeType"> & { - ScopeType: { - Agent?: Parameters[1]; - } | undefined; +export type NemoRelayRuntimeModule = Omit, 'ScopeType'> & { + ScopeType: + | { + Agent?: Parameters[1]; + } + | undefined; }; /** * @internal Package-owned subset of the dynamically imported - * `nemo-flow-node/plugin` namespace used by this integration. + * `nemo-relay-node/plugin` namespace used by this integration. */ -export type NemoFlowPluginHostModule = Pick; +export type NemoRelayPluginHostModule = Pick; /** * @internal Adaptive helper subset loaded so the package verifies the built-in * adaptive plugin path is available alongside the generic plugin host. */ -export type NemoFlowAdaptiveModule = Pick; +export type NemoRelayAdaptiveModule = Pick; -export type NemoFlowModules = { - nf: NemoFlowRuntimeModule; - pluginHost: NemoFlowPluginHostModule; - adaptive: NemoFlowAdaptiveModule; +export type NemoRelayModules = { + nf: NemoRelayRuntimeModule; + pluginHost: NemoRelayPluginHostModule; + adaptive: NemoRelayAdaptiveModule; }; -export type NemoFlowModuleLoader = () => Promise; +export type NemoRelayModuleLoader = () => Promise; /** Load the runtime and plugin-host modules used by the OpenClaw integration. */ -export const defaultNemoFlowModuleLoader: NemoFlowModuleLoader = async () => { +export const defaultNemoRelayModuleLoader: NemoRelayModuleLoader = async () => { const [nf, pluginHost, adaptive] = await Promise.all([ - import("nemo-flow-node"), - import("nemo-flow-node/plugin"), - import("nemo-flow-node/adaptive"), + import('nemo-relay-node'), + import('nemo-relay-node/plugin'), + import('nemo-relay-node/adaptive'), ]); return { - nf: nf as NemoFlowRuntimeModule, - pluginHost: pluginHost as NemoFlowPluginHostModule, - adaptive: adaptive as NemoFlowAdaptiveModule, + nf: nf as NemoRelayRuntimeModule, + pluginHost: pluginHost as NemoRelayPluginHostModule, + adaptive: adaptive as NemoRelayAdaptiveModule, }; }; diff --git a/integrations/openclaw/src/openclaw-hook-types.ts b/integrations/openclaw/src/openclaw-hook-types.ts index c6ff0fbbb..188871c52 100644 --- a/integrations/openclaw/src/openclaw-hook-types.ts +++ b/integrations/openclaw/src/openclaw-hook-types.ts @@ -80,9 +80,9 @@ export type PluginHookModelCallStartedEvent = { export type PluginHookModelCallEndedEvent = PluginHookModelCallStartedEvent & { durationMs: number; - outcome: "completed" | "error"; + outcome: 'completed' | 'error'; errorCategory?: string; - failureKind?: "aborted" | "connection_closed" | "connection_reset" | "terminated" | "timeout"; + failureKind?: 'aborted' | 'connection_closed' | 'connection_reset' | 'terminated' | 'timeout'; requestPayloadBytes?: number; responseStreamBytes?: number; timeToFirstByteMs?: number; @@ -122,7 +122,7 @@ export type PluginHookSessionEndEvent = { sessionKey?: string; messageCount: number; durationMs?: number; - reason?: "new" | "reset" | "idle" | "daily" | "compaction" | "deleted" | "shutdown" | "restart" | "unknown"; + reason?: 'new' | 'reset' | 'idle' | 'daily' | 'compaction' | 'deleted' | 'shutdown' | 'restart' | 'unknown'; sessionFile?: string; transcriptArchived?: boolean; nextSessionId?: string; @@ -172,7 +172,7 @@ export type PluginHookSubagentSpawnedEvent = { childSessionKey: string; agentId: string; label?: string; - mode: "run" | "session"; + mode: 'run' | 'session'; requester?: { channel?: string; accountId?: string; @@ -185,13 +185,13 @@ export type PluginHookSubagentSpawnedEvent = { export type PluginHookSubagentEndedEvent = { targetSessionKey: string; - targetKind: "subagent" | "acp"; + targetKind: 'subagent' | 'acp'; reason: string; sendFarewell?: boolean; accountId?: string; runId?: string; endedAt?: number; - outcome?: "ok" | "error" | "timeout" | "killed" | "reset" | "deleted"; + outcome?: 'ok' | 'error' | 'timeout' | 'killed' | 'reset' | 'deleted'; error?: string; }; diff --git a/integrations/openclaw/src/runtime-state.ts b/integrations/openclaw/src/runtime-state.ts index 762210236..a54f3e75b 100644 --- a/integrations/openclaw/src/runtime-state.ts +++ b/integrations/openclaw/src/runtime-state.ts @@ -4,7 +4,7 @@ /** * Runtime lifecycle coordinator for the OpenClaw plugin. * - * This module validates config, lazy-loads NeMo Flow Node bindings, registers + * This module validates config, lazy-loads NeMo Relay Node bindings, registers * OpenClaw service/lifecycle/gateway surfaces, and forwards hooks to the replay * backend once runtime state is ready. */ @@ -13,26 +13,26 @@ import type { OpenClawPluginServiceContext, PluginLogger, PluginRuntimeLifecycleRegistration, -} from "openclaw/plugin-sdk/plugin-entry"; - -import { parseConfig } from "./config.js"; -import type { NemoFlowHookBackendConfig } from "./config.js"; -import { createHealthSnapshot, type HookReplayBackendStatus } from "./health.js"; -import type { HookReplayCounters } from "./hook-replay/session.js"; -import { HookReplayBackend } from "./hooks-backend.js"; -import type { PluginAgentToolCallMiddlewareContext } from "./openclaw-hook-types.js"; +} from 'openclaw/plugin-sdk/plugin-entry'; + +import { parseConfig } from './config.js'; +import type { NemoRelayHookBackendConfig } from './config.js'; +import { createHealthSnapshot, type HookReplayBackendStatus } from './health.js'; +import type { HookReplayCounters } from './hook-replay/session.js'; +import { HookReplayBackend } from './hooks-backend.js'; +import type { PluginAgentToolCallMiddlewareContext } from './openclaw-hook-types.js'; import { - defaultNemoFlowModuleLoader, + defaultNemoRelayModuleLoader, type ConfigDiagnostic, - type NemoFlowModules, - type NemoFlowModuleLoader, -} from "./modules.js"; -import type { RuntimeStateOptions, StartContext } from "./types.js"; - -const SERVICE_ID = "nemo-flow-observability"; -const LIFECYCLE_ID = "nemo-flow-observability-cleanup"; -const STATUS_METHOD = "nemoFlow.status"; -type RuntimeCleanupContext = Parameters>[0]; + type NemoRelayModules, + type NemoRelayModuleLoader, +} from './modules.js'; +import type { RuntimeStateOptions, StartContext } from './types.js'; + +const SERVICE_ID = 'nemo-relay-observability'; +const LIFECYCLE_ID = 'nemo-relay-observability-cleanup'; +const STATUS_METHOD = 'nemoRelay.status'; +type RuntimeCleanupContext = Parameters>[0]; type ToolCallMiddlewareOptions = { runtimes?: string[]; priority?: number; @@ -45,14 +45,14 @@ type ToolCallMiddlewareApi = { }; /** Owns one plugin runtime instance across OpenClaw service start/stop cycles. */ -export class NemoFlowRuntimeState { +export class NemoRelayRuntimeState { private readonly api: OpenClawPluginApi; - private readonly config: NemoFlowHookBackendConfig; - private readonly moduleLoader: NemoFlowModuleLoader; - private loadPromise: Promise | undefined; + private readonly config: NemoRelayHookBackendConfig; + private readonly moduleLoader: NemoRelayModuleLoader; + private loadPromise: Promise | undefined; private startPromise: Promise | undefined; - private statusValue: HookReplayBackendStatus = { state: "not_initialized" }; - private modulesValue?: NemoFlowModules; + private statusValue: HookReplayBackendStatus = { state: 'not_initialized' }; + private modulesValue?: NemoRelayModules; private backendValue: HookReplayBackend | undefined; private initializedPluginHost = false; private pluginHostOutputsHealthy = false; @@ -66,7 +66,7 @@ export class NemoFlowRuntimeState { constructor(options: RuntimeStateOptions) { this.api = options.api; this.config = options.config; - this.moduleLoader = options.moduleLoader ?? defaultNemoFlowModuleLoader; + this.moduleLoader = options.moduleLoader ?? defaultNemoRelayModuleLoader; } /** Return the current coarse backend status. */ @@ -92,12 +92,12 @@ export class NemoFlowRuntimeState { }); } - /** Start NeMo Flow modules, generic plugins, and the hook replay backend. */ + /** Start NeMo Relay modules, generic plugins, and the hook replay backend. */ async start(ctx: StartContext): Promise { this.lastStartContext = copyStartContext(ctx); this.missingStartContextLogged = false; - if (this.started || this.statusValue.state === "ready" || this.statusValue.state === "degraded") { + if (this.started || this.statusValue.state === 'ready' || this.statusValue.state === 'degraded') { return; } @@ -120,14 +120,14 @@ export class NemoFlowRuntimeState { this.initializedPluginHost = false; this.pluginHostOutputsHealthy = false; - let modules: NemoFlowModules; + let modules: NemoRelayModules; try { this.loadPromise ??= this.moduleLoader(); modules = await this.loadPromise; this.modulesValue = modules; } catch (error) { this.loadPromise = undefined; - this.statusValue = { state: "degraded", reason: `failed to load nemo-flow-node: ${toMessage(error)}` }; + this.statusValue = { state: 'degraded', reason: `failed to load nemo-relay-node: ${toMessage(error)}` }; if (!this.unavailableLogged) { ctx.logger.warn?.(this.statusValue.reason); this.unavailableLogged = true; @@ -135,7 +135,7 @@ export class NemoFlowRuntimeState { return; } - const hostConfig = this.config.plugins as Parameters[0]; + const hostConfig = this.config.plugins as Parameters[0]; let degradedReason; const validationReport = validatePluginHostConfig(modules, hostConfig, ctx.logger); @@ -143,27 +143,27 @@ export class NemoFlowRuntimeState { if (!validationReport.ok) { degradedReason = validationReport.reason; ctx.logger.warn?.(degradedReason); - } else if (validationReport.report.diagnostics.some((diagnostic) => diagnostic.level === "error")) { - degradedReason = "NeMo Flow plugin host config validation failed"; + } else if (validationReport.report.diagnostics.some((diagnostic) => diagnostic.level === 'error')) { + degradedReason = 'NeMo Relay plugin host config validation failed'; } else { if ( - validationReport.report.diagnostics.some((diagnostic) => diagnostic.level === "warning") && + validationReport.report.diagnostics.some((diagnostic) => diagnostic.level === 'warning') && degradedReason === undefined ) { - degradedReason = "NeMo Flow plugin host config validation produced warnings"; + degradedReason = 'NeMo Relay plugin host config validation produced warnings'; } try { const activationReport = await modules.pluginHost.initialize(hostConfig); logDiagnostics(ctx.logger, activationReport.diagnostics); this.initializedPluginHost = true; - const hasInitializationErrors = activationReport.diagnostics.some((diagnostic) => diagnostic.level === "error"); + const hasInitializationErrors = activationReport.diagnostics.some((diagnostic) => diagnostic.level === 'error'); this.pluginHostOutputsHealthy = !hasInitializationErrors; if (hasInitializationErrors) { - degradedReason ??= "NeMo Flow plugin host initialization reported errors"; + degradedReason ??= 'NeMo Relay plugin host initialization reported errors'; } } catch (error) { - degradedReason = `failed to initialize NeMo Flow plugin host: ${toMessage(error)}`; + degradedReason = `failed to initialize NeMo Relay plugin host: ${toMessage(error)}`; ctx.logger.warn?.(degradedReason); } } @@ -176,12 +176,13 @@ export class NemoFlowRuntimeState { }); this.registerBeforeExit(ctx.logger); this.started = true; - this.statusValue = degradedReason === undefined ? { state: "ready" } : { state: "degraded", reason: degradedReason }; + this.statusValue = + degradedReason === undefined ? { state: 'ready' } : { state: 'degraded', reason: degradedReason }; } /** Stop the runtime because OpenClaw service or gateway shutdown is happening. */ async stop(reason: string, logger?: PluginLogger): Promise { - await this.stopWithStatus(reason, logger, { state: "stopped", reason }); + await this.stopWithStatus(reason, logger, { state: 'stopped', reason }); } /** Apply conditional-execution guardrails before an OpenClaw tool call proceeds. */ @@ -208,9 +209,9 @@ export class NemoFlowRuntimeState { finalStatus: HookReplayBackendStatus, ): Promise { if ( - this.statusValue.state === "stopped" || - this.statusValue.state === "disabled" || - this.statusValue.state === "stopping" + this.statusValue.state === 'stopped' || + this.statusValue.state === 'disabled' || + this.statusValue.state === 'stopping' ) { return; } @@ -218,18 +219,18 @@ export class NemoFlowRuntimeState { if (this.startPromise) { await this.startPromise.catch((error) => { const log = logger ?? this.api.logger; - log.warn?.(`failed to finish NeMo Flow startup before stop: ${toMessage(error)}`); + log.warn?.(`failed to finish NeMo Relay startup before stop: ${toMessage(error)}`); }); } - this.statusValue = { state: "stopping" }; + this.statusValue = { state: 'stopping' }; const log = logger ?? this.api.logger; this.removeBeforeExitListener(); try { await this.backendValue?.drainForGatewayStop(reason); } catch (error) { - log.warn?.(`failed to stop NeMo Flow hook backend: ${toMessage(error)}`); + log.warn?.(`failed to stop NeMo Relay hook backend: ${toMessage(error)}`); } const backendState = this.backendValue?.state(); if (backendState) { @@ -241,7 +242,7 @@ export class NemoFlowRuntimeState { try { this.modulesValue.pluginHost.clear(); } catch (error) { - log.warn?.(`failed to clear NeMo Flow plugin host: ${toMessage(error)}`); + log.warn?.(`failed to clear NeMo Relay plugin host: ${toMessage(error)}`); } this.initializedPluginHost = false; this.pluginHostOutputsHealthy = false; @@ -265,7 +266,9 @@ export class NemoFlowRuntimeState { await this.stopWithStatus( ctx.reason, this.api.logger, - ctx.reason === "restart" ? { state: "not_initialized", reason: "restart" } : { state: "stopped", reason: ctx.reason }, + ctx.reason === 'restart' + ? { state: 'not_initialized', reason: 'restart' } + : { state: 'stopped', reason: ctx.reason }, ); } @@ -275,14 +278,14 @@ export class NemoFlowRuntimeState { return this.backendValue; } - if (this.statusValue.state === "disabled" || this.statusValue.state === "stopping") { + if (this.statusValue.state === 'disabled' || this.statusValue.state === 'stopping') { return undefined; } const startContext = this.lastStartContext ?? this.startContextFromRuntime(workspaceDir); if (!startContext) { if (!this.missingStartContextLogged) { - this.api.logger.warn?.("nemo-flow skipped hook replay because OpenClaw service start context is unavailable"); + this.api.logger.warn?.('nemo-relay skipped hook replay because OpenClaw service start context is unavailable'); this.missingStartContextLogged = true; } return undefined; @@ -322,78 +325,70 @@ export class NemoFlowRuntimeState { /** Register every OpenClaw hook used by the observability backend. */ registerHooks(): void { - this.api.on("gateway_start", async (event, ctx) => { - await this.replayWithBackend("gateway_start", ctx.workspaceDir, (backend) => - backend.onGatewayStart(event, ctx), - ); + this.api.on('gateway_start', async (event, ctx) => { + await this.replayWithBackend('gateway_start', ctx.workspaceDir, (backend) => backend.onGatewayStart(event, ctx)); }); - this.api.on("gateway_stop", async (event) => { - await this.stop(event.reason ?? "gateway_stop", this.api.logger); + this.api.on('gateway_stop', async (event) => { + await this.stop(event.reason ?? 'gateway_stop', this.api.logger); }); - this.api.on("session_start", async (event, ctx) => { - await this.replayWithBackend("session_start", undefined, (backend) => backend.onSessionStart(event, ctx)); + this.api.on('session_start', async (event, ctx) => { + await this.replayWithBackend('session_start', undefined, (backend) => backend.onSessionStart(event, ctx)); }); - this.api.on("session_end", async (event, ctx) => { - await this.replayWithBackendAsync("session_end", undefined, (backend) => backend.onSessionEnd(event, ctx)); + this.api.on('session_end', async (event, ctx) => { + await this.replayWithBackendAsync('session_end', undefined, (backend) => backend.onSessionEnd(event, ctx)); }); - this.api.on("llm_input", async (event, ctx) => { - await this.replayWithBackend("llm_input", ctx.workspaceDir, (backend) => backend.onLlmInput(event, ctx)); + this.api.on('llm_input', async (event, ctx) => { + await this.replayWithBackend('llm_input', ctx.workspaceDir, (backend) => backend.onLlmInput(event, ctx)); }); - this.api.on("llm_output", async (event, ctx) => { - await this.replayWithBackend("llm_output", ctx.workspaceDir, (backend) => backend.onLlmOutput(event, ctx)); + this.api.on('llm_output', async (event, ctx) => { + await this.replayWithBackend('llm_output', ctx.workspaceDir, (backend) => backend.onLlmOutput(event, ctx)); }); - this.api.on("model_call_started", async (event, ctx) => { - await this.replayWithBackend("model_call_started", ctx.workspaceDir, (backend) => + this.api.on('model_call_started', async (event, ctx) => { + await this.replayWithBackend('model_call_started', ctx.workspaceDir, (backend) => backend.onModelCallStarted(event, ctx), ); }); - this.api.on("model_call_ended", async (event, ctx) => { - await this.replayWithBackend("model_call_ended", ctx.workspaceDir, (backend) => + this.api.on('model_call_ended', async (event, ctx) => { + await this.replayWithBackend('model_call_ended', ctx.workspaceDir, (backend) => backend.onModelCallEnded(event, ctx), ); }); - this.api.on("after_tool_call", async (event, ctx) => { - await this.replayWithBackend("after_tool_call", undefined, (backend) => - backend.onAfterToolCall(event, ctx), - ); + this.api.on('after_tool_call', async (event, ctx) => { + await this.replayWithBackend('after_tool_call', undefined, (backend) => backend.onAfterToolCall(event, ctx)); }); - this.api.on("before_message_write", (event, ctx) => { + this.api.on('before_message_write', (event, ctx) => { const backend = this.backendValue; if (!backend) { return; } - backend.safeReplay("before_message_write", undefined, () => backend.onBeforeMessageWrite(event, ctx)); + backend.safeReplay('before_message_write', undefined, () => backend.onBeforeMessageWrite(event, ctx)); }); - this.api.on("agent_end", async (event, ctx) => { - await this.replayWithBackend("agent_end", ctx.workspaceDir, (backend) => backend.onAgentEnd(event, ctx)); + this.api.on('agent_end', async (event, ctx) => { + await this.replayWithBackend('agent_end', ctx.workspaceDir, (backend) => backend.onAgentEnd(event, ctx)); }); - this.api.on("before_agent_finalize", async (event, ctx) => { - await this.replayWithBackend("before_agent_finalize", ctx.workspaceDir, (backend) => + this.api.on('before_agent_finalize', async (event, ctx) => { + await this.replayWithBackend('before_agent_finalize', ctx.workspaceDir, (backend) => backend.onBeforeAgentFinalize(event, ctx), ); }); - this.api.on("subagent_spawned", async (event, ctx) => { - await this.replayWithBackend("subagent_spawned", undefined, (backend) => - backend.onSubagentSpawned(event, ctx), - ); + this.api.on('subagent_spawned', async (event, ctx) => { + await this.replayWithBackend('subagent_spawned', undefined, (backend) => backend.onSubagentSpawned(event, ctx)); }); - this.api.on("subagent_ended", async (event, ctx) => { - await this.replayWithBackend("subagent_ended", undefined, (backend) => - backend.onSubagentEnded(event, ctx), - ); + this.api.on('subagent_ended', async (event, ctx) => { + await this.replayWithBackend('subagent_ended', undefined, (backend) => backend.onSubagentEnded(event, ctx)); }); } @@ -405,11 +400,11 @@ export class NemoFlowRuntimeState { stateDir, logger: this.api.logger, resolvePath: this.api.resolvePath, - agentVersion: this.api.version ?? "unknown", + agentVersion: this.api.version ?? 'unknown', ...(workspaceDir === undefined ? {} : { workspaceDir }), }; } catch (error) { - this.api.logger.warn?.(`nemo-flow could not resolve OpenClaw runtime state dir: ${toMessage(error)}`); + this.api.logger.warn?.(`nemo-relay could not resolve OpenClaw runtime state dir: ${toMessage(error)}`); return undefined; } } @@ -420,11 +415,11 @@ export class NemoFlowRuntimeState { return; } const listener = () => { - void this.stop("beforeExit", logger).catch((error) => { - logger.warn?.(`nemo-flow beforeExit cleanup failed: ${toMessage(error)}`); + void this.stop('beforeExit', logger).catch((error) => { + logger.warn?.(`nemo-relay beforeExit cleanup failed: ${toMessage(error)}`); }); }; - process.on("beforeExit", listener); + process.on('beforeExit', listener); this.beforeExitListener = listener; } @@ -433,17 +428,14 @@ export class NemoFlowRuntimeState { if (!this.beforeExitListener) { return; } - process.removeListener("beforeExit", this.beforeExitListener); + process.removeListener('beforeExit', this.beforeExitListener); delete this.beforeExitListener; } } -/** Register the NeMo Flow observability plugin with the OpenClaw plugin API. */ -export function registerNemoFlowPlugin( - api: OpenClawPluginApi, - moduleLoader?: NemoFlowModuleLoader, -): void { - if (api.registrationMode !== "full") { +/** Register the NeMo Relay observability plugin with the OpenClaw plugin API. */ +export function registerNemoRelayPlugin(api: OpenClawPluginApi, moduleLoader?: NemoRelayModuleLoader): void { + if (api.registrationMode !== 'full') { return; } @@ -451,18 +443,16 @@ export function registerNemoFlowPlugin( try { config = parseConfig(api.pluginConfig); } catch (error) { - api.logger.warn?.( - `nemo-flow observability disabled because plugin config is invalid: ${toMessage(error)}`, - ); + api.logger.warn?.(`nemo-relay observability disabled because plugin config is invalid: ${toMessage(error)}`); return; } if (!config.enabled) { - api.logger.info?.("nemo-flow observability disabled by plugin config"); + api.logger.info?.('nemo-relay observability disabled by plugin config'); return; } - const runtime = new NemoFlowRuntimeState( + const runtime = new NemoRelayRuntimeState( moduleLoader === undefined ? { api, config } : { api, config, moduleLoader }, ); @@ -473,15 +463,15 @@ export function registerNemoFlowPlugin( stateDir: ctx.stateDir, logger: ctx.logger, resolvePath: api.resolvePath, - agentVersion: api.version ?? "unknown", + agentVersion: api.version ?? 'unknown', ...(ctx.workspaceDir === undefined ? {} : { workspaceDir: ctx.workspaceDir }), }), - stop: (ctx: OpenClawPluginServiceContext) => runtime.stop("service_stop", ctx.logger), + stop: (ctx: OpenClawPluginServiceContext) => runtime.stop('service_stop', ctx.logger), }); api.registerRuntimeLifecycle({ id: LIFECYCLE_ID, - description: "Clean up NeMo Flow OpenClaw observability plugin state", + description: 'Clean up NeMo Relay OpenClaw observability plugin state', cleanup: (ctx) => runtime.cleanup(ctx), }); @@ -491,7 +481,7 @@ export function registerNemoFlowPlugin( respond(true, runtime.health()); }, { - scope: "operator.admin", + scope: 'operator.admin', }, ); @@ -499,9 +489,9 @@ export function registerNemoFlowPlugin( registerToolCallMiddleware(api, runtime); } -function registerToolCallMiddleware(api: OpenClawPluginApi, runtime: NemoFlowRuntimeState): void { +function registerToolCallMiddleware(api: OpenClawPluginApi, runtime: NemoRelayRuntimeState): void { const register = (api as OpenClawPluginApi & ToolCallMiddlewareApi).registerAgentToolCallMiddleware; - if (typeof register !== "function") { + if (typeof register !== 'function') { return; } @@ -511,18 +501,16 @@ function registerToolCallMiddleware(api: OpenClawPluginApi, runtime: NemoFlowRun await runtime.guardToolCall(ctx); return await ctx.execute(ctx.params); }, - { runtimes: ["pi"], priority: 100 }, + { runtimes: ['pi'], priority: 100 }, ); } -/** Validate the NeMo Flow plugin-host config and log diagnostics. */ +/** Validate the NeMo Relay plugin-host config and log diagnostics. */ function validatePluginHostConfig( - modules: NemoFlowModules, - config: Parameters[0], + modules: NemoRelayModules, + config: Parameters[0], logger: PluginLogger, -): - | { ok: true; report: ReturnType } - | { ok: false; reason: string } { +): { ok: true; report: ReturnType } | { ok: false; reason: string } { try { const report = modules.pluginHost.validate(config); logDiagnostics(logger, report.diagnostics); @@ -530,7 +518,7 @@ function validatePluginHostConfig( } catch (error) { return { ok: false, - reason: `failed to validate NeMo Flow plugin host config: ${toMessage(error)}`, + reason: `failed to validate NeMo Relay plugin host config: ${toMessage(error)}`, }; } } @@ -538,9 +526,9 @@ function validatePluginHostConfig( /** Log plugin-host diagnostics at warning or info level based on severity. */ function logDiagnostics(logger: PluginLogger, diagnostics: ConfigDiagnostic[]): void { for (const diagnostic of diagnostics) { - const prefix = diagnostic.component ? `${diagnostic.component}: ` : ""; + const prefix = diagnostic.component ? `${diagnostic.component}: ` : ''; const message = `${prefix}${diagnostic.code}: ${diagnostic.message}`; - if (diagnostic.level === "error") { + if (diagnostic.level === 'error') { logger.warn?.(message); } else { logger.info?.(message); diff --git a/integrations/openclaw/src/types.ts b/integrations/openclaw/src/types.ts index 499d33816..4429bf503 100644 --- a/integrations/openclaw/src/types.ts +++ b/integrations/openclaw/src/types.ts @@ -7,23 +7,23 @@ * These types avoid importing OpenClaw implementation modules outside the public * plugin SDK surface and keep runtime-state constructor signatures explicit. */ -import type { OpenClawPluginApi, OpenClawPluginServiceContext } from "openclaw/plugin-sdk/plugin-entry"; +import type { OpenClawPluginApi, OpenClawPluginServiceContext } from 'openclaw/plugin-sdk/plugin-entry'; -import type { NemoFlowHookBackendConfig } from "./config.js"; -import type { HookReplayBackendStatus } from "./health.js"; -import type { NemoFlowModuleLoader } from "./modules.js"; +import type { NemoRelayHookBackendConfig } from './config.js'; +import type { HookReplayBackendStatus } from './health.js'; +import type { NemoRelayModuleLoader } from './modules.js'; export type RuntimeStateOptions = { api: OpenClawPluginApi; - config: NemoFlowHookBackendConfig; - moduleLoader?: NemoFlowModuleLoader; + config: NemoRelayHookBackendConfig; + moduleLoader?: NemoRelayModuleLoader; }; export type StartContext = { stateDir: string; workspaceDir?: string; - logger: OpenClawPluginServiceContext["logger"]; - resolvePath: OpenClawPluginApi["resolvePath"]; + logger: OpenClawPluginServiceContext['logger']; + resolvePath: OpenClawPluginApi['resolvePath']; agentVersion: string; }; diff --git a/integrations/openclaw/test/config.test.ts b/integrations/openclaw/test/config.test.ts index d0e385f22..f82212709 100644 --- a/integrations/openclaw/test/config.test.ts +++ b/integrations/openclaw/test/config.test.ts @@ -4,37 +4,33 @@ /** * Plugin config and registration tests for the OpenClaw integration shell. */ -import assert from "node:assert/strict"; -import { readdirSync, readFileSync } from "node:fs"; -import * as fs from "node:fs/promises"; -import * as os from "node:os"; -import * as path from "node:path"; -import { describe, it } from "node:test"; - -import { - NEMO_FLOW_OPENCLAW_JSON_SCHEMA, - nemoFlowConfigSchema, - parseConfig, -} from "../src/config.js"; +import assert from 'node:assert/strict'; +import { readdirSync, readFileSync } from 'node:fs'; +import * as fs from 'node:fs/promises'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import { describe, it } from 'node:test'; + +import { NEMO_RELAY_OPENCLAW_JSON_SCHEMA, nemoRelayConfigSchema, parseConfig } from '../src/config.js'; import { - defaultNemoFlowModuleLoader, - type NemoFlowModuleLoader, - type NemoFlowModules, - type NemoFlowRuntimeModule, -} from "../src/modules.js"; -import { registerNemoFlowPlugin } from "../src/runtime-state.js"; -import type { PluginAgentToolCallMiddlewareContext } from "../src/openclaw-hook-types.js"; -import type { OpenClawPluginApi, PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; -import { callGatewayStatus, type TestGatewayMethodHandler } from "./gateway-status.js"; - -const liveSmokeEnabled = process.env.NEMO_FLOW_OPENCLAW_LIVE_SMOKE === "1"; - -describe("nemo-flow OpenClaw plugin shell", () => { - it("applies hook-backend config defaults", () => { + defaultNemoRelayModuleLoader, + type NemoRelayModuleLoader, + type NemoRelayModules, + type NemoRelayRuntimeModule, +} from '../src/modules.js'; +import { registerNemoRelayPlugin } from '../src/runtime-state.js'; +import type { PluginAgentToolCallMiddlewareContext } from '../src/openclaw-hook-types.js'; +import type { OpenClawPluginApi, PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; +import { callGatewayStatus, type TestGatewayMethodHandler } from './gateway-status.js'; + +const liveSmokeEnabled = process.env.NEMO_RELAY_OPENCLAW_LIVE_SMOKE === '1'; + +describe('nemo-relay OpenClaw plugin shell', () => { + it('applies hook-backend config defaults', () => { const config = parseConfig(undefined); assert.equal(config.enabled, true); - assert.equal(config.backend, "hooks"); + assert.equal(config.backend, 'hooks'); assert.deepEqual(config.plugins, { version: 1, components: [] }); assert.deepEqual(config.capture, { includePrompts: true, @@ -49,20 +45,20 @@ describe("nemo-flow OpenClaw plugin shell", () => { }); }); - it("keeps the generic plugin config shape under top-level plugins", () => { + it('keeps the generic plugin config shape under top-level plugins', () => { const pluginConfig = { version: 1, components: [ { - kind: "observability", + kind: 'observability', enabled: true, config: { version: 1, - atif: { enabled: true, agent_name: "openclaw" }, + atif: { enabled: true, agent_name: 'openclaw' }, }, }, ], - policy: { unknown_component: "error" }, + policy: { unknown_component: 'error' }, }; const config = parseConfig({ plugins: pluginConfig }); @@ -70,30 +66,30 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.deepEqual(config.plugins, pluginConfig); }); - it("keeps adaptive components in the generic plugin config path", () => { + it('keeps adaptive components in the generic plugin config path', () => { const pluginConfig = { version: 1, components: [ { - kind: "adaptive", + kind: 'adaptive', enabled: true, config: { version: 1, - agent_id: "openclaw", + agent_id: 'openclaw', state: { backend: { - kind: "in_memory", + kind: 'in_memory', config: {}, }, }, telemetry: { - learners: ["tool_parallelism"], + learners: ['tool_parallelism'], }, adaptive_hints: { priority: 100, break_chain: false, inject_header: true, - inject_body_path: "nvext.agent_hints", + inject_body_path: 'nvext.agent_hints', }, }, }, @@ -105,10 +101,10 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.deepEqual(config.plugins, pluginConfig); }); - it("rejects unsupported backends and invalid correlation values", () => { + it('rejects unsupported backends and invalid correlation values', () => { assert.throws( - () => parseConfig({ backend: "managed_execution" }), - /unsupported nemo-flow backend: managed_execution/, + () => parseConfig({ backend: 'managed_execution' }), + /unsupported nemo-relay backend: managed_execution/, ); assert.throws( () => parseConfig({ correlation: { llmOutputGraceMs: -1 } }), @@ -124,7 +120,7 @@ describe("nemo-flow OpenClaw plugin shell", () => { ); }); - it("rejects removed specialized OpenClaw output fields with migration errors", () => { + it('rejects removed specialized OpenClaw output fields with migration errors', () => { assert.throws( () => parseConfig({ atif: { enabled: true } }), /atif was removed; configure plugins\.components\[\]\.config\.atif/, @@ -134,21 +130,21 @@ describe("nemo-flow OpenClaw plugin shell", () => { /telemetry was removed; configure plugins\.components\[\]\.config\.opentelemetry or openinference/, ); assert.throws( - () => parseConfig({ nemoFlow: { pluginConfig: { version: 1, components: [] } } }), - /nemoFlow\.pluginConfig was removed; use top-level plugins instead/, + () => parseConfig({ nemoRelay: { pluginConfig: { version: 1, components: [] } } }), + /nemoRelay\.pluginConfig was removed; use top-level plugins instead/, ); }); - it("wraps manifest JSON Schema in OpenClawPluginConfigSchema", () => { - assert.equal(typeof nemoFlowConfigSchema.safeParse, "function"); - assert.deepEqual(nemoFlowConfigSchema.jsonSchema, NEMO_FLOW_OPENCLAW_JSON_SCHEMA); - assert.equal(nemoFlowConfigSchema.safeParse?.({ backend: "hooks" }).success, true); - assert.equal(nemoFlowConfigSchema.safeParse?.({ backend: "bad" }).success, false); - assert.equal(nemoFlowConfigSchema.safeParse?.({ atif: { enabled: true } }).success, false); + it('wraps manifest JSON Schema in OpenClawPluginConfigSchema', () => { + assert.equal(typeof nemoRelayConfigSchema.safeParse, 'function'); + assert.deepEqual(nemoRelayConfigSchema.jsonSchema, NEMO_RELAY_OPENCLAW_JSON_SCHEMA); + assert.equal(nemoRelayConfigSchema.safeParse?.({ backend: 'hooks' }).success, true); + assert.equal(nemoRelayConfigSchema.safeParse?.({ backend: 'bad' }).success, false); + assert.equal(nemoRelayConfigSchema.safeParse?.({ atif: { enabled: true } }).success, false); }); - it("returns without side effects outside full registration mode", () => { - const api = createApi({ registrationMode: "discovery" }); + it('returns without side effects outside full registration mode', () => { + const api = createApi({ registrationMode: 'discovery' }); registerPlugin(api); @@ -159,7 +155,7 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.equal(api.calls.toolMiddlewares.length, 0); }); - it("returns without side effects when disabled", () => { + it('returns without side effects when disabled', () => { const api = createApi({ pluginConfig: { enabled: false } }); registerPlugin(api); @@ -169,11 +165,11 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.equal(api.calls.gatewayMethods.length, 0); assert.equal(api.calls.hooks.length, 0); assert.equal(api.calls.toolMiddlewares.length, 0); - assert.deepEqual(api.messages.info, ["nemo-flow observability disabled by plugin config"]); + assert.deepEqual(api.messages.info, ['nemo-relay observability disabled by plugin config']); }); - it("returns without side effects when config parsing fails during registration", () => { - const api = createApi({ pluginConfig: { backend: "managed_execution" } }); + it('returns without side effects when config parsing fails during registration', () => { + const api = createApi({ pluginConfig: { backend: 'managed_execution' } }); registerPlugin(api); @@ -182,45 +178,52 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.equal(api.calls.gatewayMethods.length, 0); assert.equal(api.calls.hooks.length, 0); assert.equal(api.calls.toolMiddlewares.length, 0); - assert.match( - api.messages.warn[0] ?? "", - /nemo-flow observability disabled because plugin config is invalid/, - ); + assert.match(api.messages.warn[0] ?? '', /nemo-relay observability disabled because plugin config is invalid/); }); - it("registers service, lifecycle, and health surfaces in full mode", () => { + it('registers service, lifecycle, and health surfaces in full mode', () => { const api = createApi(); registerPlugin(api, async () => createModules()); - assert.deepEqual(api.calls.services.map((service) => service.id), ["nemo-flow-observability"]); - assert.deepEqual(api.calls.lifecycle.map((lifecycle) => lifecycle.id), ["nemo-flow-observability-cleanup"]); - assert.deepEqual(api.calls.gatewayMethods.map((method) => method.method), ["nemoFlow.status"]); - assert.deepEqual(api.calls.toolMiddlewares.map((middleware) => middleware.options), [ - { runtimes: ["pi"], priority: 100 }, - ]); + assert.deepEqual( + api.calls.services.map((service) => service.id), + ['nemo-relay-observability'], + ); + assert.deepEqual( + api.calls.lifecycle.map((lifecycle) => lifecycle.id), + ['nemo-relay-observability-cleanup'], + ); + assert.deepEqual( + api.calls.gatewayMethods.map((method) => method.method), + ['nemoRelay.status'], + ); + assert.deepEqual( + api.calls.toolMiddlewares.map((middleware) => middleware.options), + [{ runtimes: ['pi'], priority: 100 }], + ); assert.deepEqual( api.calls.hooks.map((hook) => hook.hookName), [ - "gateway_start", - "gateway_stop", - "session_start", - "session_end", - "llm_input", - "llm_output", - "model_call_started", - "model_call_ended", - "after_tool_call", - "before_message_write", - "agent_end", - "before_agent_finalize", - "subagent_spawned", - "subagent_ended", + 'gateway_start', + 'gateway_stop', + 'session_start', + 'session_end', + 'llm_input', + 'llm_output', + 'model_call_started', + 'model_call_ended', + 'after_tool_call', + 'before_message_write', + 'agent_end', + 'before_agent_finalize', + 'subagent_spawned', + 'subagent_ended', ], ); }); - it("runs tool conditional guardrails before OpenClaw tool middleware execution", async () => { + it('runs tool conditional guardrails before OpenClaw tool middleware execution', async () => { const modules = createModules(); const api = createApi(); @@ -229,25 +232,23 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.ok(middleware); const result = await middleware.handler({ - toolName: "shell", - params: { command: "pwd" }, - sessionId: "session-1", - sessionKey: "agent:main:session-1", - runId: "run-1", - agentId: "agent-1", + toolName: 'shell', + params: { command: 'pwd' }, + sessionId: 'session-1', + sessionKey: 'agent:main:session-1', + runId: 'run-1', + agentId: 'agent-1', execute: async (params) => ({ ok: true, params }), }); - assert.deepEqual(result, { ok: true, params: { command: "pwd" } }); - assert.deepEqual(modules.nf.calls.toolConditionalExecution, [ - { name: "shell", args: { command: "pwd" } }, - ]); + assert.deepEqual(result, { ok: true, params: { command: 'pwd' } }); + assert.deepEqual(modules.nf.calls.toolConditionalExecution, [{ name: 'shell', args: { command: 'pwd' } }]); }); - it("does not execute OpenClaw tools when conditional guardrails reject", async () => { + it('does not execute OpenClaw tools when conditional guardrails reject', async () => { const modules = createModules(); modules.nf.toolConditionalExecution = async () => { - throw new Error("guardrail rejected: blocked by policy"); + throw new Error('guardrail rejected: blocked by policy'); }; const api = createApi(); let executed = false; @@ -259,9 +260,9 @@ describe("nemo-flow OpenClaw plugin shell", () => { await assert.rejects( () => middleware.handler({ - toolName: "shell", - params: { command: "rm -rf /tmp/demo" }, - sessionId: "session-1", + toolName: 'shell', + params: { command: 'rm -rf /tmp/demo' }, + sessionId: 'session-1', execute: async () => { executed = true; return { ok: true }; @@ -272,51 +273,51 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.equal(executed, false); }); - it("uses config parsed during registration when service starts", async () => { + it('uses config parsed during registration when service starts', async () => { const api = createApi({ pluginConfig: { correlation: { maxRecordsPerKey: 1 } } }); registerPlugin(api, async () => createModules()); - api.pluginConfig = { backend: "managed_execution" }; + api.pluginConfig = { backend: 'managed_execution' }; const service = api.calls.services[0]; assert.ok(service); try { await assert.doesNotReject(async () => { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); }); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); - it("validates and initializes configured generic plugin components", async () => { + it('validates and initializes configured generic plugin components', async () => { const configuredPlugins = { version: 1, components: [ { - kind: "observability", + kind: 'observability', enabled: true, config: { version: 1, - atif: { enabled: true, agent_name: "openclaw" }, - opentelemetry: { enabled: true, endpoint: "http://otel.example" }, - openinference: { enabled: true, endpoint: "http://phoenix.example" }, + atif: { enabled: true, agent_name: 'openclaw' }, + opentelemetry: { enabled: true, endpoint: 'http://otel.example' }, + openinference: { enabled: true, endpoint: 'http://phoenix.example' }, }, }, { - kind: "adaptive", + kind: 'adaptive', enabled: true, config: { version: 1, - agent_id: "openclaw", + agent_id: 'openclaw', state: { backend: { - kind: "in_memory", + kind: 'in_memory', config: {}, }, }, telemetry: { - learners: ["tool_parallelism"], + learners: ['tool_parallelism'], }, }, }, @@ -329,33 +330,33 @@ describe("nemo-flow OpenClaw plugin shell", () => { const service = api.calls.services[0]; assert.ok(service); try { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); assert.deepEqual(modules.pluginHost.calls.validate, [configuredPlugins]); assert.deepEqual(modules.pluginHost.calls.initialize, [configuredPlugins]); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.status.state, "ready"); + assert.equal(status.status.state, 'ready'); assert.deepEqual(status.outputs, { - atif: "enabled", - otel: "enabled", - openInference: "enabled", + atif: 'enabled', + otel: 'enabled', + openInference: 'enabled', }); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); - it("passes adaptive helper components through plugin host initialization", async () => { + it('passes adaptive helper components through plugin host initialization', async () => { const modules = createModules(); const configuredPlugins = { version: 1, components: [ modules.adaptive.ComponentSpec({ version: 1, - agent_id: "openclaw-helper", + agent_id: 'openclaw-helper', state: { backend: { - kind: "in_memory", + kind: 'in_memory', config: {}, }, }, @@ -363,7 +364,7 @@ describe("nemo-flow OpenClaw plugin shell", () => { priority: 100, break_chain: false, inject_header: true, - inject_body_path: "nvext.agent_hints", + inject_body_path: 'nvext.agent_hints', }, }), ], @@ -374,20 +375,20 @@ describe("nemo-flow OpenClaw plugin shell", () => { const service = api.calls.services[0]; assert.ok(service); try { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); assert.deepEqual(modules.pluginHost.calls.validate, [configuredPlugins]); assert.deepEqual(modules.pluginHost.calls.initialize, [configuredPlugins]); assert.equal(configuredPlugins.components[0]?.kind, modules.adaptive.ADAPTIVE_PLUGIN_KIND); assert.equal(configuredPlugins.components[0]?.enabled, true); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); - it("continues hook-backed telemetry when plugin host validation fails", async () => { + it('continues hook-backed telemetry when plugin host validation fails', async () => { const modules = createModules({ - validateDiagnostics: [{ level: "error", code: "bad_config", message: "invalid" }], + validateDiagnostics: [{ level: 'error', code: 'bad_config', message: 'invalid' }], }); const api = createApi({ pluginConfig: { @@ -395,7 +396,7 @@ describe("nemo-flow OpenClaw plugin shell", () => { version: 1, components: [ { - kind: "observability", + kind: 'observability', config: { version: 1, atif: { enabled: true } }, }, ], @@ -407,25 +408,28 @@ describe("nemo-flow OpenClaw plugin shell", () => { const service = api.calls.services[0]; assert.ok(service); try { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); assert.ok(sessionStart); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); - assert.equal(status.status.state, "degraded"); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); + assert.equal(status.status.state, 'degraded'); assert.equal(status.initializedPluginHost, false); - assert.equal(status.outputs.atif, "degraded"); + assert.equal(status.outputs.atif, 'degraded'); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); - it("reports configured outputs degraded when plugin host initialization returns error diagnostics", async () => { + it('reports configured outputs degraded when plugin host initialization returns error diagnostics', async () => { const modules = createModules({ - initializeDiagnostics: [{ level: "error", code: "activation_failed", message: "failed to activate" }], + initializeDiagnostics: [{ level: 'error', code: 'activation_failed', message: 'failed to activate' }], }); const api = createApi({ pluginConfig: { @@ -433,7 +437,7 @@ describe("nemo-flow OpenClaw plugin shell", () => { version: 1, components: [ { - kind: "observability", + kind: 'observability', config: { version: 1, atif: { enabled: true } }, }, ], @@ -445,21 +449,21 @@ describe("nemo-flow OpenClaw plugin shell", () => { const service = api.calls.services[0]; assert.ok(service); try { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.status.state, "degraded"); - assert.equal(status.status.reason, "NeMo Flow plugin host initialization reported errors"); + assert.equal(status.status.state, 'degraded'); + assert.equal(status.status.reason, 'NeMo Relay plugin host initialization reported errors'); assert.equal(status.initializedPluginHost, true); - assert.equal(status.outputs.atif, "degraded"); + assert.equal(status.outputs.atif, 'degraded'); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); - it("degrades hook replay when plugin host validation throws", async () => { + it('degrades hook replay when plugin host validation throws', async () => { const modules = createModules({ - validateThrows: new Error("invalid plugin document"), + validateThrows: new Error('invalid plugin document'), }); const api = createApi({ pluginConfig: { @@ -475,43 +479,46 @@ describe("nemo-flow OpenClaw plugin shell", () => { assert.ok(service); try { await assert.doesNotReject(async () => { - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); }); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); assert.ok(sessionStart); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.status.state, "degraded"); + assert.equal(status.status.state, 'degraded'); assert.equal(status.initializedPluginHost, false); - assert.match(status.status.reason, /failed to validate NeMo Flow plugin host config/); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); + assert.match(status.status.reason, /failed to validate NeMo Relay plugin host config/); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); } finally { - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); } }); it( - "exports ATIF with the documented observability component through the real plugin host", + 'exports ATIF with the documented observability component through the real plugin host', { skip: !liveSmokeEnabled }, async () => { - const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "nemo-flow-openclaw-observability-")); + const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), 'nemo-relay-openclaw-observability-')); const api = createApi({ pluginConfig: { plugins: { version: 1, components: [ { - kind: "observability", + kind: 'observability', enabled: true, config: { version: 1, atif: { enabled: true, - agent_name: "openclaw", + agent_name: 'openclaw', output_directory: outputDir, - filename_template: "openclaw-e2e-{session_id}.json", + filename_template: 'openclaw-e2e-{session_id}.json', }, }, }, @@ -522,28 +529,31 @@ describe("nemo-flow OpenClaw plugin shell", () => { let serviceStarted = false; try { - registerPlugin(api, defaultNemoFlowModuleLoader); + registerPlugin(api, defaultNemoRelayModuleLoader); const service = api.calls.services[0]; assert.ok(service); await service.start({ stateDir: outputDir, config: {} as never, logger: api.logger }); serviceStarted = true; - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); - const sessionEnd = api.calls.hooks.find((hook) => hook.hookName === "session_end"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); + const sessionEnd = api.calls.hooks.find((hook) => hook.hookName === 'session_end'); assert.ok(sessionStart); assert.ok(sessionEnd); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); - await sessionEnd.handler({ sessionId: "session-1", messageCount: 1, reason: "done" }, { sessionId: "session-1" }); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); + await sessionEnd.handler( + { sessionId: 'session-1', messageCount: 1, reason: 'done' }, + { sessionId: 'session-1' }, + ); const files = await fs.readdir(outputDir); - const atifFile = files.find((file) => file.startsWith("openclaw-e2e-") && file.endsWith(".json")); - assert.ok(atifFile, "expected generic observability ATIF export"); - const exported = JSON.parse(await fs.readFile(path.join(outputDir, atifFile), "utf8")) as unknown; - assert.equal(typeof exported, "object"); + const atifFile = files.find((file) => file.startsWith('openclaw-e2e-') && file.endsWith('.json')); + assert.ok(atifFile, 'expected generic observability ATIF export'); + const exported = JSON.parse(await fs.readFile(path.join(outputDir, atifFile), 'utf8')) as unknown; + assert.equal(typeof exported, 'object'); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.status.state, "ready"); - assert.equal(status.outputs.atif, "enabled"); + assert.equal(status.status.state, 'ready'); + assert.equal(status.outputs.atif, 'enabled'); } finally { if (serviceStarted) { await api.calls.services[0]?.stop?.({ stateDir: outputDir, config: {} as never, logger: api.logger }); @@ -553,32 +563,32 @@ describe("nemo-flow OpenClaw plugin shell", () => { }, ); - it("routes gateway_stop through runtime stop", async () => { + it('routes gateway_stop through runtime stop', async () => { const modules = createModules(); const api = createApi(); registerPlugin(api, async () => modules); const service = api.calls.services[0]; assert.ok(service); - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); - const gatewayStop = api.calls.hooks.find((hook) => hook.hookName === "gateway_stop"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); + const gatewayStop = api.calls.hooks.find((hook) => hook.hookName === 'gateway_stop'); assert.ok(sessionStart); assert.ok(gatewayStop); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); - await gatewayStop.handler({ reason: "test_stop" }, {}); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); + await gatewayStop.handler({ reason: 'test_stop' }, {}); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.status.state, "stopped"); + assert.equal(status.status.state, 'stopped'); assert.equal(status.counters.marksEmitted, 2); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), [ - "openclaw.session_start", - "openclaw.session_end", - ]); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start', 'openclaw.session_end'], + ); }); - it("keeps the runtime running for scoped lifecycle cleanup", async () => { + it('keeps the runtime running for scoped lifecycle cleanup', async () => { const modules = createModules(); const api = createApi(); @@ -587,36 +597,38 @@ describe("nemo-flow OpenClaw plugin shell", () => { const lifecycle = api.calls.lifecycle[0]; assert.ok(service); assert.ok(lifecycle?.cleanup); - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); assert.ok(sessionStart); - await sessionStart.handler({ sessionId: "session-1", sessionKey: "agent:main:session-1" }, { - sessionId: "session-1", - sessionKey: "agent:main:session-1", - }); + await sessionStart.handler( + { sessionId: 'session-1', sessionKey: 'agent:main:session-1' }, + { + sessionId: 'session-1', + sessionKey: 'agent:main:session-1', + }, + ); - await lifecycle.cleanup({ reason: "restart", sessionKey: "agent:main:session-1" }); + await lifecycle.cleanup({ reason: 'restart', sessionKey: 'agent:main:session-1' }); const statusAfterScopedCleanup = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(statusAfterScopedCleanup.status.state, "ready"); + assert.equal(statusAfterScopedCleanup.status.state, 'ready'); assert.equal(statusAfterScopedCleanup.counters.marksEmitted, 2); - await sessionStart.handler({ sessionId: "session-2" }, { sessionId: "session-2" }); + await sessionStart.handler({ sessionId: 'session-2' }, { sessionId: 'session-2' }); const statusAfterNextHook = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(statusAfterNextHook.status.state, "ready"); + assert.equal(statusAfterNextHook.status.state, 'ready'); assert.equal(statusAfterNextHook.counters.marksEmitted, 3); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), [ - "openclaw.session_start", - "openclaw.session_end", - "openclaw.session_start", - ]); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start', 'openclaw.session_end', 'openclaw.session_start'], + ); - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); }); - it("restarts hook replay after unscoped runtime restart cleanup", async () => { + it('restarts hook replay after unscoped runtime restart cleanup', async () => { const modules = createModules(); const api = createApi(); @@ -625,65 +637,71 @@ describe("nemo-flow OpenClaw plugin shell", () => { const lifecycle = api.calls.lifecycle[0]; assert.ok(service); assert.ok(lifecycle?.cleanup); - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); - await lifecycle.cleanup({ reason: "restart" }); + await lifecycle.cleanup({ reason: 'restart' }); const statusAfterRestart = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(statusAfterRestart.status.state, "not_initialized"); - assert.equal(statusAfterRestart.status.reason, "restart"); + assert.equal(statusAfterRestart.status.state, 'not_initialized'); + assert.equal(statusAfterRestart.status.reason, 'restart'); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); assert.ok(sessionStart); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); const statusAfterNextHook = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(statusAfterNextHook.status.state, "ready"); + assert.equal(statusAfterNextHook.status.state, 'ready'); assert.equal(statusAfterNextHook.counters.marksEmitted, 1); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); }); - it("starts hook replay from the OpenClaw runtime when service start has not run", async () => { + it('starts hook replay from the OpenClaw runtime when service start has not run', async () => { const modules = createModules(); const api = createApi(); registerPlugin(api, async () => modules); - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); assert.ok(sessionStart); - await sessionStart.handler({ sessionId: "session-1" }, { sessionId: "session-1" }); + await sessionStart.handler({ sessionId: 'session-1' }, { sessionId: 'session-1' }); const statusAfterHook = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(statusAfterHook.status.state, "ready"); + assert.equal(statusAfterHook.status.state, 'ready'); assert.equal(statusAfterHook.counters.marksEmitted, 1); - assert.deepEqual(modules.nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); + assert.deepEqual( + modules.nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); const service = api.calls.services[0]; assert.ok(service); - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); }); - it("removes beforeExit listener during normal stop", async () => { + it('removes beforeExit listener during normal stop', async () => { const modules = createModules(); const api = createApi(); - const before = process.listenerCount("beforeExit"); + const before = process.listenerCount('beforeExit'); registerPlugin(api, async () => modules); const service = api.calls.services[0]; assert.ok(service); - await service.start({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); - assert.equal(process.listenerCount("beforeExit"), before + 1); + await service.start({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); + assert.equal(process.listenerCount('beforeExit'), before + 1); - await service.stop?.({ stateDir: "/tmp/openclaw-state", config: {} as never, logger: api.logger }); - assert.equal(process.listenerCount("beforeExit"), before); + await service.stop?.({ stateDir: '/tmp/openclaw-state', config: {} as never, logger: api.logger }); + assert.equal(process.listenerCount('beforeExit'), before); }); - it("does not statically import nemo-flow-node or OpenClaw private src paths", () => { - const files = readBuiltJavaScriptFiles(new URL("../../", import.meta.url)); + it('does not statically import nemo-relay-node or OpenClaw private src paths', () => { + const files = readBuiltJavaScriptFiles(new URL('../../', import.meta.url)); - assert.doesNotMatch(files, /from ["']nemo-flow-node/); - assert.doesNotMatch(files, /from ["']nemo-flow-node\/plugin/); + assert.doesNotMatch(files, /from ["']nemo-relay-node/); + assert.doesNotMatch(files, /from ["']nemo-relay-node\/plugin/); assert.doesNotMatch(files, /openclaw\/src\//); }); }); @@ -691,14 +709,14 @@ describe("nemo-flow OpenClaw plugin shell", () => { function readBuiltJavaScriptFiles(directory: URL): string { const chunks: string[] = []; for (const entry of readdirSync(directory, { withFileTypes: true })) { - const child = new URL(`${entry.name}${entry.isDirectory() ? "/" : ""}`, directory); + const child = new URL(`${entry.name}${entry.isDirectory() ? '/' : ''}`, directory); if (entry.isDirectory()) { chunks.push(readBuiltJavaScriptFiles(child)); - } else if (entry.isFile() && entry.name.endsWith(".js")) { - chunks.push(readFileSync(child, "utf8")); + } else if (entry.isFile() && entry.name.endsWith('.js')) { + chunks.push(readFileSync(child, 'utf8')); } } - return chunks.join("\n"); + return chunks.join('\n'); } type HookHandler = (event: unknown, ctx: unknown) => void | Promise; @@ -707,26 +725,22 @@ type ToolMiddlewareHandler = (ctx: PluginAgentToolCallMiddlewareContext) => Prom type TestApi = { id: string; version?: string; - registrationMode: OpenClawPluginApi["registrationMode"]; + registrationMode: OpenClawPluginApi['registrationMode']; pluginConfig?: Record; logger: PluginLogger; - runtime: OpenClawPluginApi["runtime"]; - resolvePath: OpenClawPluginApi["resolvePath"]; - registerService: (service: Parameters[0]) => void; - registerRuntimeLifecycle: (lifecycle: Parameters[0]) => void; + runtime: OpenClawPluginApi['runtime']; + resolvePath: OpenClawPluginApi['resolvePath']; + registerService: (service: Parameters[0]) => void; + registerRuntimeLifecycle: (lifecycle: Parameters[0]) => void; on: (hookName: string, handler: HookHandler) => void; registerAgentToolCallMiddleware: ( handler: ToolMiddlewareHandler, options?: { runtimes?: string[]; priority?: number }, ) => void; - registerGatewayMethod: ( - method: string, - handler: TestGatewayMethodHandler, - opts?: { scope?: string }, - ) => void; + registerGatewayMethod: (method: string, handler: TestGatewayMethodHandler, opts?: { scope?: string }) => void; calls: { - services: Parameters[0][]; - lifecycle: Parameters[0][]; + services: Parameters[0][]; + lifecycle: Parameters[0][]; gatewayMethods: Array<{ method: string; handler: TestGatewayMethodHandler; @@ -743,12 +757,14 @@ type TestApi = { }; }; -function createApi(params: { - registrationMode?: OpenClawPluginApi["registrationMode"]; - pluginConfig?: Record; -} = {}): TestApi { - const messages: TestApi["messages"] = { info: [], warn: [] }; - const calls: TestApi["calls"] = { +function createApi( + params: { + registrationMode?: OpenClawPluginApi['registrationMode']; + pluginConfig?: Record; + } = {}, +): TestApi { + const messages: TestApi['messages'] = { info: [], warn: [] }; + const calls: TestApi['calls'] = { services: [], lifecycle: [], gatewayMethods: [], @@ -762,15 +778,15 @@ function createApi(params: { }; const api: TestApi = { - id: "nemo-flow", - version: "1.2.3", - registrationMode: params.registrationMode ?? "full", + id: 'nemo-relay', + version: '1.2.3', + registrationMode: params.registrationMode ?? 'full', logger, runtime: { state: { - resolveStateDir: () => "/tmp/openclaw-state", + resolveStateDir: () => '/tmp/openclaw-state', }, - } as unknown as OpenClawPluginApi["runtime"], + } as unknown as OpenClawPluginApi['runtime'], resolvePath: (input) => input, registerService: (service) => calls.services.push(service), registerRuntimeLifecycle: (lifecycle) => calls.lifecycle.push(lifecycle), @@ -789,11 +805,11 @@ function createApi(params: { return api; } -function registerPlugin(api: TestApi, moduleLoader?: NemoFlowModuleLoader): void { - registerNemoFlowPlugin(api as unknown as OpenClawPluginApi, moduleLoader); +function registerPlugin(api: TestApi, moduleLoader?: NemoRelayModuleLoader): void { + registerNemoRelayPlugin(api as unknown as OpenClawPluginApi, moduleLoader); } -type TestPluginHost = NemoFlowModules["pluginHost"] & { +type TestPluginHost = NemoRelayModules['pluginHost'] & { calls: { validate: unknown[]; initialize: unknown[]; @@ -801,30 +817,32 @@ type TestPluginHost = NemoFlowModules["pluginHost"] & { }; }; -type TestNemoFlowRuntime = NemoFlowModules["nf"] & { +type TestNemoRelayRuntime = NemoRelayModules['nf'] & { calls: { event: Array<{ name: string; handle: unknown; data: unknown }>; toolConditionalExecution: Array<{ name: string; args: unknown }>; }; }; -type TestModules = NemoFlowModules & { - nf: TestNemoFlowRuntime; +type TestModules = NemoRelayModules & { + nf: TestNemoRelayRuntime; pluginHost: TestPluginHost; }; -function createModules(params: { - validateDiagnostics?: Array<{ level: "warning" | "error"; code: string; message: string }>; - validateThrows?: Error; - initializeDiagnostics?: Array<{ level: "warning" | "error"; code: string; message: string }>; -} = {}): TestModules { - const nf = createNemoFlowRuntime(); - const calls: TestPluginHost["calls"] = { validate: [], initialize: [], clear: 0 }; - const adaptive: TestModules["adaptive"] = { - ADAPTIVE_PLUGIN_KIND: "adaptive", +function createModules( + params: { + validateDiagnostics?: Array<{ level: 'warning' | 'error'; code: string; message: string }>; + validateThrows?: Error; + initializeDiagnostics?: Array<{ level: 'warning' | 'error'; code: string; message: string }>; + } = {}, +): TestModules { + const nf = createNemoRelayRuntime(); + const calls: TestPluginHost['calls'] = { validate: [], initialize: [], clear: 0 }; + const adaptive: TestModules['adaptive'] = { + ADAPTIVE_PLUGIN_KIND: 'adaptive', ComponentSpec: ( - config: Parameters[0], - options?: Parameters[1], + config: Parameters[0], + options?: Parameters[1], ) => ({ kind: adaptive.ADAPTIVE_PLUGIN_KIND, enabled: options?.enabled ?? true, @@ -855,24 +873,25 @@ function createModules(params: { }; } -function createNemoFlowRuntime(): TestNemoFlowRuntime { - const calls: TestNemoFlowRuntime["calls"] = { +function createNemoRelayRuntime(): TestNemoRelayRuntime { + const calls: TestNemoRelayRuntime['calls'] = { event: [], toolConditionalExecution: [], }; return { - ScopeType: { Agent: 0 } as NemoFlowRuntimeModule["ScopeType"], + ScopeType: { Agent: 0 } as NemoRelayRuntimeModule['ScopeType'], calls, - createScopeStack: () => ({ type: "stack" }) as unknown as ReturnType, - currentScopeStack: () => ({ type: "previous-stack" }) as unknown as ReturnType, + createScopeStack: () => ({ type: 'stack' }) as unknown as ReturnType, + currentScopeStack: () => + ({ type: 'previous-stack' }) as unknown as ReturnType, setThreadScopeStack: () => {}, - pushScope: () => ({ type: "scope" } as unknown as ReturnType), + pushScope: () => ({ type: 'scope' }) as unknown as ReturnType, popScope: () => {}, event: (name, handle, data) => calls.event.push({ name, handle, data }), - llmCall: () => ({} as unknown as ReturnType), + llmCall: () => ({}) as unknown as ReturnType, llmCallEnd: () => {}, - toolCall: () => ({} as unknown as ReturnType), + toolCall: () => ({}) as unknown as ReturnType, toolCallEnd: () => {}, toolConditionalExecution: async (name, args) => { calls.toolConditionalExecution.push({ name, args }); diff --git a/integrations/openclaw/test/failure-model.test.ts b/integrations/openclaw/test/failure-model.test.ts index d1d50ccf3..646470f50 100644 --- a/integrations/openclaw/test/failure-model.test.ts +++ b/integrations/openclaw/test/failure-model.test.ts @@ -4,16 +4,16 @@ /** * Failure-model tests that ensure hook replay fails open and records diagnostics. */ -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; -import { parseConfig } from "../src/config.js"; -import { HookReplayBackend } from "../src/hooks-backend.js"; -import type { NemoFlowRuntimeModule } from "../src/modules.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; +import { parseConfig } from '../src/config.js'; +import { HookReplayBackend } from '../src/hooks-backend.js'; +import type { NemoRelayRuntimeModule } from '../src/modules.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; -describe("Replay failure model", () => { - it("grace timer replay failure is caught and counted", async () => { +describe('Replay failure model', () => { + it('grace timer replay failure is caught and counted', async () => { const logger = createLogger(); const backend = new HookReplayBackend({ nf: createThrowingLlmRuntime(), @@ -21,25 +21,25 @@ describe("Replay failure model", () => { correlation: { llmOutputGraceMs: 1 }, }), logger, - agentVersion: "test-version", + agentVersion: 'test-version', }); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); await waitFor(() => backend.state().counters.replayErrors === 1 && logger.messages.warn.length >= 1); assert.equal(backend.state().counters.replayErrors, 1); assert.equal(logger.messages.warn.length, 1); - assert.match(logger.messages.warn[0] ?? "", /llm_output/); + assert.match(logger.messages.warn[0] ?? '', /llm_output/); }); }); @@ -50,7 +50,7 @@ type TestLogger = PluginLogger & { }; function createLogger(): TestLogger { - const messages: TestLogger["messages"] = { warn: [] }; + const messages: TestLogger['messages'] = { warn: [] }; return { messages, info: () => {}, @@ -59,22 +59,23 @@ function createLogger(): TestLogger { }; } -function createThrowingLlmRuntime(): NemoFlowRuntimeModule { +function createThrowingLlmRuntime(): NemoRelayRuntimeModule { let nextScopeId = 0; - const previousStack = { id: "previous" }; + const previousStack = { id: 'previous' }; return { - ScopeType: { Agent: 0 } as NemoFlowRuntimeModule["ScopeType"], - createScopeStack: () => ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, - currentScopeStack: () => previousStack as unknown as ReturnType, + ScopeType: { Agent: 0 } as NemoRelayRuntimeModule['ScopeType'], + createScopeStack: () => + ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, + currentScopeStack: () => previousStack as unknown as ReturnType, setThreadScopeStack: () => {}, - pushScope: () => ({ id: `scope-${nextScopeId++}` } as unknown as ReturnType), + pushScope: () => ({ id: `scope-${nextScopeId++}` }) as unknown as ReturnType, popScope: () => {}, event: () => {}, llmCall: () => { - throw new Error("llmCall failed"); + throw new Error('llmCall failed'); }, llmCallEnd: () => {}, - toolCall: () => ({} as unknown as ReturnType), + toolCall: () => ({}) as unknown as ReturnType, toolCallEnd: () => {}, toolConditionalExecution: async () => {}, }; @@ -84,7 +85,7 @@ async function waitFor(predicate: () => boolean, timeoutMs = 1000): Promise timeoutMs) { - throw new Error("timed out waiting for replay failure state"); + throw new Error('timed out waiting for replay failure state'); } await new Promise((resolve) => setTimeout(resolve, 5)); } diff --git a/integrations/openclaw/test/gateway-status.ts b/integrations/openclaw/test/gateway-status.ts index 85e6a6281..b4e2c0689 100644 --- a/integrations/openclaw/test/gateway-status.ts +++ b/integrations/openclaw/test/gateway-status.ts @@ -6,19 +6,19 @@ /** * Test helper for querying the OpenClaw gateway status endpoint in live smoke runs. */ -import assert from "node:assert/strict"; +import assert from 'node:assert/strict'; -import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry"; +import type { OpenClawPluginApi } from 'openclaw/plugin-sdk/plugin-entry'; -import type { NemoFlowHealthSnapshot } from "../src/health.js"; +import type { NemoRelayHealthSnapshot } from '../src/health.js'; -export type TestGatewayMethodHandler = Parameters[1]; +export type TestGatewayMethodHandler = Parameters[1]; export async function callGatewayStatus( handler: TestGatewayMethodHandler | undefined, -): Promise { +): Promise { assert.ok(handler); - let status: NemoFlowHealthSnapshot | undefined; + let status: NemoRelayHealthSnapshot | undefined; await handler({ req: {} as never, @@ -28,7 +28,7 @@ export async function callGatewayStatus( respond: (ok, payload, error) => { assert.equal(ok, true); assert.equal(error, undefined); - status = payload as NemoFlowHealthSnapshot; + status = payload as NemoRelayHealthSnapshot; }, context: {} as never, }); diff --git a/integrations/openclaw/test/hooks-backend.test.ts b/integrations/openclaw/test/hooks-backend.test.ts index 76b501161..c8163fc6a 100644 --- a/integrations/openclaw/test/hooks-backend.test.ts +++ b/integrations/openclaw/test/hooks-backend.test.ts @@ -4,121 +4,124 @@ /** * HookReplayBackend tests covering session lifecycle, aliases, marks, and cleanup. */ -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; - -import { parseConfig } from "../src/config.js"; -import { errorToJson, toJsonRecord } from "../src/hook-replay/marks.js"; -import { HookReplayBackend } from "../src/hooks-backend.js"; -import type { NemoFlowRuntimeModule } from "../src/modules.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; - -describe("HookReplayBackend", () => { - it("opens a session root and records aliases on session_start", () => { - const nf = createNemoFlowRuntime(); +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; + +import { parseConfig } from '../src/config.js'; +import { errorToJson, toJsonRecord } from '../src/hook-replay/marks.js'; +import { HookReplayBackend } from '../src/hooks-backend.js'; +import type { NemoRelayRuntimeModule } from '../src/modules.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; + +describe('HookReplayBackend', () => { + it('opens a session root and records aliases on session_start', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onSessionStart( - { sessionId: "session-1", sessionKey: "session-key-1", resumedFrom: "previous-session" }, - { sessionId: "session-1", sessionKey: "session-key-1", agentId: "agent-1" }, + { sessionId: 'session-1', sessionKey: 'session-key-1', resumedFrom: 'previous-session' }, + { sessionId: 'session-1', sessionKey: 'session-key-1', agentId: 'agent-1' }, ); - const session = backend.state().sessions.get("session-1"); + const session = backend.state().sessions.get('session-1'); assert.ok(session); - assert.equal(session.sessionId, "session-1"); - assert.equal(session.sessionKey, "session-key-1"); - assert.equal(session.agentId, "agent-1"); - assert.equal(session.resumedFrom, "previous-session"); - assert.equal(backend.state().sessionAliases.get("session-key-1"), "session-1"); + assert.equal(session.sessionId, 'session-1'); + assert.equal(session.sessionKey, 'session-key-1'); + assert.equal(session.agentId, 'agent-1'); + assert.equal(session.resumedFrom, 'previous-session'); + assert.equal(backend.state().sessionAliases.get('session-key-1'), 'session-1'); assert.equal(nf.calls.pushScope.length, 1); - assert.deepEqual(nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); + assert.deepEqual( + nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); }); - it("emits session_start when a session is created lazily from llm_input", () => { - const nf = createNemoFlowRuntime(); + it('emits session_start when a session is created lazily from llm_input', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onLlmInput( { - runId: "run-1", - sessionId: "lazy-session", - provider: "openai", - model: "gpt", - prompt: "hello", + runId: 'run-1', + sessionId: 'lazy-session', + provider: 'openai', + model: 'gpt', + prompt: 'hello', historyMessages: [], imagesCount: 0, }, - { runId: "run-1", sessionId: "lazy-session" }, + { runId: 'run-1', sessionId: 'lazy-session' }, ); - assert.deepEqual(nf.calls.event.map((event) => event.name), ["openclaw.session_start"]); + assert.deepEqual( + nf.calls.event.map((event) => event.name), + ['openclaw.session_start'], + ); assert.deepEqual(nf.calls.event[0]?.data, { - sessionId: "lazy-session", - source: "lazy_session", - runId: "run-1", + sessionId: 'lazy-session', + source: 'lazy_session', + runId: 'run-1', }); }); - it("keeps concurrent sessions isolated by scope handle and alias", () => { - const nf = createNemoFlowRuntime(); + it('keeps concurrent sessions isolated by scope handle and alias', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onSessionStart({ sessionId: "a", sessionKey: "ka" }, { sessionId: "a", sessionKey: "ka" }); - backend.onSessionStart({ sessionId: "b", sessionKey: "kb" }, { sessionId: "b", sessionKey: "kb" }); + backend.onSessionStart({ sessionId: 'a', sessionKey: 'ka' }, { sessionId: 'a', sessionKey: 'ka' }); + backend.onSessionStart({ sessionId: 'b', sessionKey: 'kb' }, { sessionId: 'b', sessionKey: 'kb' }); - const first = backend.state().sessions.get("a"); - const second = backend.state().sessions.get("b"); + const first = backend.state().sessions.get('a'); + const second = backend.state().sessions.get('b'); assert.ok(first?.rootHandle); assert.ok(second?.rootHandle); assert.notEqual(first.rootHandle, second.rootHandle); - assert.equal(backend.state().sessionAliases.get("ka"), "a"); - assert.equal(backend.state().sessionAliases.get("kb"), "b"); + assert.equal(backend.state().sessionAliases.get('ka'), 'a'); + assert.equal(backend.state().sessionAliases.get('kb'), 'b'); }); - it("drains before close, emits unpaired timing mark, and evicts session records", async () => { - const nf = createNemoFlowRuntime(); + it('drains before close, emits unpaired timing mark, and evicts session records', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onSessionStart({ sessionId: "session-1" }, { sessionId: "session-1" }); + backend.onSessionStart({ sessionId: 'session-1' }, { sessionId: 'session-1' }); backend.onLlmInput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt", - prompt: "hello", + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt', + prompt: 'hello', historyMessages: [], imagesCount: 0, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); backend.onModelCallEnded( { - runId: "run-1", - callId: "call-1", - sessionId: "session-1", - provider: "openai", - model: "gpt", + runId: 'run-1', + callId: 'call-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt', durationMs: 42, - outcome: "completed", + outcome: 'completed', }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - await backend.onSessionEnd( - { sessionId: "session-1", messageCount: 3, reason: "idle" }, - { sessionId: "session-1" }, - ); + await backend.onSessionEnd({ sessionId: 'session-1', messageCount: 3, reason: 'idle' }, { sessionId: 'session-1' }); assert.equal(backend.state().sessions.size, 0); assert.equal(backend.state().sessionAliases.size, 0); @@ -128,56 +131,52 @@ describe("HookReplayBackend", () => { assert.equal(backend.state().modelTimingsByLlmKey.size, 0); assert.deepEqual( nf.calls.event.map((event) => event.name), - [ - "openclaw.session_start", - "openclaw.model_call_timing_unpaired", - "openclaw.session_end", - ], + ['openclaw.session_start', 'openclaw.model_call_timing_unpaired', 'openclaw.session_end'], ); assert.equal(nf.calls.popScope.length, 1); }); - it("emits blocked tool marks from after_tool_call only", () => { - const nf = createNemoFlowRuntime(); + it('emits blocked tool marks from after_tool_call only', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onSessionStart({ sessionId: "session-1", sessionKey: "sk" }, { sessionId: "session-1", sessionKey: "sk" }); + backend.onSessionStart({ sessionId: 'session-1', sessionKey: 'sk' }, { sessionId: 'session-1', sessionKey: 'sk' }); backend.onAfterToolCall( { - toolName: "dangerous_tool", + toolName: 'dangerous_tool', params: {}, - toolCallId: "tool-call-1", - result: { details: { status: "blocked", deniedReason: "policy" } }, + toolCallId: 'tool-call-1', + result: { details: { status: 'blocked', deniedReason: 'policy' } }, durationMs: 5, }, - { sessionKey: "sk", runId: "run-1", toolName: "dangerous_tool", toolCallId: "tool-call-1" }, + { sessionKey: 'sk', runId: 'run-1', toolName: 'dangerous_tool', toolCallId: 'tool-call-1' }, ); - assert.deepEqual(nf.calls.event.map((event) => event.name), [ - "openclaw.session_start", - "openclaw.tool_blocked", - ]); + assert.deepEqual( + nf.calls.event.map((event) => event.name), + ['openclaw.session_start', 'openclaw.tool_blocked'], + ); assert.deepEqual(nf.calls.event[1]?.data, { - toolName: "dangerous_tool", - toolCallId: "tool-call-1", - runId: "run-1", + toolName: 'dangerous_tool', + toolCallId: 'tool-call-1', + runId: 'run-1', blocked: true, - deniedReason: "policy", + deniedReason: 'policy', durationMs: 5, }); }); - it("safe replay restores the previous scope stack and fails open", () => { - const nf = createNemoFlowRuntime(); + it('safe replay restores the previous scope stack and fails open', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onSessionStart({ sessionId: "session-1" }, { sessionId: "session-1" }); - const session = backend.state().sessions.get("session-1"); + backend.onSessionStart({ sessionId: 'session-1' }, { sessionId: 'session-1' }); + const session = backend.state().sessions.get('session-1'); assert.ok(session); assert.doesNotThrow(() => { - backend.emitCapturedUnderSession("test_throw", session, () => { - throw new Error("boom"); + backend.emitCapturedUnderSession('test_throw', session, () => { + throw new Error('boom'); }); }); @@ -185,140 +184,143 @@ describe("HookReplayBackend", () => { assert.equal(nf.calls.setThreadScopeStack.at(-1), nf.previousStack); }); - it("bounds repeated replay warnings by label", () => { - const nf = createNemoFlowRuntime(); + it('bounds repeated replay warnings by label', () => { + const nf = createNemoRelayRuntime(); const logger = createLogger(); const backend = createBackend(nf, logger); - backend.safeReplay("same_failure", undefined, () => { - throw new Error("first"); + backend.safeReplay('same_failure', undefined, () => { + throw new Error('first'); }); - backend.safeReplay("same_failure", undefined, () => { - throw new Error("second"); + backend.safeReplay('same_failure', undefined, () => { + throw new Error('second'); }); assert.equal(logger.messages.warn.length, 1); - assert.match(logger.messages.warn[0] ?? "", /same_failure/); + assert.match(logger.messages.warn[0] ?? '', /same_failure/); assert.equal(backend.state().counters.replayErrors, 2); }); - it("returns undefined from before_agent_finalize", () => { - const nf = createNemoFlowRuntime(); + it('returns undefined from before_agent_finalize', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); const result = backend.onBeforeAgentFinalize( { - runId: "run-1", - sessionId: "session-1", + runId: 'run-1', + sessionId: 'session-1', stopHookActive: false, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(result, undefined); - assert.deepEqual(nf.calls.event.map((event) => event.name), [ - "openclaw.session_start", - "openclaw.before_agent_finalize", - ]); + assert.deepEqual( + nf.calls.event.map((event) => event.name), + ['openclaw.session_start', 'openclaw.before_agent_finalize'], + ); }); - it("keeps gateway stop reason out of the root session output when a final answer is known", async () => { - const nf = createNemoFlowRuntime(); + it('keeps gateway stop reason out of the root session output when a final answer is known', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "hello" }, - { role: "assistant", provider: "openai", model: "gpt", content: "Final answer." }, + { role: 'user', content: 'hello' }, + { role: 'assistant', provider: 'openai', model: 'gpt', content: 'Final answer.' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - await backend.drainForGatewayStop("gateway stopping"); + await backend.drainForGatewayStop('gateway stopping'); assert.deepEqual(nf.calls.popScope[0]?.output, { - content: "Final answer.", - source: "openclaw.agent_end", - runId: "run-1", + content: 'Final answer.', + source: 'openclaw.agent_end', + runId: 'run-1', success: true, }); - assert.deepEqual(nf.calls.event.at(-1)?.data, { reason: "gateway stopping" }); + assert.deepEqual(nf.calls.event.at(-1)?.data, { reason: 'gateway stopping' }); }); - it("records subagent marks under the requester alias without merging child session identity", () => { - const nf = createNemoFlowRuntime(); + it('records subagent marks under the requester alias without merging child session identity', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onSessionStart( - { sessionId: "parent-session", sessionKey: "parent-key" }, - { sessionId: "parent-session", sessionKey: "parent-key" }, + { sessionId: 'parent-session', sessionKey: 'parent-key' }, + { sessionId: 'parent-session', sessionKey: 'parent-key' }, ); backend.onSubagentSpawned( { - childSessionKey: "child-key", - agentId: "child-agent", - mode: "run", + childSessionKey: 'child-key', + agentId: 'child-agent', + mode: 'run', threadRequested: false, - runId: "child-run", + runId: 'child-run', }, - { requesterSessionKey: "parent-key", childSessionKey: "child-key", runId: "child-run" }, + { requesterSessionKey: 'parent-key', childSessionKey: 'child-key', runId: 'child-run' }, ); - assert.equal(backend.state().sessionAliases.get("child-key"), undefined); - assert.deepEqual(nf.calls.event.map((event) => event.name), [ - "openclaw.session_start", - "openclaw.subagent_spawned", - ]); + assert.equal(backend.state().sessionAliases.get('child-key'), undefined); + assert.deepEqual( + nf.calls.event.map((event) => event.name), + ['openclaw.session_start', 'openclaw.subagent_spawned'], + ); }); - it("uses child session key as a lazy-session fallback without aliasing it away", () => { - const nf = createNemoFlowRuntime(); + it('uses child session key as a lazy-session fallback without aliasing it away', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onSubagentSpawned( { - childSessionKey: "child-key", - agentId: "child-agent", - mode: "run", + childSessionKey: 'child-key', + agentId: 'child-agent', + mode: 'run', threadRequested: false, - runId: "child-run", + runId: 'child-run', }, - { childSessionKey: "child-key", runId: "child-run" }, + { childSessionKey: 'child-key', runId: 'child-run' }, ); - assert.ok(backend.state().sessions.get("child-key")); - assert.equal(backend.state().sessionAliases.get("child-run"), "child-key"); - assert.equal(backend.state().sessionAliases.get("child-key"), undefined); + assert.ok(backend.state().sessions.get('child-key')); + assert.equal(backend.state().sessionAliases.get('child-run'), 'child-key'); + assert.equal(backend.state().sessionAliases.get('child-key'), undefined); }); - it("normalizes circular replay payloads before NAPI boundaries", () => { + it('normalizes circular replay payloads before NAPI boundaries', () => { const payload: Record = { ok: true }; payload.self = payload; assert.deepEqual(toJsonRecord(payload), { ok: true, - self: { ok: true, self: "[Circular]" }, + self: { ok: true, self: '[Circular]' }, }); - assert.deepEqual(toJsonRecord({ - finite: 42, - nan: Number.NaN, - positiveInfinity: Number.POSITIVE_INFINITY, - negativeInfinity: Number.NEGATIVE_INFINITY, - }), { - finite: 42, - nan: null, - positiveInfinity: null, - negativeInfinity: null, - }); - assert.deepEqual(errorToJson(new Error("boom")).message, "boom"); + assert.deepEqual( + toJsonRecord({ + finite: 42, + nan: Number.NaN, + positiveInfinity: Number.POSITIVE_INFINITY, + negativeInfinity: Number.NEGATIVE_INFINITY, + }), + { + finite: 42, + nan: null, + positiveInfinity: null, + negativeInfinity: null, + }, + ); + assert.deepEqual(errorToJson(new Error('boom')).message, 'boom'); }); - it("normalizes prototype keys without mutating output prototypes", () => { + it('normalizes prototype keys without mutating output prototypes', () => { const payload: Record = {}; - Object.defineProperty(payload, "__proto__", { + Object.defineProperty(payload, '__proto__', { enumerable: true, value: { polluted: true }, }); @@ -326,13 +328,13 @@ describe("HookReplayBackend", () => { const normalized = toJsonRecord(payload); assert.equal(Object.getPrototypeOf(normalized), Object.prototype); - assert.deepEqual(normalized["__proto__"], { polluted: true }); + assert.deepEqual(normalized['__proto__'], { polluted: true }); assert.equal(({} as Record).polluted, undefined); }); }); -type TestNemoFlowRuntime = NemoFlowRuntimeModule & { - previousStack: { id: "previous" }; +type TestNemoRelayRuntime = NemoRelayRuntimeModule & { + previousStack: { id: 'previous' }; calls: { pushScope: Array<{ name: string; scopeType: number; data: unknown }>; popScope: Array<{ handle: unknown; output: unknown }>; @@ -349,7 +351,7 @@ type TestLogger = PluginLogger & { }; function createBackend( - nf: TestNemoFlowRuntime, + nf: TestNemoRelayRuntime, logger = createLogger(), options: { config?: ReturnType; @@ -359,12 +361,12 @@ function createBackend( nf, config: options.config ?? parseConfig({}), logger, - agentVersion: "test-version", + agentVersion: 'test-version', }); } function createLogger(): TestLogger { - const messages: TestLogger["messages"] = { warn: [] }; + const messages: TestLogger['messages'] = { warn: [] }; return { messages, info: () => {}, @@ -373,10 +375,10 @@ function createLogger(): TestLogger { }; } -function createNemoFlowRuntime(): TestNemoFlowRuntime { +function createNemoRelayRuntime(): TestNemoRelayRuntime { let nextScopeId = 0; - const previousStack = { id: "previous" as const }; - const calls: TestNemoFlowRuntime["calls"] = { + const previousStack = { id: 'previous' as const }; + const calls: TestNemoRelayRuntime['calls'] = { pushScope: [], popScope: [], event: [], @@ -385,22 +387,23 @@ function createNemoFlowRuntime(): TestNemoFlowRuntime { }; return { - ScopeType: { Agent: 0 } as NemoFlowRuntimeModule["ScopeType"], + ScopeType: { Agent: 0 } as NemoRelayRuntimeModule['ScopeType'], previousStack, calls, - createScopeStack: () => ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, - currentScopeStack: () => previousStack as unknown as ReturnType, + createScopeStack: () => + ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, + currentScopeStack: () => previousStack as unknown as ReturnType, setThreadScopeStack: (stack) => calls.setThreadScopeStack.push(stack), pushScope: (name, scopeType, _handle, _attributes, data) => { const handle = { id: `scope-${nextScopeId++}` }; calls.pushScope.push({ name, scopeType, data }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, popScope: (handle, output) => calls.popScope.push({ handle, output }), event: (name, handle, data) => calls.event.push({ name, handle, data }), - llmCall: () => ({} as unknown as ReturnType), + llmCall: () => ({}) as unknown as ReturnType, llmCallEnd: () => {}, - toolCall: () => ({} as unknown as ReturnType), + toolCall: () => ({}) as unknown as ReturnType, toolCallEnd: () => {}, toolConditionalExecution: async (name, args) => { calls.toolConditionalExecution.push({ name, args }); diff --git a/integrations/openclaw/test/live-smoke.test.ts b/integrations/openclaw/test/live-smoke.test.ts index 0f343285e..98026f40c 100644 --- a/integrations/openclaw/test/live-smoke.test.ts +++ b/integrations/openclaw/test/live-smoke.test.ts @@ -4,61 +4,57 @@ /** * Opt-in live smoke test for exercising the real OpenClaw plugin runtime. */ -import assert from "node:assert/strict"; -import * as fs from "node:fs/promises"; -import * as os from "node:os"; -import * as path from "node:path"; -import { it } from "node:test"; - -import { registerNemoFlowPlugin } from "../src/runtime-state.js"; -import { - defaultNemoFlowModuleLoader, - type NemoFlowModuleLoader, - type NemoFlowModules, -} from "../src/modules.js"; -import type { OpenClawPluginApi, PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; -import { callGatewayStatus, type TestGatewayMethodHandler } from "./gateway-status.js"; - -const liveSmokeEnabled = process.env.NEMO_FLOW_OPENCLAW_LIVE_SMOKE === "1"; +import assert from 'node:assert/strict'; +import * as fs from 'node:fs/promises'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import { it } from 'node:test'; + +import { registerNemoRelayPlugin } from '../src/runtime-state.js'; +import { defaultNemoRelayModuleLoader, type NemoRelayModuleLoader, type NemoRelayModules } from '../src/modules.js'; +import type { OpenClawPluginApi, PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; +import { callGatewayStatus, type TestGatewayMethodHandler } from './gateway-status.js'; + +const liveSmokeEnabled = process.env.NEMO_RELAY_OPENCLAW_LIVE_SMOKE === '1'; it( - "runs a live NeMo Flow binding smoke for session ATIF export and hook replay", + 'runs a live NeMo Relay binding smoke for session ATIF export and hook replay', { skip: !liveSmokeEnabled }, async () => { - const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "nemo-flow-openclaw-live-")); - const modules = await loadRealNemoFlowModules(); + const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), 'nemo-relay-openclaw-live-')); + const modules = await loadRealNemoRelayModules(); const api = createApi({ pluginConfig: { plugins: { version: 1, components: [ { - kind: "observability", + kind: 'observability', enabled: true, config: { version: 1, atif: { enabled: true, - agent_name: "openclaw", + agent_name: 'openclaw', output_directory: outputDir, - filename_template: "live-{session_id}.json", + filename_template: 'live-{session_id}.json', }, }, }, { - kind: "adaptive", + kind: 'adaptive', enabled: true, config: { version: 1, - agent_id: "openclaw-live", + agent_id: 'openclaw-live', state: { backend: { - kind: "in_memory", + kind: 'in_memory', config: {}, }, }, telemetry: { - learners: ["tool_parallelism"], + learners: ['tool_parallelism'], }, }, }, @@ -72,7 +68,7 @@ it( registerPlugin(api, async () => modules); const service = api.calls.services[0]; - assert.ok(service, "expected OpenClaw service registration"); + assert.ok(service, 'expected OpenClaw service registration'); await service.start({ stateDir: outputDir, config: {} as never, @@ -80,74 +76,73 @@ it( }); serviceStarted = true; - const sessionStart = api.calls.hooks.find((hook) => hook.hookName === "session_start"); - const llmInput = api.calls.hooks.find((hook) => hook.hookName === "llm_input"); - const llmOutput = api.calls.hooks.find((hook) => hook.hookName === "llm_output"); - const afterToolCall = api.calls.hooks.find((hook) => hook.hookName === "after_tool_call"); - const sessionEnd = api.calls.hooks.find((hook) => hook.hookName === "session_end"); - assert.ok(sessionStart, "expected session_start hook registration"); - assert.ok(llmInput, "expected llm_input hook registration"); - assert.ok(llmOutput, "expected llm_output hook registration"); - assert.ok(afterToolCall, "expected after_tool_call hook registration"); - assert.ok(sessionEnd, "expected session_end hook registration"); - - await sessionStart.handler({ sessionId: "../live-session:1" }, { sessionId: "../live-session:1" }); + const sessionStart = api.calls.hooks.find((hook) => hook.hookName === 'session_start'); + const llmInput = api.calls.hooks.find((hook) => hook.hookName === 'llm_input'); + const llmOutput = api.calls.hooks.find((hook) => hook.hookName === 'llm_output'); + const afterToolCall = api.calls.hooks.find((hook) => hook.hookName === 'after_tool_call'); + const sessionEnd = api.calls.hooks.find((hook) => hook.hookName === 'session_end'); + assert.ok(sessionStart, 'expected session_start hook registration'); + assert.ok(llmInput, 'expected llm_input hook registration'); + assert.ok(llmOutput, 'expected llm_output hook registration'); + assert.ok(afterToolCall, 'expected after_tool_call hook registration'); + assert.ok(sessionEnd, 'expected session_end hook registration'); + + await sessionStart.handler({ sessionId: '../live-session:1' }, { sessionId: '../live-session:1' }); await llmInput.handler( { - runId: "live-run-1", - sessionId: "../live-session:1", - provider: "openai", - model: "gpt-live", - systemPrompt: "be concise", - prompt: "hello", + runId: 'live-run-1', + sessionId: '../live-session:1', + provider: 'openai', + model: 'gpt-live', + systemPrompt: 'be concise', + prompt: 'hello', historyMessages: [], imagesCount: 0, }, - { runId: "live-run-1", sessionId: "../live-session:1", agentId: "agent-live" }, + { runId: 'live-run-1', sessionId: '../live-session:1', agentId: 'agent-live' }, ); await llmOutput.handler( { - runId: "live-run-1", - sessionId: "../live-session:1", - provider: "openai", - model: "gpt-live", - assistantTexts: ["hi"], + runId: 'live-run-1', + sessionId: '../live-session:1', + provider: 'openai', + model: 'gpt-live', + assistantTexts: ['hi'], usage: { input: 1, output: 1 }, }, - { runId: "live-run-1", sessionId: "../live-session:1", agentId: "agent-live" }, + { runId: 'live-run-1', sessionId: '../live-session:1', agentId: 'agent-live' }, ); await afterToolCall.handler( { - toolName: "read_file", - params: { path: "README.md" }, - runId: "live-run-1", - toolCallId: "tool-live-1", - result: { text: "ok" }, + toolName: 'read_file', + params: { path: 'README.md' }, + runId: 'live-run-1', + toolCallId: 'tool-live-1', + result: { text: 'ok' }, durationMs: 2, }, { - runId: "live-run-1", - sessionId: "../live-session:1", - toolName: "read_file", - toolCallId: "tool-live-1", + runId: 'live-run-1', + sessionId: '../live-session:1', + toolName: 'read_file', + toolCallId: 'tool-live-1', }, ); await sessionEnd.handler( - { sessionId: "../live-session:1", messageCount: 1, reason: "idle" }, - { sessionId: "../live-session:1" }, + { sessionId: '../live-session:1', messageCount: 1, reason: 'idle' }, + { sessionId: '../live-session:1' }, ); const files = await fs.readdir(outputDir); - const exportedPath = files.find((file) => file.startsWith("live-") && file.endsWith(".json")); - assert.ok(exportedPath, "expected generic observability ATIF export"); - const exported = JSON.parse(await fs.readFile(path.join(outputDir, exportedPath), "utf8")) as unknown; - assert.equal(typeof exported, "object"); + const exportedPath = files.find((file) => file.startsWith('live-') && file.endsWith('.json')); + assert.ok(exportedPath, 'expected generic observability ATIF export'); + const exported = JSON.parse(await fs.readFile(path.join(outputDir, exportedPath), 'utf8')) as unknown; + assert.equal(typeof exported, 'object'); const status = await callGatewayStatus(api.calls.gatewayMethods[0]?.handler); - assert.equal(status.outputs.atif, "enabled"); + assert.equal(status.outputs.atif, 'enabled'); assert.equal(status.counters.llmSpansReplayed, 1); assert.equal(status.counters.toolSpansReplayed, 1); - } finally { if (serviceStarted) { await api.calls.services[0]?.stop?.({ @@ -166,21 +161,17 @@ type HookHandler = (event: unknown, ctx: unknown) => void | Promise; type TestApi = { id: string; version?: string; - registrationMode: OpenClawPluginApi["registrationMode"]; + registrationMode: OpenClawPluginApi['registrationMode']; pluginConfig?: Record; logger: PluginLogger; - resolvePath: OpenClawPluginApi["resolvePath"]; - registerService: (service: Parameters[0]) => void; - registerRuntimeLifecycle: (lifecycle: Parameters[0]) => void; + resolvePath: OpenClawPluginApi['resolvePath']; + registerService: (service: Parameters[0]) => void; + registerRuntimeLifecycle: (lifecycle: Parameters[0]) => void; on: (hookName: string, handler: HookHandler) => void; - registerGatewayMethod: ( - method: string, - handler: TestGatewayMethodHandler, - opts?: { scope?: string }, - ) => void; + registerGatewayMethod: (method: string, handler: TestGatewayMethodHandler, opts?: { scope?: string }) => void; calls: { - services: Parameters[0][]; - lifecycle: Parameters[0][]; + services: Parameters[0][]; + lifecycle: Parameters[0][]; gatewayMethods: Array<{ method: string; handler: TestGatewayMethodHandler; @@ -190,7 +181,7 @@ type TestApi = { }; function createApi(params: { pluginConfig: Record }): TestApi { - const calls: TestApi["calls"] = { + const calls: TestApi['calls'] = { services: [], lifecycle: [], gatewayMethods: [], @@ -203,9 +194,9 @@ function createApi(params: { pluginConfig: Record }): TestApi { }; return { - id: "nemo-flow", - version: "live-smoke", - registrationMode: "full", + id: 'nemo-relay', + version: 'live-smoke', + registrationMode: 'full', pluginConfig: params.pluginConfig, logger, resolvePath: (input) => input, @@ -217,28 +208,28 @@ function createApi(params: { pluginConfig: Record }): TestApi { }; } -function registerPlugin(api: TestApi, moduleLoader: NemoFlowModuleLoader): void { - registerNemoFlowPlugin(api as unknown as OpenClawPluginApi, moduleLoader); +function registerPlugin(api: TestApi, moduleLoader: NemoRelayModuleLoader): void { + registerNemoRelayPlugin(api as unknown as OpenClawPluginApi, moduleLoader); } -async function loadRealNemoFlowModules(): Promise { +async function loadRealNemoRelayModules(): Promise { try { - return await defaultNemoFlowModuleLoader(); + return await defaultNemoRelayModuleLoader(); } catch (error) { - if (isMissingLocalNemoFlowNode(error)) { + if (isMissingLocalNemoRelayNode(error)) { throw new Error( - "Live smoke requires the nemo-flow-node native package for this platform. Install workspace dependencies, or build local bindings when testing an unpublished version, then rerun `npm run test:live --workspace=nemo-flow-openclaw`.", + 'Live smoke requires the nemo-relay-node native package for this platform. Install workspace dependencies, or build local bindings when testing an unpublished version, then rerun `npm run test:live --workspace=nemo-relay-openclaw`.', ); } throw error; } } -function isMissingLocalNemoFlowNode(error: unknown): boolean { +function isMissingLocalNemoRelayNode(error: unknown): boolean { return ( error instanceof Error && - "code" in error && - error.code === "ERR_MODULE_NOT_FOUND" && - error.message.includes("nemo-flow-node") + 'code' in error && + error.code === 'ERR_MODULE_NOT_FOUND' && + error.message.includes('nemo-relay-node') ); } diff --git a/integrations/openclaw/test/llm-replay.test.ts b/integrations/openclaw/test/llm-replay.test.ts index 7ee250bca..505bfa87b 100644 --- a/integrations/openclaw/test/llm-replay.test.ts +++ b/integrations/openclaw/test/llm-replay.test.ts @@ -4,44 +4,44 @@ /** * LLM replay tests for hook correlation, token accounting, capture policy, and diagnostics. */ -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; -import { parseConfig } from "../src/config.js"; -import { HookReplayBackend } from "../src/hooks-backend.js"; -import type { NemoFlowRuntimeModule } from "../src/modules.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; +import { parseConfig } from '../src/config.js'; +import { HookReplayBackend } from '../src/hooks-backend.js'; +import type { NemoRelayRuntimeModule } from '../src/modules.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; -describe("LLM replay", () => { - it("replays llm output with buffered input under the session root", () => { - const nf = createNemoFlowRuntime(); +describe('LLM replay', () => { + it('replays llm output with buffered input under the session root', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onLlmInput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - systemPrompt: "be concise", - prompt: "hello", + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + systemPrompt: 'be concise', + prompt: 'hello', historyMessages: [], imagesCount: 0, }, - { runId: "run-1", sessionId: "session-1", agentId: "agent-1" }, + { runId: 'run-1', sessionId: 'session-1', agentId: 'agent-1' }, ); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], - resolvedRef: "provider/model", - harnessId: "harness-1", + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], + resolvedRef: 'provider/model', + harnessId: 'harness-1', usage: { input: 2, output: 3 }, }, - { runId: "run-1", sessionId: "session-1", agentId: "agent-1" }, + { runId: 'run-1', sessionId: 'session-1', agentId: 'agent-1' }, ); assert.equal(nf.calls.llmCall.length, 1); @@ -49,30 +49,30 @@ describe("LLM replay", () => { assert.equal(backend.state().counters.llmSpansReplayed, 1); assert.equal(backend.state().llmInputs.size, 0); const request = nf.calls.llmCall[0]?.request as ReplayRequest; - assert.deepEqual(request.content.messages, [{ role: "user", content: "hello" }]); - assert.equal(request.content.systemPrompt, "be concise"); + assert.deepEqual(request.content.messages, [{ role: 'user', content: 'hello' }]); + assert.equal(request.content.systemPrompt, 'be concise'); assert.equal(nf.calls.llmCall[0]?.data, null); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; - assert.equal(response.content, "hi"); + assert.equal(response.content, 'hi'); assert.equal(nf.calls.llmCallEnd[0]?.data, null); assert.deepEqual(response.usage, { prompt_tokens: 2, completion_tokens: 3, total_tokens: 5, }); - assert.equal("token_usage" in response, false); + assert.equal('token_usage' in response, false); }); - it("uses the observed input time as the fallback llm span start time", () => { + it('uses the observed input time as the fallback llm span start time', () => { const now = Date.now; - const nf = createNemoFlowRuntime(); + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); try { Date.now = () => 1_000; - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); Date.now = () => 1_250; - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); } finally { Date.now = now; } @@ -81,11 +81,11 @@ describe("LLM replay", () => { assert.equal(nf.calls.llmCallEnd[0]?.timestamp, 1_250_000); }); - it("folds cache read and write tokens into prompt token totals", () => { - const nf = createNemoFlowRuntime(); + it('folds cache read and write tokens into prompt token totals', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); backend.onLlmOutput( { ...llmOutput(), @@ -97,7 +97,7 @@ describe("LLM replay", () => { total: 6_868, }, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; @@ -111,11 +111,11 @@ describe("LLM replay", () => { }); }); - it("does not derive impossible prompt tokens from inconsistent usage totals", () => { - const nf = createNemoFlowRuntime(); + it('does not derive impossible prompt tokens from inconsistent usage totals', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); backend.onLlmOutput( { ...llmOutput(), @@ -125,7 +125,7 @@ describe("LLM replay", () => { total: 5, }, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; @@ -135,55 +135,55 @@ describe("LLM replay", () => { }); }); - it("replays pending output when matching input arrives and cancels pending queue", () => { - const nf = createNemoFlowRuntime(); + it('replays pending output when matching input arrives and cancels pending queue', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { llmOutputGraceMs: 10_000 }); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(backend.state().llmOutputsPendingInput.size, 1); backend.onLlmInput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - prompt: "hello", + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + prompt: 'hello', historyMessages: [], imagesCount: 0, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(backend.state().llmOutputsPendingInput.size, 0); assert.equal(nf.calls.llmCall.length, 1); const request = nf.calls.llmCall[0]?.request as ReplayRequest; assert.equal(request.content.placeholderRequest, false); - assert.equal(request.content.prompt, "hello"); + assert.equal(request.content.prompt, 'hello'); }); - it("replays placeholder request when output grace timer expires", async () => { - const nf = createNemoFlowRuntime(); + it('replays placeholder request when output grace timer expires', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { llmOutputGraceMs: 1 }); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); await delay(10); @@ -192,22 +192,22 @@ describe("LLM replay", () => { assert.equal(nf.calls.llmCall.length, 1); const request = nf.calls.llmCall[0]?.request as ReplayRequest; assert.equal(request.content.placeholderRequest, true); - assert.equal(request.content.prompt, ""); + assert.equal(request.content.prompt, ''); }); - it("does not keep the process alive while waiting for llm output grace", async () => { - const nf = createNemoFlowRuntime(); + it('does not keep the process alive while waiting for llm output grace', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { llmOutputGraceMs: 10_000 }); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); const pending = [...backend.state().llmOutputsPendingInput.values()][0]?.[0]; @@ -215,32 +215,26 @@ describe("LLM replay", () => { if (isRefableTimer(pending.timer)) { assert.equal(pending.timer.hasRef(), false); } - await backend.onSessionEnd( - { sessionId: "session-1", messageCount: 1, reason: "idle" }, - { sessionId: "session-1" }, - ); + await backend.onSessionEnd({ sessionId: 'session-1', messageCount: 1, reason: 'idle' }, { sessionId: 'session-1' }); assert.equal(pending.timer, undefined); }); - it("drains pending llm output with placeholder request on session end", async () => { - const nf = createNemoFlowRuntime(); + it('drains pending llm output with placeholder request on session end', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { llmOutputGraceMs: 10_000 }); backend.onLlmOutput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - await backend.onSessionEnd( - { sessionId: "session-1", messageCount: 1, reason: "idle" }, - { sessionId: "session-1" }, - ); + await backend.onSessionEnd({ sessionId: 'session-1', messageCount: 1, reason: 'idle' }, { sessionId: 'session-1' }); assert.equal(backend.state().llmOutputsPendingInput.size, 0); assert.equal(nf.calls.llmCall.length, 1); @@ -248,97 +242,103 @@ describe("LLM replay", () => { assert.equal(nf.calls.popScope.length, 1); const request = nf.calls.llmCall[0]?.request as ReplayRequest; assert.equal(request.content.placeholderRequest, true); - assert.equal(request.content.prompt, ""); + assert.equal(request.content.prompt, ''); }); - it("attaches model timing only when timing is unambiguous", () => { - const nf = createNemoFlowRuntime(); + it('attaches model timing only when timing is unambiguous', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onModelCallStarted(modelStarted("call-1"), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallStarted(modelStarted('call-1'), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; assert.equal(response.openclaw.duration_ms, 42); - assert.equal(response.openclaw.outcome, "completed"); + assert.equal(response.openclaw.outcome, 'completed'); assert.equal(backend.state().counters.llmSpansReplayed, 1); }); - it("emits ambiguity mark and does not attach ambiguous timing", () => { - const nf = createNemoFlowRuntime(); + it('emits ambiguity mark and does not attach ambiguous timing', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onModelCallStarted(modelStarted("call-1"), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallStarted(modelStarted("call-2"), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-2", 55), { runId: "run-1", sessionId: "session-1" }); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallStarted(modelStarted('call-1'), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallStarted(modelStarted('call-2'), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-2', 55), { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); - assert.ok(nf.calls.event.some((event) => event.name === "openclaw.model_call_timing_ambiguous")); + assert.ok(nf.calls.event.some((event) => event.name === 'openclaw.model_call_timing_ambiguous')); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; - assert.equal("duration_ms" in response.openclaw, false); + assert.equal('duration_ms' in response.openclaw, false); }); - it("replays recorded assistant messages as ordered llm spans with usage and timing", () => { - const nf = createNemoFlowRuntime(); + it('replays recorded assistant messages as ordered llm spans with usage and timing', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); const firstAssistant = { - role: "assistant", - provider: "openai", - model: "gpt-4", + role: 'assistant', + provider: 'openai', + model: 'gpt-4', content: [ - { type: "thinking", thinking: "private reasoning", thinkingSignature: "opaque-signature" }, - { type: "toolCall", name: "web_search", arguments: { query: "answer" } }, + { type: 'thinking', thinking: 'private reasoning', thinkingSignature: 'opaque-signature' }, + { type: 'toolCall', name: 'web_search', arguments: { query: 'answer' } }, ], usage: { input: 10, output: 5, totalTokens: 15 }, - stopReason: "tool_use", + stopReason: 'tool_use', }; const finalAssistant = { - role: "assistant", - provider: "openai", - model: "gpt-4", - content: [{ type: "text", text: "Final answer." }], + role: 'assistant', + provider: 'openai', + model: 'gpt-4', + content: [{ type: 'text', text: 'Final answer.' }], usage: { input: 20, output: 7, totalTokens: 27 }, - stopReason: "stop", + stopReason: 'stop', }; const historyMessages: unknown[] = []; backend.onLlmInput( - { ...llmInput(), prompt: "Find the answer.", historyMessages }, - { runId: "run-1", sessionId: "session-1" }, + { ...llmInput(), prompt: 'Find the answer.', historyMessages }, + { runId: 'run-1', sessionId: 'session-1' }, ); historyMessages.push(firstAssistant); - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-2", 55), { runId: "run-1", sessionId: "session-1" }); - backend.onBeforeMessageWrite({ message: firstAssistant }, { sessionKey: "session-1" }); - backend.onBeforeMessageWrite({ message: { role: "toolResult", content: "tool result" } }, { sessionKey: "session-1" }); - backend.onBeforeMessageWrite({ message: finalAssistant }, { sessionKey: "session-1" }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-2', 55), { runId: 'run-1', sessionId: 'session-1' }); + backend.onBeforeMessageWrite({ message: firstAssistant }, { sessionKey: 'session-1' }); + backend.onBeforeMessageWrite( + { message: { role: 'toolResult', content: 'tool result' } }, + { sessionKey: 'session-1' }, + ); + backend.onBeforeMessageWrite({ message: finalAssistant }, { sessionKey: 'session-1' }); backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "Find the answer." }, + { role: 'user', content: 'Find the answer.' }, firstAssistant, - { role: "tool", content: "tool result" }, + { role: 'tool', content: 'tool result' }, finalAssistant, ], success: true, durationMs: 100, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(nf.calls.llmCall.length, 2); assert.equal(nf.calls.llmCallEnd.length, 2); - assert.equal(nf.calls.event.some((event) => event.name === "openclaw.model_call_timing_ambiguous"), false); + assert.equal( + nf.calls.event.some((event) => event.name === 'openclaw.model_call_timing_ambiguous'), + false, + ); const firstResponse = nf.calls.llmCallEnd[0]?.response as ReplayResponse; const firstRequest = nf.calls.llmCall[0]?.request as ReplayRequest; - assert.deepEqual(firstRequest.content.messages, [{ role: "user", content: "Find the answer." }]); - assert.equal(firstResponse.content, "tool calls: web_search"); - assert.equal((firstResponse.openclaw as ResponseOpenClaw).assistant_tool_call_names?.[0], "web_search"); + assert.deepEqual(firstRequest.content.messages, [{ role: 'user', content: 'Find the answer.' }]); + assert.equal(firstResponse.content, 'tool calls: web_search'); + assert.equal((firstResponse.openclaw as ResponseOpenClaw).assistant_tool_call_names?.[0], 'web_search'); assert.equal(firstResponse.openclaw.duration_ms, 42); assert.deepEqual(firstResponse.usage, { prompt_tokens: 10, @@ -348,18 +348,18 @@ describe("LLM replay", () => { const secondResponse = nf.calls.llmCallEnd[1]?.response as ReplayResponse; const secondRequest = nf.calls.llmCall[1]?.request as ReplayRequest; assert.deepEqual(secondRequest.content.messages?.[1], { - role: "assistant", - provider: "openai", - model: "gpt-4", + role: 'assistant', + provider: 'openai', + model: 'gpt-4', content: [ - { type: "thinking", stripped: true }, - { type: "toolCall", name: "web_search", arguments: { stripped: true } }, + { type: 'thinking', stripped: true }, + { type: 'toolCall', name: 'web_search', arguments: { stripped: true } }, ], usage: { input: 10, output: 5, totalTokens: 15 }, - stopReason: "tool_use", + stopReason: 'tool_use', }); - assert.deepEqual(secondRequest.content.messages?.at(-1), { role: "toolResult", content: { stripped: true } }); - assert.equal(secondResponse.content, "Final answer."); + assert.deepEqual(secondRequest.content.messages?.at(-1), { role: 'toolResult', content: { stripped: true } }); + assert.equal(secondResponse.content, 'Final answer.'); assert.equal(secondResponse.openclaw.duration_ms, 55); assert.deepEqual(secondResponse.usage, { prompt_tokens: 20, @@ -368,32 +368,32 @@ describe("LLM replay", () => { }); }); - it("uses model_call timestamps for recorded assistant message spans", () => { + it('uses model_call timestamps for recorded assistant message spans', () => { const now = Date.now; - const nf = createNemoFlowRuntime(); + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); try { Date.now = () => 1_000; - backend.onModelCallStarted(modelStarted("call-1"), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallStarted(modelStarted('call-1'), { runId: 'run-1', sessionId: 'session-1' }); Date.now = () => 1_250; - backend.onModelCallEnded(modelEnded("call-1", 250), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallEnded(modelEnded('call-1', 250), { runId: 'run-1', sessionId: 'session-1' }); Date.now = () => 1_260; backend.onBeforeMessageWrite( - { message: { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" } }, - { sessionKey: "session-1" }, + { message: { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' } }, + { sessionKey: 'session-1' }, ); Date.now = () => 2_000; backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "hello" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" }, + { role: 'user', content: 'hello' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); } finally { Date.now = now; @@ -404,238 +404,244 @@ describe("LLM replay", () => { assert.equal(nf.calls.pushScope[0]?.timestamp, 1_000_000); }); - it("suppresses collapsed llm_output after recorded assistant message replay", () => { - const nf = createNemoFlowRuntime(); + it('suppresses collapsed llm_output after recorded assistant message replay', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); backend.onBeforeMessageWrite( - { message: { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" } }, - { sessionKey: "session-1" }, + { message: { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' } }, + { sessionKey: 'session-1' }, ); backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "hello" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" }, + { role: 'user', content: 'hello' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); assert.equal(nf.calls.llmCall.length, 1); assert.equal(nf.calls.llmCallEnd.length, 1); assert.equal(backend.state().llmInputs.size, 0); }); - it("replays multiple llm_output hooks from the same run", () => { - const nf = createNemoFlowRuntime(); + it('replays multiple llm_output hooks from the same run', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onLlmInput({ ...llmInput(), prompt: "first" }, { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput({ ...llmOutput(), assistantTexts: ["first answer"] }, { runId: "run-1", sessionId: "session-1" }); - backend.onLlmInput({ ...llmInput(), prompt: "second" }, { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput({ ...llmOutput(), assistantTexts: ["second answer"] }, { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput({ ...llmInput(), prompt: 'first' }, { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput( + { ...llmOutput(), assistantTexts: ['first answer'] }, + { runId: 'run-1', sessionId: 'session-1' }, + ); + backend.onLlmInput({ ...llmInput(), prompt: 'second' }, { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput( + { ...llmOutput(), assistantTexts: ['second answer'] }, + { runId: 'run-1', sessionId: 'session-1' }, + ); assert.equal(nf.calls.llmCall.length, 2); assert.equal(nf.calls.llmCallEnd.length, 2); - assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, "first answer"); - assert.equal((nf.calls.llmCallEnd[1]?.response as ReplayResponse).content, "second answer"); + assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, 'first answer'); + assert.equal((nf.calls.llmCallEnd[1]?.response as ReplayResponse).content, 'second answer'); }); - it("does not reconstruct agent_end transcripts without reliable message-write state", () => { - const transcriptOnlyNf = createNemoFlowRuntime(); + it('does not reconstruct agent_end transcripts without reliable message-write state', () => { + const transcriptOnlyNf = createNemoRelayRuntime(); const transcriptOnlyBackend = createBackend(transcriptOnlyNf); transcriptOnlyBackend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "current question" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "current answer" }, + { role: 'user', content: 'current question' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'current answer' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(transcriptOnlyNf.calls.llmCall.length, 0); assert.equal(transcriptOnlyNf.calls.llmCallEnd.length, 0); - const compactedNf = createNemoFlowRuntime(); + const compactedNf = createNemoRelayRuntime(); const compactedBackend = createBackend(compactedNf); compactedBackend.onLlmInput( { ...llmInput(), - prompt: "current question", + prompt: 'current question', historyMessages: [ - { role: "user", content: "previous question 1" }, - { role: "assistant", content: "previous answer 1" }, + { role: 'user', content: 'previous question 1' }, + { role: 'assistant', content: 'previous answer 1' }, ], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); compactedBackend.onAgentEnd( { - runId: "run-1", - messages: [{ role: "assistant", provider: "openai", model: "gpt-4", content: "previous answer" }], + runId: 'run-1', + messages: [{ role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'previous answer' }], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); assert.equal(compactedNf.calls.llmCall.length, 0); assert.equal(compactedNf.calls.llmCallEnd.length, 0); }); - it("replays compacted message-write turns from the latest llm input snapshot", () => { + it('replays compacted message-write turns from the latest llm input snapshot', () => { const now = Date.now; - const nf = createNemoFlowRuntime(); + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); try { Date.now = () => 1_000; backend.onLlmInput( - { ...llmInput(), runId: "old-run", prompt: "old question" }, - { runId: "old-run", sessionId: "session-1" }, + { ...llmInput(), runId: 'old-run', prompt: 'old question' }, + { runId: 'old-run', sessionId: 'session-1' }, ); Date.now = () => 2_000; backend.onLlmInput( - { ...llmInput(), runId: "run-1", prompt: "current question" }, - { runId: "run-1", sessionId: "session-1" }, + { ...llmInput(), runId: 'run-1', prompt: 'current question' }, + { runId: 'run-1', sessionId: 'session-1' }, ); } finally { Date.now = now; } - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); backend.onBeforeMessageWrite( - { message: { role: "assistant", provider: "openai", model: "gpt-4", content: "current answer" } }, - { sessionKey: "session-1" }, + { message: { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'current answer' } }, + { sessionKey: 'session-1' }, ); backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "assistant", provider: "openai", model: "gpt-4", content: "compacted previous answer" }, - { role: "user", content: "current question" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "current answer" }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'compacted previous answer' }, + { role: 'user', content: 'current question' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'current answer' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); const request = nf.calls.llmCall[0]?.request as ReplayRequest; - assert.deepEqual(request.content.messages, [{ role: "user", content: "current question" }]); - assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, "current answer"); + assert.deepEqual(request.content.messages, [{ role: 'user', content: 'current question' }]); + assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, 'current answer'); }); - it("does not duplicate trajectory replay across llm_output, message-write, and late hooks", () => { - const nf = createNemoFlowRuntime(); + it('does not duplicate trajectory replay across llm_output, message-write, and late hooks', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); - backend.onModelCallEnded(modelEnded("call-1", 42), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); + backend.onModelCallEnded(modelEnded('call-1', 42), { runId: 'run-1', sessionId: 'session-1' }); backend.onBeforeMessageWrite( - { message: { role: "assistant", provider: "openai", model: "gpt-4", content: "Final answer." } }, - { sessionKey: "session-1" }, + { message: { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'Final answer.' } }, + { sessionKey: 'session-1' }, ); backend.onAgentEnd( { - runId: "run-1", + runId: 'run-1', messages: [ - { role: "user", content: "hello" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" }, - { role: "tool", content: "tool result" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "Final answer." }, + { role: 'user', content: 'hello' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' }, + { role: 'tool', content: 'tool result' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'Final answer.' }, ], success: true, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, + ); + backend.onLlmInput({ ...llmInput(), prompt: 'late duplicate' }, { runId: 'run-1', sessionId: 'session-1' }); + backend.onLlmOutput( + { ...llmOutput(), assistantTexts: ['late duplicate'] }, + { runId: 'run-1', sessionId: 'session-1' }, ); - backend.onLlmInput({ ...llmInput(), prompt: "late duplicate" }, { runId: "run-1", sessionId: "session-1" }); - backend.onLlmOutput({ ...llmOutput(), assistantTexts: ["late duplicate"] }, { runId: "run-1", sessionId: "session-1" }); assert.equal(nf.calls.llmCall.length, 1); assert.equal(nf.calls.llmCallEnd.length, 1); - assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, "hi"); + assert.equal((nf.calls.llmCallEnd[0]?.response as ReplayResponse).content, 'hi'); }); - it("bounds replayed run markers for long-lived sessions", () => { - const nf = createNemoFlowRuntime(); + it('bounds replayed run markers for long-lived sessions', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { maxRecordsPerKey: 2 }); - for (const runId of ["run-1", "run-2", "run-3"]) { - backend.onLlmInput({ ...llmInput(), runId }, { runId, sessionId: "session-1" }); - backend.onLlmOutput({ ...llmOutput(), runId }, { runId, sessionId: "session-1" }); + for (const runId of ['run-1', 'run-2', 'run-3']) { + backend.onLlmInput({ ...llmInput(), runId }, { runId, sessionId: 'session-1' }); + backend.onLlmOutput({ ...llmOutput(), runId }, { runId, sessionId: 'session-1' }); backend.onAgentEnd( { runId, messages: [ - { role: "user", content: "hello" }, - { role: "assistant", provider: "openai", model: "gpt-4", content: "hi" }, + { role: 'user', content: 'hello' }, + { role: 'assistant', provider: 'openai', model: 'gpt-4', content: 'hi' }, ], success: true, }, - { runId, sessionId: "session-1" }, + { runId, sessionId: 'session-1' }, ); } - const session = backend.state().sessions.get("session-1"); - assert.deepEqual([...(session?.trajectoryReplayedRuns ?? [])], ["run-2", "run-3"]); + const session = backend.state().sessions.get('session-1'); + assert.deepEqual([...(session?.trajectoryReplayedRuns ?? [])], ['run-2', 'run-3']); }); - it("bounds run bookkeeping for long-lived sessions without agent_end", () => { - const nf = createNemoFlowRuntime(); + it('bounds run bookkeeping for long-lived sessions without agent_end', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { maxRecordsPerKey: 2 }); - for (const runId of ["run-1", "run-2", "run-3"]) { + for (const runId of ['run-1', 'run-2', 'run-3']) { backend.onLlmInput( { ...llmInput(), runId, prompt: `prompt for ${runId}`, }, - { runId, sessionId: "session-1" }, + { runId, sessionId: 'session-1' }, ); - backend.onLlmOutput({ ...llmOutput(), runId }, { runId, sessionId: "session-1" }); + backend.onLlmOutput({ ...llmOutput(), runId }, { runId, sessionId: 'session-1' }); } - const session = backend.state().sessions.get("session-1"); - assert.deepEqual([...(session?.agentRunInputSnapshots?.keys() ?? [])], ["run-2", "run-3"]); - assert.deepEqual([...(session?.hookLlmOutputReplayCounts?.keys() ?? [])], ["run-2", "run-3"]); + const session = backend.state().sessions.get('session-1'); + assert.deepEqual([...(session?.agentRunInputSnapshots?.keys() ?? [])], ['run-2', 'run-3']); + assert.deepEqual([...(session?.hookLlmOutputReplayCounts?.keys() ?? [])], ['run-2', 'run-3']); }); - it("emits unpaired mark for model_call_started without matching end on session drain", async () => { - const nf = createNemoFlowRuntime(); + it('emits unpaired mark for model_call_started without matching end on session drain', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - backend.onModelCallStarted(modelStarted("call-1"), { runId: "run-1", sessionId: "session-1" }); + backend.onModelCallStarted(modelStarted('call-1'), { runId: 'run-1', sessionId: 'session-1' }); - await backend.onSessionEnd( - { sessionId: "session-1", messageCount: 1, reason: "idle" }, - { sessionId: "session-1" }, - ); + await backend.onSessionEnd({ sessionId: 'session-1', messageCount: 1, reason: 'idle' }, { sessionId: 'session-1' }); - const unpaired = nf.calls.event.find((event) => event.name === "openclaw.model_call_timing_unpaired"); + const unpaired = nf.calls.event.find((event) => event.name === 'openclaw.model_call_timing_unpaired'); assert.ok(unpaired); assert.deepEqual(unpaired.data, { - runId: "run-1", - callId: "call-1", - provider: "openai", - model: "gpt-4", + runId: 'run-1', + callId: 'call-1', + provider: 'openai', + model: 'gpt-4', }); }); - it("strips prompt fields when prompt capture is disabled", () => { - const nf = createNemoFlowRuntime(); + it('strips prompt fields when prompt capture is disabled', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend( nf, {}, @@ -646,28 +652,28 @@ describe("LLM replay", () => { backend.onLlmInput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - systemPrompt: "classified system", - prompt: "classified prompt", - historyMessages: [{ role: "user", content: "classified history" }], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + systemPrompt: 'classified system', + prompt: 'classified prompt', + historyMessages: [{ role: 'user', content: 'classified history' }], imagesCount: 1, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); const request = nf.calls.llmCall[0]?.request as ReplayRequest; - assert.equal("prompt" in request.content, false); - assert.equal("systemPrompt" in request.content, false); + assert.equal('prompt' in request.content, false); + assert.equal('systemPrompt' in request.content, false); assert.deepEqual(request.content.messages, []); assert.equal(request.content.imagesCount, 1); }); - it("strips response content when response capture is disabled", () => { - const nf = createNemoFlowRuntime(); + it('strips response content when response capture is disabled', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend( nf, {}, @@ -676,90 +682,90 @@ describe("LLM replay", () => { }, ); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); backend.onLlmOutput( { ...llmOutput(), - assistantTexts: ["classified response"], + assistantTexts: ['classified response'], }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); const response = nf.calls.llmCallEnd[0]?.response as ReplayResponse; - assert.equal("content" in response, false); + assert.equal('content' in response, false); assert.equal(response.assistant_texts_count, 1); }); - it("does not duplicate current prompt when history already ends with the same user message", () => { - const nf = createNemoFlowRuntime(); + it('does not duplicate current prompt when history already ends with the same user message', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onLlmInput( { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - prompt: "hello", - historyMessages: [{ role: "user", content: [{ type: "text", text: "hello" }] }], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + prompt: 'hello', + historyMessages: [{ role: 'user', content: [{ type: 'text', text: 'hello' }] }], imagesCount: 0, }, - { runId: "run-1", sessionId: "session-1" }, + { runId: 'run-1', sessionId: 'session-1' }, ); - backend.onLlmOutput(llmOutput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmOutput(llmOutput(), { runId: 'run-1', sessionId: 'session-1' }); const request = nf.calls.llmCall[0]?.request as ReplayRequest; - assert.deepEqual(request.content.messages, [{ role: "user", content: [{ type: "text", text: "hello" }] }]); + assert.deepEqual(request.content.messages, [{ role: 'user', content: [{ type: 'text', text: 'hello' }] }]); }); - it("evicts stale expanded correlation records by TTL", () => { - const nf = createNemoFlowRuntime(); + it('evicts stale expanded correlation records by TTL', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { recordTtlMs: 1 }); const stalePendingOutput = { - sessionKey: "session-1", - sessionId: "session-1", - runId: "old-run", - provider: "openai", - model: "gpt-4", + sessionKey: 'session-1', + sessionId: 'session-1', + runId: 'old-run', + provider: 'openai', + model: 'gpt-4', event: llmOutput(), - ctx: { runId: "old-run", sessionId: "session-1" }, + ctx: { runId: 'old-run', sessionId: 'session-1' }, observedAtMs: 0, timer: setTimeout(() => {}, 10_000), }; - backend.state().llmInputs.set("stale-input", [ + backend.state().llmInputs.set('stale-input', [ { - sessionKey: "session-1", - sessionId: "session-1", - runId: "old-run", - provider: "openai", - model: "gpt-4", - prompt: "old", + sessionKey: 'session-1', + sessionId: 'session-1', + runId: 'old-run', + provider: 'openai', + model: 'gpt-4', + prompt: 'old', historyMessages: [], imagesCount: 0, observedAtMs: 0, }, ]); - backend.state().llmOutputsPendingInput.set("stale-output", [stalePendingOutput]); - backend.state().modelTimingsByLlmKey.set("stale-timing", [ + backend.state().llmOutputsPendingInput.set('stale-output', [stalePendingOutput]); + backend.state().modelTimingsByLlmKey.set('stale-timing', [ { - sessionKey: "session-1", - sessionId: "session-1", - runId: "old-run", - callId: "old-call", - provider: "openai", - model: "gpt-4", + sessionKey: 'session-1', + sessionId: 'session-1', + runId: 'old-run', + callId: 'old-call', + provider: 'openai', + model: 'gpt-4', consumed: false, observedAtMs: 0, }, ]); - backend.onLlmInput(llmInput(), { runId: "run-1", sessionId: "session-1" }); + backend.onLlmInput(llmInput(), { runId: 'run-1', sessionId: 'session-1' }); - assert.equal(backend.state().llmInputs.has("stale-input"), false); - assert.equal(backend.state().llmOutputsPendingInput.has("stale-output"), false); + assert.equal(backend.state().llmInputs.has('stale-input'), false); + assert.equal(backend.state().llmOutputsPendingInput.has('stale-output'), false); assert.equal(stalePendingOutput.timer, undefined); - assert.equal(backend.state().modelTimingsByLlmKey.has("stale-timing"), false); + assert.equal(backend.state().modelTimingsByLlmKey.has('stale-timing'), false); }); }); @@ -786,7 +792,7 @@ type ResponseOpenClaw = { [key: string]: unknown; }; -type TestNemoFlowRuntime = NemoFlowRuntimeModule & { +type TestNemoRelayRuntime = NemoRelayRuntimeModule & { calls: { pushScope: Array<{ name: string; scopeType: number; data: unknown; timestamp: number | null | undefined }>; popScope: Array<{ handle: unknown; output: unknown }>; @@ -807,9 +813,9 @@ type TestNemoFlowRuntime = NemoFlowRuntimeModule & { }; function createBackend( - nf: TestNemoFlowRuntime, - correlation: Partial["correlation"]> = {}, - capture: Partial["capture"]> = {}, + nf: TestNemoRelayRuntime, + correlation: Partial['correlation']> = {}, + capture: Partial['capture']> = {}, ): HookReplayBackend { return new HookReplayBackend({ nf, @@ -818,7 +824,7 @@ function createBackend( capture, }), logger: createLogger(), - agentVersion: "test-version", + agentVersion: 'test-version', }); } @@ -830,10 +836,10 @@ function createLogger(): PluginLogger { }; } -function createNemoFlowRuntime(): TestNemoFlowRuntime { +function createNemoRelayRuntime(): TestNemoRelayRuntime { let nextScopeId = 0; - const previousStack = { id: "previous" }; - const calls: TestNemoFlowRuntime["calls"] = { + const previousStack = { id: 'previous' }; + const calls: TestNemoRelayRuntime['calls'] = { pushScope: [], popScope: [], event: [], @@ -846,29 +852,30 @@ function createNemoFlowRuntime(): TestNemoFlowRuntime { }; return { - ScopeType: { Agent: 0 } as NemoFlowRuntimeModule["ScopeType"], + ScopeType: { Agent: 0 } as NemoRelayRuntimeModule['ScopeType'], calls, - createScopeStack: () => ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, - currentScopeStack: () => previousStack as unknown as ReturnType, + createScopeStack: () => + ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, + currentScopeStack: () => previousStack as unknown as ReturnType, setThreadScopeStack: (stack) => calls.setThreadScopeStack.push(stack), pushScope: (name, scopeType, _handle, _attributes, data, _links, _metadata, timestamp) => { const handle = { id: `scope-${nextScopeId++}` }; calls.pushScope.push({ name, scopeType, data, timestamp }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, popScope: (handle, output) => calls.popScope.push({ handle, output }), event: (name, handle, data) => calls.event.push({ name, handle, data }), llmCall: (name, request, _handle, _attributes, data, _metadata, modelName, timestamp) => { const handle = { id: `llm-${nextScopeId++}` }; calls.llmCall.push({ name, request, data, modelName, timestamp }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, llmCallEnd: (handle, response, data, _metadata, timestamp) => calls.llmCallEnd.push({ handle, response, data, timestamp }), toolCall: (name, args) => { const handle = { id: `tool-${nextScopeId++}` }; calls.toolCall.push({ name, args }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, toolCallEnd: (handle, result, data) => calls.toolCallEnd.push({ handle, result, data }), toolConditionalExecution: async (name, args) => { @@ -879,11 +886,11 @@ function createNemoFlowRuntime(): TestNemoFlowRuntime { function llmInput() { return { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - prompt: "hello", + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + prompt: 'hello', historyMessages: [], imagesCount: 0, }; @@ -891,21 +898,21 @@ function llmInput() { function llmOutput() { return { - runId: "run-1", - sessionId: "session-1", - provider: "openai", - model: "gpt-4", - assistantTexts: ["hi"], + runId: 'run-1', + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', + assistantTexts: ['hi'], }; } function modelStarted(callId: string) { return { - runId: "run-1", + runId: 'run-1', callId, - sessionId: "session-1", - provider: "openai", - model: "gpt-4", + sessionId: 'session-1', + provider: 'openai', + model: 'gpt-4', }; } @@ -913,7 +920,7 @@ function modelEnded(callId: string, durationMs: number) { return { ...modelStarted(callId), durationMs, - outcome: "completed" as const, + outcome: 'completed' as const, }; } @@ -923,9 +930,9 @@ function delay(ms: number): Promise { function isRefableTimer(timer: unknown): timer is { hasRef: () => boolean } { return ( - typeof timer === "object" && + typeof timer === 'object' && timer !== null && - "hasRef" in timer && - typeof (timer as { hasRef?: unknown }).hasRef === "function" + 'hasRef' in timer && + typeof (timer as { hasRef?: unknown }).hasRef === 'function' ); } diff --git a/integrations/openclaw/test/tool-replay.test.ts b/integrations/openclaw/test/tool-replay.test.ts index bad59ecbb..2f3607413 100644 --- a/integrations/openclaw/test/tool-replay.test.ts +++ b/integrations/openclaw/test/tool-replay.test.ts @@ -4,29 +4,29 @@ /** * Tool replay tests for stripped payloads, trusted payload capture, and blocked tools. */ -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; +import assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; -import { parseConfig } from "../src/config.js"; -import { HookReplayBackend } from "../src/hooks-backend.js"; -import type { NemoFlowRuntimeModule } from "../src/modules.js"; -import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry"; +import { parseConfig } from '../src/config.js'; +import { HookReplayBackend } from '../src/hooks-backend.js'; +import type { NemoRelayRuntimeModule } from '../src/modules.js'; +import type { PluginLogger } from 'openclaw/plugin-sdk/plugin-entry'; -describe("Tool replay", () => { - it("replays after_tool_call with stripped payloads by default", () => { - const nf = createNemoFlowRuntime(); +describe('Tool replay', () => { + it('replays after_tool_call with stripped payloads by default', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onAfterToolCall( { - toolName: "read_file", - params: { path: "/secret", token: "value" }, - toolCallId: "tool-call-1", - runId: "run-1", - result: { text: "secret" }, + toolName: 'read_file', + params: { path: '/secret', token: 'value' }, + toolCallId: 'tool-call-1', + runId: 'run-1', + result: { text: 'secret' }, durationMs: 7, }, - { runId: "run-1", sessionId: "session-1", toolCallId: "tool-call-1" }, + { runId: 'run-1', sessionId: 'session-1', toolCallId: 'tool-call-1' }, ); assert.equal(nf.calls.toolCall.length, 1); @@ -34,25 +34,25 @@ describe("Tool replay", () => { assert.equal(backend.state().counters.toolSpansReplayed, 1); assert.deepEqual(nf.calls.toolCall[0]?.args, { stripped: true, - argKeys: ["path", "token"], + argKeys: ['path', 'token'], }); assert.equal(nf.calls.toolCall[0]?.data, null); assert.deepEqual(nf.calls.toolCallEnd[0]?.result, { - content: "Tool read_file completed.", + content: 'Tool read_file completed.', openclaw: { - toolName: "read_file", - toolCallId: "tool-call-1", + toolName: 'read_file', + toolCallId: 'tool-call-1', durationMs: 7, hasError: false, stripped: true, - resultKeys: ["text"], + resultKeys: ['text'], }, }); assert.equal(nf.calls.toolCallEnd[0]?.data, null); }); - it("captures full tool payloads only when trusted config opts in", () => { - const nf = createNemoFlowRuntime(); + it('captures full tool payloads only when trusted config opts in', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { capture: { stripToolArgs: false, @@ -62,34 +62,34 @@ describe("Tool replay", () => { backend.onAfterToolCall( { - toolName: "read_file", - params: { path: "/workspace/file.txt" }, - toolCallId: "tool-call-1", - runId: "run-1", - result: { text: "ok" }, + toolName: 'read_file', + params: { path: '/workspace/file.txt' }, + toolCallId: 'tool-call-1', + runId: 'run-1', + result: { text: 'ok' }, durationMs: 7, }, - { runId: "run-1", sessionId: "session-1", toolCallId: "tool-call-1" }, + { runId: 'run-1', sessionId: 'session-1', toolCallId: 'tool-call-1' }, ); - assert.deepEqual(nf.calls.toolCall[0]?.args, { path: "/workspace/file.txt" }); + assert.deepEqual(nf.calls.toolCall[0]?.args, { path: '/workspace/file.txt' }); assert.deepEqual(nf.calls.toolCallEnd[0]?.result, { - content: "Tool read_file completed.", + content: 'Tool read_file completed.', openclaw: { - toolName: "read_file", - toolCallId: "tool-call-1", + toolName: 'read_file', + toolCallId: 'tool-call-1', durationMs: 7, hasError: false, stripped: false, - resultKeys: ["text"], + resultKeys: ['text'], }, - result: { text: "ok" }, + result: { text: 'ok' }, }); assert.equal(nf.calls.toolCallEnd[0]?.data, null); }); - it("passes non-null tool end payload when result and error are missing", () => { - const nf = createNemoFlowRuntime(); + it('passes non-null tool end payload when result and error are missing', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf, { capture: { stripToolResults: false, @@ -98,19 +98,19 @@ describe("Tool replay", () => { backend.onAfterToolCall( { - toolName: "noop", + toolName: 'noop', params: {}, - toolCallId: "tool-call-1", - runId: "run-1", + toolCallId: 'tool-call-1', + runId: 'run-1', }, - { runId: "run-1", sessionId: "session-1", toolCallId: "tool-call-1" }, + { runId: 'run-1', sessionId: 'session-1', toolCallId: 'tool-call-1' }, ); assert.deepEqual(nf.calls.toolCallEnd[0]?.result, { - content: "Tool noop completed.", + content: 'Tool noop completed.', openclaw: { - toolName: "noop", - toolCallId: "tool-call-1", + toolName: 'noop', + toolCallId: 'tool-call-1', hasError: false, stripped: false, }, @@ -119,40 +119,38 @@ describe("Tool replay", () => { assert.equal(nf.calls.toolCallEnd[0]?.data, null); }); - it("emits blocked tool mark instead of successful tool span", () => { - const nf = createNemoFlowRuntime(); + it('emits blocked tool mark instead of successful tool span', () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); backend.onAfterToolCall( { - toolName: "dangerous_tool", + toolName: 'dangerous_tool', params: {}, - toolCallId: "tool-call-1", - runId: "run-1", - result: { details: { status: "blocked", deniedReason: "policy" } }, + toolCallId: 'tool-call-1', + runId: 'run-1', + result: { details: { status: 'blocked', deniedReason: 'policy' } }, durationMs: 3, }, - { runId: "run-1", sessionId: "session-1", toolCallId: "tool-call-1" }, + { runId: 'run-1', sessionId: 'session-1', toolCallId: 'tool-call-1' }, ); assert.equal(nf.calls.toolCall.length, 0); - assert.ok(nf.calls.event.some((event) => event.name === "openclaw.tool_blocked")); + assert.ok(nf.calls.event.some((event) => event.name === 'openclaw.tool_blocked')); }); - it("runs tool guardrails even when no session key is available", async () => { - const nf = createNemoFlowRuntime(); + it('runs tool guardrails even when no session key is available', async () => { + const nf = createNemoRelayRuntime(); const backend = createBackend(nf); - await backend.onBeforeToolCall({ toolName: "shell", params: { command: "pwd" } }, {}); + await backend.onBeforeToolCall({ toolName: 'shell', params: { command: 'pwd' } }, {}); - assert.deepEqual(nf.calls.toolConditionalExecution, [ - { name: "shell", args: { command: "pwd" } }, - ]); + assert.deepEqual(nf.calls.toolConditionalExecution, [{ name: 'shell', args: { command: 'pwd' } }]); assert.equal(nf.calls.setThreadScopeStack.length, 0); }); }); -type TestNemoFlowRuntime = NemoFlowRuntimeModule & { +type TestNemoRelayRuntime = NemoRelayRuntimeModule & { calls: { pushScope: Array<{ name: string; scopeType: number; data: unknown }>; popScope: Array<{ handle: unknown; output: unknown }>; @@ -167,9 +165,9 @@ type TestNemoFlowRuntime = NemoFlowRuntimeModule & { }; function createBackend( - nf: TestNemoFlowRuntime, + nf: TestNemoRelayRuntime, overrides: { - capture?: Partial["capture"]>; + capture?: Partial['capture']>; } = {}, ): HookReplayBackend { return new HookReplayBackend({ @@ -178,7 +176,7 @@ function createBackend( capture: overrides.capture, }), logger: createLogger(), - agentVersion: "test-version", + agentVersion: 'test-version', }); } @@ -190,10 +188,10 @@ function createLogger(): PluginLogger { }; } -function createNemoFlowRuntime(): TestNemoFlowRuntime { +function createNemoRelayRuntime(): TestNemoRelayRuntime { let nextScopeId = 0; - const previousStack = { id: "previous" }; - const calls: TestNemoFlowRuntime["calls"] = { + const previousStack = { id: 'previous' }; + const calls: TestNemoRelayRuntime['calls'] = { pushScope: [], popScope: [], event: [], @@ -206,28 +204,29 @@ function createNemoFlowRuntime(): TestNemoFlowRuntime { }; return { - ScopeType: { Agent: 0 } as NemoFlowRuntimeModule["ScopeType"], + ScopeType: { Agent: 0 } as NemoRelayRuntimeModule['ScopeType'], calls, - createScopeStack: () => ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, - currentScopeStack: () => previousStack as unknown as ReturnType, + createScopeStack: () => + ({ id: `stack-${nextScopeId++}` }) as unknown as ReturnType, + currentScopeStack: () => previousStack as unknown as ReturnType, setThreadScopeStack: (stack) => calls.setThreadScopeStack.push(stack), pushScope: (name, scopeType, _handle, _attributes, data) => { const handle = { id: `scope-${nextScopeId++}` }; calls.pushScope.push({ name, scopeType, data }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, popScope: (handle, output) => calls.popScope.push({ handle, output }), event: (name, handle, data) => calls.event.push({ name, handle, data }), llmCall: (name, request) => { const handle = { id: `llm-${nextScopeId++}` }; calls.llmCall.push({ name, request }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, llmCallEnd: (handle, response) => calls.llmCallEnd.push({ handle, response }), toolCall: (name, args, _handle, _attributes, data) => { const handle = { id: `tool-${nextScopeId++}` }; calls.toolCall.push({ name, args, data }); - return handle as unknown as ReturnType; + return handle as unknown as ReturnType; }, toolCallEnd: (handle, result, data) => calls.toolCallEnd.push({ handle, result, data }), toolConditionalExecution: async (name, args) => { diff --git a/integrations/openclaw/tsconfig.build.json b/integrations/openclaw/tsconfig.build.json index 5b2d5d342..5cd286889 100644 --- a/integrations/openclaw/tsconfig.build.json +++ b/integrations/openclaw/tsconfig.build.json @@ -7,10 +7,5 @@ "sourceMap": false, "outDir": "dist" }, - "exclude": [ - "test/**", - "src/**/*.test.ts", - ".test-dist/**", - "dist/**" - ] + "exclude": ["test/**", "src/**/*.test.ts", ".test-dist/**", "dist/**"] } diff --git a/integrations/openclaw/tsconfig.json b/integrations/openclaw/tsconfig.json index a2aa149f9..3f47383b3 100644 --- a/integrations/openclaw/tsconfig.json +++ b/integrations/openclaw/tsconfig.json @@ -7,16 +7,10 @@ "rootDir": ".", "noEmit": true, "resolveJsonModule": true, - "types": [ - "node" - ], + "types": ["node"], "skipLibCheck": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true }, - "include": [ - "index.ts", - "src/**/*.ts", - "src/**/*.d.ts" - ] + "include": ["index.ts", "src/**/*.ts", "src/**/*.d.ts"] } diff --git a/integrations/openclaw/tsconfig.test.json b/integrations/openclaw/tsconfig.test.json index 5c7a7c9e9..80dfdda3c 100644 --- a/integrations/openclaw/tsconfig.test.json +++ b/integrations/openclaw/tsconfig.test.json @@ -7,14 +7,6 @@ "sourceMap": false, "outDir": ".test-dist" }, - "exclude": [ - ".test-dist/**", - "dist/**" - ], - "include": [ - "index.ts", - "src/**/*.ts", - "src/**/*.d.ts", - "test/**/*.ts" - ] + "exclude": [".test-dist/**", "dist/**"], + "include": ["index.ts", "src/**/*.ts", "src/**/*.d.ts", "test/**/*.ts"] } diff --git a/justfile b/justfile index 4ebd4a913..a07dc4597 100644 --- a/justfile +++ b/justfile @@ -4,7 +4,7 @@ set shell := ["bash", "-eu", "-o", "pipefail", "-c"] export REPO_ROOT := justfile_directory() -export NEMO_FLOW_REPO_ROOT := REPO_ROOT +export NEMO_RELAY_REPO_ROOT := REPO_ROOT # Shared knobs used by the CI-oriented build, test, and package targets below. ci := "false" @@ -22,7 +22,7 @@ export_uv_python_runtime() { local python_executable="" python_executable="$(uv_python_executable)" python_runtime_exports="$( - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" "$python_executable" - <<'PY' import shlex from pathlib import Path @@ -56,7 +56,7 @@ PY uv_python_executable() { ( - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" uv python find ) } @@ -64,12 +64,12 @@ uv_python_executable() { activate_project_venv() { # Ensure PATH-based tool lookups (for example, `zig`) resolve from the # synced project environment without asking uv to resync the project. - if [[ -f "$NEMO_FLOW_REPO_ROOT/.venv/bin/activate" ]]; then + if [[ -f "$NEMO_RELAY_REPO_ROOT/.venv/bin/activate" ]]; then # shellcheck disable=SC1091 - source "$NEMO_FLOW_REPO_ROOT/.venv/bin/activate" - elif [[ -f "$NEMO_FLOW_REPO_ROOT/.venv/Scripts/activate" ]]; then + source "$NEMO_RELAY_REPO_ROOT/.venv/bin/activate" + elif [[ -f "$NEMO_RELAY_REPO_ROOT/.venv/Scripts/activate" ]]; then # shellcheck disable=SC1091 - source "$NEMO_FLOW_REPO_ROOT/.venv/Scripts/activate" + source "$NEMO_RELAY_REPO_ROOT/.venv/Scripts/activate" else echo "ERROR: expected project virtualenv activation script under .venv" >&2 exit 1 @@ -78,10 +78,10 @@ activate_project_venv() { project_python_executable() { local python_executable="" - if [[ -x "$NEMO_FLOW_REPO_ROOT/.venv/bin/python" ]]; then - python_executable="$NEMO_FLOW_REPO_ROOT/.venv/bin/python" - elif [[ -x "$NEMO_FLOW_REPO_ROOT/.venv/Scripts/python.exe" ]]; then - python_executable="$NEMO_FLOW_REPO_ROOT/.venv/Scripts/python.exe" + if [[ -x "$NEMO_RELAY_REPO_ROOT/.venv/bin/python" ]]; then + python_executable="$NEMO_RELAY_REPO_ROOT/.venv/bin/python" + elif [[ -x "$NEMO_RELAY_REPO_ROOT/.venv/Scripts/python.exe" ]]; then + python_executable="$NEMO_RELAY_REPO_ROOT/.venv/Scripts/python.exe" else echo "ERROR: expected project virtualenv Python executable under .venv" >&2 exit 1 @@ -121,7 +121,7 @@ PY use_project_python_source() { local python_executable="$1" local python_pathsep="" - local python_source_path="$NEMO_FLOW_REPO_ROOT/python" + local python_source_path="$NEMO_RELAY_REPO_ROOT/python" python_pathsep="$("$python_executable" - <<'PY' import os @@ -135,7 +135,7 @@ PY } docs_dependencies_ready() { - case "${NEMO_FLOW_DOCS_DEPS_READY:-}" in + case "${NEMO_RELAY_DOCS_DEPS_READY:-}" in 1|true|TRUE|True|yes|YES|Yes|on|ON|On) return 0 ;; @@ -150,14 +150,14 @@ ensure_docs_dependencies() { return 0 fi - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" uv sync --inexact --no-default-groups --group docs --no-install-project npm install --ignore-scripts } ensure_docs_node_workspace_compat() { - local node_modules="$NEMO_FLOW_REPO_ROOT/crates/node/node_modules" - local root_node_modules="$NEMO_FLOW_REPO_ROOT/node_modules" + local node_modules="$NEMO_RELAY_REPO_ROOT/crates/node/node_modules" + local root_node_modules="$NEMO_RELAY_REPO_ROOT/node_modules" # Historical versioned docs builds run older docs hooks that resolve # TypeDoc peers only from crates/node/node_modules. A root npm install may @@ -180,7 +180,7 @@ prepare_parent_dir() { artifact_path() { local filename="$1" - local base_dir="${output_dir:-$NEMO_FLOW_REPO_ROOT/target/coverage}" + local base_dir="${output_dir:-$NEMO_RELAY_REPO_ROOT/target/coverage}" printf '%s/%s\n' "$base_dir" "$filename" } @@ -194,7 +194,7 @@ prepare_artifact() { # Package artifacts are grouped by ecosystem so local runs mirror CI layout. package_output_dir() { local channel="$1" - local base_dir="${output_dir:-$NEMO_FLOW_REPO_ROOT/target/packages}" + local base_dir="${output_dir:-$NEMO_RELAY_REPO_ROOT/target/packages}" printf '%s/%s\n' "$base_dir" "$channel" } @@ -206,7 +206,7 @@ prepare_package_dir() { } head_git_sha() { - git -C "$NEMO_FLOW_REPO_ROOT" rev-parse --short=8 HEAD + git -C "$NEMO_RELAY_REPO_ROOT" rev-parse --short=8 HEAD } # Version helpers intentionally mutate package metadata in-place to match how CI @@ -419,7 +419,7 @@ section = "" output = [] changed = [] found_workspace_version = False -local_dependencies = ("nemo-flow", "nemo-flow-adaptive", "nemo-flow-ffi", "nemo-flow-cli") +local_dependencies = ("nemo-relay", "nemo-relay-adaptive", "nemo-relay-ffi", "nemo-relay-cli") found_dependencies = set() for line in text.splitlines(keepends=True): @@ -487,17 +487,17 @@ mismatched = [] checked = 0 for package in metadata["packages"]: - if package["id"] not in workspace_members or not package["name"].startswith("nemo-flow"): + if package["id"] not in workspace_members or not package["name"].startswith("nemo-relay"): continue checked += 1 if package["version"] != version: mismatched.append(f"{package['name']}={package['version']}") if checked == 0: - raise SystemExit("Cargo metadata did not include any nemo-flow workspace packages") + raise SystemExit("Cargo metadata did not include any nemo-relay workspace packages") if mismatched: raise SystemExit(f"Cargo workspace packages do not all resolve to {version}: {', '.join(mismatched)}") -print(f"Cargo metadata resolves {checked} nemo-flow workspace packages to {version}") +print(f"Cargo metadata resolves {checked} nemo-relay workspace packages to {version}") PY then rm -f "$metadata_file" @@ -510,7 +510,7 @@ set_node_package_versions() { local version="$1" set_npm_package_version crates/node/package.json package-lock.json "$version" crates/node set_npm_package_version integrations/openclaw/package.json package-lock.json "$version" integrations/openclaw - set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-flow-node "$version" + set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-relay-node "$version" } set_node_package_version() { @@ -685,7 +685,7 @@ docs: {{ bash_helpers }} ensure_docs_dependencies configure_docs_environment - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" uv run sphinx-build -W -b html docs docs/_build/html # linkcheck the documentation @@ -694,7 +694,7 @@ docs-linkcheck: {{ bash_helpers }} ensure_docs_dependencies configure_docs_environment - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" uv run sphinx-build -W -b linkcheck docs docs/_build/linkcheck # build the complete multi-version documentation site @@ -703,7 +703,7 @@ docs-github-pages: {{ bash_helpers }} ensure_docs_dependencies configure_docs_environment - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" uv run sphinx-multiversion docs docs/_build/pages -W --keep-going uv run python scripts/docs/postprocess_sphinx_multiversion.py docs/_build/pages @@ -712,7 +712,7 @@ build-rust: #!/usr/bin/env bash {{ bash_helpers }} export_uv_python_runtime - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then prepare_llvm_cov_workspace cargo test --workspace --no-run @@ -724,8 +724,8 @@ build-rust: build-python: #!/usr/bin/env bash {{ bash_helpers }} - cd "$NEMO_FLOW_REPO_ROOT" - uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents + cd "$NEMO_RELAY_REPO_ROOT" + uv sync --inexact --no-install-project --no-install-package nemo-relay --extra langchain --extra langgraph --extra deepagents activate_project_venv if is_true "{{ ci }}"; then prepare_llvm_cov_workspace @@ -738,11 +738,11 @@ build-python: build-go: #!/usr/bin/env bash {{ bash_helpers }} - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then - cargo build -p nemo-flow-ffi + cargo build -p nemo-relay-ffi else - cargo build --release -p nemo-flow-ffi + cargo build --release -p nemo-relay-ffi fi @@ -753,23 +753,23 @@ build-node: if is_true "{{ ci }}"; then prepare_llvm_cov_workspace fi - cd "$NEMO_FLOW_REPO_ROOT" - npm install --workspace=nemo-flow-node --ignore-scripts + cd "$NEMO_RELAY_REPO_ROOT" + npm install --workspace=nemo-relay-node --ignore-scripts if is_true "{{ ci }}"; then - npm run build-debug --workspace=nemo-flow-node + npm run build-debug --workspace=nemo-relay-node else - npm run build --workspace=nemo-flow-node + npm run build --workspace=nemo-relay-node fi # --set [ci=true|false] build-wasm: #!/usr/bin/env bash {{ bash_helpers }} - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then - npm run build:pkg --workspace=nemo-flow-wasm + npm run build:pkg --workspace=nemo-relay-wasm else - NEMO_FLOW_WASM_RELEASE=1 npm run build:pkg --workspace=nemo-flow-wasm + NEMO_RELAY_WASM_RELEASE=1 npm run build:pkg --workspace=nemo-relay-wasm fi build-all: build-rust build-python build-go build-node build-wasm @@ -799,10 +799,10 @@ clean: docs/_build/ \ docs/reference/api/**/_generated/ \ docs/reference/api/**/_source/ \ - go/nemo_flow/coverage.out \ - python/nemo_flow/*.so \ - python/nemo_flow/__pycache__ \ - python/nemo_flow/_native*.pyd \ + go/nemo_relay/coverage.out \ + python/nemo_relay/*.so \ + python/nemo_relay/__pycache__ \ + python/nemo_relay/_native*.pyd \ python/tests/__pycache__ \ target @@ -813,7 +813,7 @@ test-rust: output_dir="{{ output_dir }}" junit_out="" export_uv_python_runtime - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then coverage_out="$(prepare_artifact rust-workspace.xml)" junit_out="$(prepare_artifact rust_junit_report.xml)" @@ -821,7 +821,7 @@ test-rust: prepare_llvm_cov_workspace fi cargo nextest run --workspace --profile ci - cp "$NEMO_FLOW_REPO_ROOT/target/nextest/ci/rust_junit_report.xml" "$junit_out" + cp "$NEMO_RELAY_REPO_ROOT/target/nextest/ci/rust_junit_report.xml" "$junit_out" if rust_source_coverage_supported; then cargo llvm-cov report \ --ignore-filename-regex '.*/tests/.*\.rs$' \ @@ -841,20 +841,20 @@ test-python: coverage_out="" junit_out="" rust_coverage_out="" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then coverage_out="$(prepare_artifact python-coverage.xml)" junit_out="$(prepare_artifact python-junit.xml)" - pytest_cmd+=(--cov=nemo_flow --cov-report term-missing --cov-report "xml:$coverage_out") + pytest_cmd+=(--cov=nemo_relay --cov-report term-missing --cov-report "xml:$coverage_out") pytest_cmd+=(--junit-xml "$junit_out") export_uv_python_runtime if rust_source_coverage_supported; then rust_coverage_out="$(prepare_artifact python-rust.xml)" prepare_llvm_cov_workspace fi - cargo test -p nemo-flow-python --lib + cargo test -p nemo-relay-python --lib fi - uv sync --inexact --no-install-project --no-install-package nemo-flow + uv sync --inexact --no-install-project --no-install-package nemo-relay activate_project_venv python_executable="$(project_python_executable)" use_project_python_source "$python_executable" @@ -862,7 +862,7 @@ test-python: "$python_executable" -m "${pytest_cmd[@]}" --ignore=python/tests/integrations if is_true "{{ ci }}" && [[ -n "$rust_coverage_out" ]]; then cargo llvm-cov report \ - -p nemo-flow-python \ + -p nemo-relay-python \ --ignore-filename-regex '.*/tests/.*\.rs$' \ --cobertura \ --output-path "$rust_coverage_out" @@ -872,8 +872,8 @@ test-python-langchain: #!/usr/bin/env bash {{ bash_helpers }} pytest_cmd=(pytest) - cd "$NEMO_FLOW_REPO_ROOT" - uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents + cd "$NEMO_RELAY_REPO_ROOT" + uv sync --inexact --no-install-project --no-install-package nemo-relay --extra langchain --extra langgraph --extra deepagents activate_project_venv python_executable="$(project_python_executable)" use_project_python_source "$python_executable" @@ -899,7 +899,7 @@ test-go: fi coverage_out="" junit_out="" - lib_dir="$NEMO_FLOW_REPO_ROOT/target/$target" + lib_dir="$NEMO_RELAY_REPO_ROOT/target/$target" host_os="$(uname -s 2>/dev/null || true)" is_windows=false case "${RUNNER_OS:-}:${OSTYPE:-}:$host_os" in @@ -907,8 +907,8 @@ test-go: is_windows=true ;; esac - cd "$NEMO_FLOW_REPO_ROOT" - cargo build $flag -p nemo-flow-ffi + cd "$NEMO_RELAY_REPO_ROOT" + cargo build $flag -p nemo-relay-ffi if [[ "$is_windows" == true ]]; then export CC=clang @@ -946,7 +946,7 @@ test-go: go_test_cmd+=("-ldflags=${go_ldflags[*]}") fi go_test_cmd+=(./...) - cd "$NEMO_FLOW_REPO_ROOT/go/nemo_flow" + cd "$NEMO_RELAY_REPO_ROOT/go/nemo_relay" if is_true "{{ ci }}"; then # Work-around /dev/stderr not being available on Windows "${go_test_cmd[@]}" 2>&1 | tee >(cat >&2) | go-junit-report -set-exit-code > "$junit_out" @@ -963,7 +963,7 @@ test-node: coverage_out="" junit_out="" rust_coverage_out="" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then coverage_out="$(prepare_artifact node-coverage.xml)" junit_out="$(prepare_artifact node-junit.xml)" @@ -971,40 +971,40 @@ test-node: rust_coverage_out="$(prepare_artifact node-rust.xml)" prepare_llvm_cov_workspace fi - cargo test -p nemo-flow-node --lib + cargo test -p nemo-relay-node --lib fi - npm install --workspace=nemo-flow-node --ignore-scripts + npm install --workspace=nemo-relay-node --ignore-scripts if is_true "{{ ci }}"; then - npm run coverage --workspace=nemo-flow-node + npm run coverage --workspace=nemo-relay-node cp crates/node/coverage/cobertura-coverage.xml "$coverage_out" cp crates/node/junit.xml "$junit_out" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if [[ -n "$rust_coverage_out" ]]; then cargo llvm-cov report \ - -p nemo-flow-node \ + -p nemo-relay-node \ --ignore-filename-regex '.*/tests/.*\.rs$' \ --cobertura \ --output-path "$rust_coverage_out" fi else - npm test --workspace=nemo-flow-node + npm test --workspace=nemo-relay-node fi # --set [ci=true|false] test-openclaw: #!/usr/bin/env bash {{ bash_helpers }} - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" if is_true "{{ ci }}"; then npm ci --ignore-scripts - npm run build-debug --workspace=nemo-flow-node + npm run build-debug --workspace=nemo-relay-node else npm install --ignore-scripts fi - npm run typecheck --workspace=nemo-flow-openclaw - npm test --workspace=nemo-flow-openclaw - npm run test:live --workspace=nemo-flow-openclaw - npm run pack:check --workspace=nemo-flow-openclaw + npm run typecheck --workspace=nemo-relay-openclaw + npm test --workspace=nemo-relay-openclaw + npm run test:live --workspace=nemo-relay-openclaw + npm run pack:check --workspace=nemo-relay-openclaw # --set [output_dir=] [ci=true|false] test-wasm: @@ -1013,17 +1013,17 @@ test-wasm: output_dir="{{ output_dir }}" coverage_out="" junit_out="" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" wasm-pack test --node crates/wasm - npm install --workspace=nemo-flow-wasm --ignore-scripts + npm install --workspace=nemo-relay-wasm --ignore-scripts if is_true "{{ ci }}"; then coverage_out="$(prepare_artifact wasm-js.xml)" junit_out="$(prepare_artifact wasm-junit.xml)" - npm run coverage:pkg --workspace=nemo-flow-wasm + npm run coverage:pkg --workspace=nemo-relay-wasm cp crates/wasm/coverage/cobertura-coverage.xml "$coverage_out" cp crates/wasm/junit.xml "$junit_out" else - npm run test:pkg --workspace=nemo-flow-wasm + npm run test:pkg --workspace=nemo-relay-wasm fi # --set [output_dir=] [ci=true|false] @@ -1041,7 +1041,7 @@ set-version version="": echo "Error: version is required for set-version" >&2 exit 1 fi - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" set_project_version "$version" # --set [output_dir=] [ref_name=] @@ -1052,7 +1052,7 @@ package-node: # If `ref_name` is set, write it as the exact package version before packing. linux_glibc_version="{{ linux_glibc_version }}" output_dir="{{ output_dir }}" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" package_dir="$(prepare_package_dir npm)" if [[ -z "{{ ref_name }}" ]]; then sha="$(head_git_sha)" @@ -1060,25 +1060,25 @@ package-node: package_version="${version}+${sha}" echo "Non-release build: appending commit hash to version" set_npm_package_version crates/node/package.json package-lock.json "$package_version" crates/node - set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-flow-node "$package_version" + set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-relay-node "$package_version" else package_version="{{ ref_name }}" echo "Using explicit version {{ ref_name }}" set_npm_package_version crates/node/package.json package-lock.json "$package_version" crates/node - set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-flow-node "$package_version" + set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-relay-node "$package_version" fi build_args=(build) if is_true "{{ ci }}" && [[ "$(uname -s)" == "Linux" ]]; then # Zig is provided by the uv.lock `ziglang` entry; keep any explicit CI # Zig version pin aligned with that lockfile version. - uv sync --inexact --no-install-project --no-install-package nemo-flow --no-default-groups --group dev + uv sync --inexact --no-install-project --no-install-package nemo-relay --no-default-groups --group dev activate_project_venv prepend_ziglang_to_path "$(project_python_executable)" build_args+=(-- --zig --zig-abi-suffix "$linux_glibc_version") fi - npm install --workspace=nemo-flow-node --ignore-scripts - npm run --workspace=nemo-flow-node "${build_args[@]}" - npm pack --workspace=nemo-flow-node --pack-destination "$package_dir" + npm install --workspace=nemo-relay-node --ignore-scripts + npm run --workspace=nemo-relay-node "${build_args[@]}" + npm pack --workspace=nemo-relay-node --pack-destination "$package_dir" shopt -s nullglob packages=("$package_dir"/*.tgz) if ((${#packages[@]} == 0)); then @@ -1093,7 +1093,7 @@ package-openclaw: # If `ref_name` is empty, append the current short HEAD SHA to the version. # If `ref_name` is set, write it as the exact package version before packing. output_dir="{{ output_dir }}" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" package_dir="$(prepare_package_dir openclaw)" if [[ -z "{{ ref_name }}" ]]; then sha="$(head_git_sha)" @@ -1102,21 +1102,21 @@ package-openclaw: echo "Non-release build: appending commit hash to version" set_npm_package_version crates/node/package.json package-lock.json "$package_version" crates/node set_npm_package_version integrations/openclaw/package.json package-lock.json "$package_version" integrations/openclaw - set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-flow-node "$package_version" + set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-relay-node "$package_version" else package_version="{{ ref_name }}" echo "Using explicit version {{ ref_name }}" set_npm_package_version crates/node/package.json package-lock.json "$package_version" crates/node set_npm_package_version integrations/openclaw/package.json package-lock.json "$package_version" integrations/openclaw - set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-flow-node "$package_version" + set_npm_package_dependency_version integrations/openclaw/package.json package-lock.json integrations/openclaw nemo-relay-node "$package_version" fi - npm install --workspace=nemo-flow-node --workspace=nemo-flow-openclaw --ignore-scripts + npm install --workspace=nemo-relay-node --workspace=nemo-relay-openclaw --ignore-scripts if is_true "{{ ci }}"; then - npm run build-debug --workspace=nemo-flow-node + npm run build-debug --workspace=nemo-relay-node else - npm run build --workspace=nemo-flow-node + npm run build --workspace=nemo-relay-node fi - npm pack --workspace=nemo-flow-openclaw --pack-destination "$package_dir" + npm pack --workspace=nemo-relay-openclaw --pack-destination "$package_dir" shopt -s nullglob packages=("$package_dir"/*.tgz) if ((${#packages[@]} == 0)); then @@ -1133,9 +1133,9 @@ package-python: output_dir="{{ output_dir }}" linux_glibc_version="{{ linux_glibc_version }}" export_uv_python_runtime - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" package_dir="$(prepare_package_dir wheels)" - sync_args=(--no-install-project --no-install-package nemo-flow --no-group docs) + sync_args=(--no-install-project --no-install-package nemo-relay --no-group docs) uv sync --inexact "${sync_args[@]}" activate_project_venv if [[ -z "{{ ref_name }}" ]]; then @@ -1166,7 +1166,7 @@ package-wasm: # `prepare_pkg.mjs` rewrites the wasm-pack output into the publishable npm # layout before this target sets the package version and packs the tarball. output_dir="{{ output_dir }}" - cd "$NEMO_FLOW_REPO_ROOT" + cd "$NEMO_RELAY_REPO_ROOT" package_dir="$(prepare_package_dir wasm)" wasm-pack build --release crates/wasm node crates/wasm/scripts/prepare_pkg.mjs diff --git a/package-lock.json b/package-lock.json index a65b4bce2..213103174 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,10 +1,10 @@ { - "name": "nemo-flow-workspace", + "name": "nemo-relay-workspace", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "nemo-flow-workspace", + "name": "nemo-relay-workspace", "workspaces": [ "crates/node", "crates/wasm", @@ -18,7 +18,7 @@ } }, "crates/node": { - "name": "nemo-flow-node", + "name": "nemo-relay-node", "version": "0.3.0", "license": "Apache-2.0", "devDependencies": { @@ -462,7 +462,7 @@ } }, "crates/wasm": { - "name": "nemo-flow-wasm", + "name": "nemo-relay-wasm", "devDependencies": { "c8": "^11.0.0" }, @@ -834,11 +834,11 @@ } }, "integrations/openclaw": { - "name": "nemo-flow-openclaw", + "name": "nemo-relay-openclaw", "version": "0.3.0", "license": "Apache-2.0", "dependencies": { - "nemo-flow-node": "0.3.0" + "nemo-relay-node": "0.3.0" }, "devDependencies": { "@types/node": "^20.19.0", @@ -4892,15 +4892,15 @@ "node": ">= 0.6" } }, - "node_modules/nemo-flow-node": { + "node_modules/nemo-relay-node": { "resolved": "crates/node", "link": true }, - "node_modules/nemo-flow-openclaw": { + "node_modules/nemo-relay-openclaw": { "resolved": "integrations/openclaw", "link": true }, - "node_modules/nemo-flow-wasm": { + "node_modules/nemo-relay-wasm": { "resolved": "crates/wasm", "link": true }, diff --git a/package.json b/package.json index c9b616312..8d0306deb 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "nemo-flow-workspace", + "name": "nemo-relay-workspace", "private": true, "engines": { "node": ">=20.0.0" diff --git a/patches/hermes-agent/0001-add-nemo-flow-integration.patch b/patches/hermes-agent/0001-add-nemo-relay-integration.patch similarity index 88% rename from patches/hermes-agent/0001-add-nemo-flow-integration.patch rename to patches/hermes-agent/0001-add-nemo-relay-integration.patch index 7795ce5ff..839019fb4 100644 --- a/patches/hermes-agent/0001-add-nemo-flow-integration.patch +++ b/patches/hermes-agent/0001-add-nemo-relay-integration.patch @@ -6,7 +6,7 @@ index a1c46950..3f55d22a 100644 "hermes-agent[bedrock]", "hermes-agent[web]", ] -+nemo-flow = ["nemo-flow"] ++nemo-relay = ["nemo-relay"] [project.scripts] hermes = "hermes_cli.main:main" @@ -14,7 +14,7 @@ index a1c46950..3f55d22a 100644 hermes-acp = "acp_adapter.entry:main" +[project.entry-points."hermes_agent.plugins"] -+nemo_flow = "plugins.nemo_flow" ++nemo_relay = "plugins.nemo_relay" + [tool.setuptools] py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajectory_compressor", "toolset_distributions", "cli", "hermes_constants", "hermes_state", "hermes_time", "hermes_logging", "rl_cli", "utils"] @@ -25,7 +25,7 @@ index a1c46950..3f55d22a 100644 addopts = "-m 'not integration' -n auto" + +[tool.uv.sources] -+nemo-flow = { path = "../..", editable = true } ++nemo-relay = { path = "../..", editable = true } diff --git a/run_agent.py b/run_agent.py index 325df9be..83fbde29 100644 --- a/run_agent.py @@ -40,9 +40,9 @@ index 325df9be..83fbde29 100644 + # 1211-1261) has already run (Pitfall P-03 / ACG-05). Per-request + # gate on self.api_mode re-evaluates fallback crossings + # (Pitfall P-04 / ACG-07). Soft-imported so unpatched Hermes -+ # (no plugins/nemo_flow directory) still runs as a no-op. ++ # (no plugins/nemo_relay directory) still runs as a no-op. + try: -+ from plugins.nemo_flow.override import ( ++ from plugins.nemo_relay.override import ( + maybe_apply_acg_override, + _record_cache_control_owner, + ) @@ -90,19 +90,19 @@ index 325df9be..83fbde29 100644 ) except Exception: pass -diff --git a/plugins/nemo_flow/__init__.py b/plugins/nemo_flow/__init__.py +diff --git a/plugins/nemo_relay/__init__.py b/plugins/nemo_relay/__init__.py new file mode 100644 index 00000000..3fb0c8df --- /dev/null -+++ b/plugins/nemo_flow/__init__.py ++++ b/plugins/nemo_relay/__init__.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 -+"""NeMo-Flow ATOF event + trajectory export bridge for Hermes. ++"""NeMo-Relay ATOF event + trajectory export bridge for Hermes. + +Loaded automatically by Hermes's PluginManager via the -+``hermes_agent.plugins`` entry-point group when ``hermes-agent[nemo-flow]`` -+is installed. Gracefully no-ops when the ``nemo-flow`` package itself is ++``hermes_agent.plugins`` entry-point group when ``hermes-agent[nemo-relay]`` ++is installed. Gracefully no-ops when the ``nemo-relay`` package itself is +not importable so unpatched-Hermes installs still start cleanly. +""" +from __future__ import annotations @@ -112,17 +112,17 @@ index 00000000..3fb0c8df +logger = logging.getLogger(__name__) + +try: -+ import nemo_flow # noqa: F401 ++ import nemo_relay # noqa: F401 + -+ _NEMO_FLOW_OK = True ++ _NEMO_RELAY_OK = True +except ImportError as exc: # noqa: BLE001 — see Threat T-1008-S4 -+ # SMB-05 + Threat T-1008-S4: only swallow ImportError for nemo_flow itself. ++ # SMB-05 + Threat T-1008-S4: only swallow ImportError for nemo_relay itself. + # Any other ImportError (transitive dep failure, syntax error in a different + # module, etc.) must surface so real breakage is not silently masked. -+ if getattr(exc, "name", None) not in ("nemo_flow", None): ++ if getattr(exc, "name", None) not in ("nemo_relay", None): + raise -+ _NEMO_FLOW_OK = False -+ logger.info("nemo-flow package not installed; plugin loaded as no-op") ++ _NEMO_RELAY_OK = False ++ logger.info("nemo-relay package not installed; plugin loaded as no-op") + + +def register(ctx) -> None: @@ -130,11 +130,11 @@ index 00000000..3fb0c8df + + Called by hermes_cli/plugins.py:_load_plugin() once at discovery time. + SMB-05 contract: this function MUST complete without raising even when -+ ``nemo-flow`` is absent, so ``LoadedPlugin.error`` stays None. ++ ``nemo-relay`` is absent, so ``LoadedPlugin.error`` stays None. + """ -+ if not _NEMO_FLOW_OK: ++ if not _NEMO_RELAY_OK: + return # soft-import fallback: nothing to wire -+ from plugins.nemo_flow.observability import ( ++ from plugins.nemo_relay.observability import ( + ensure_openinference_subscriber_registered, + on_session_end, + on_session_finalize, @@ -154,20 +154,20 @@ index 00000000..3fb0c8df + ctx.register_hook("post_api_request", post_api_request) + ctx.register_hook("pre_tool_call", pre_tool_call) + ctx.register_hook("post_tool_call", post_tool_call) -+ logger.info("NeMo-Flow observability hooks registered (8/8)") -diff --git a/plugins/nemo_flow/config.py b/plugins/nemo_flow/config.py ++ logger.info("NeMo-Relay observability hooks registered (8/8)") +diff --git a/plugins/nemo_relay/config.py b/plugins/nemo_relay/config.py new file mode 100644 index 00000000..24c1c975 --- /dev/null -+++ b/plugins/nemo_flow/config.py ++++ b/plugins/nemo_relay/config.py @@ -0,0 +1,141 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 -+"""Configuration reader for the NeMo-Flow plugin. ++"""Configuration reader for the NeMo-Relay plugin. + +Reads from two sources, in precedence order: -+ 1. HERMES_NEMO_FLOW_* environment variables (highest priority) -+ 2. ~/.hermes/config.yaml nemo_flow.* block (fallback) ++ 1. HERMES_NEMO_RELAY_* environment variables (highest priority) ++ 2. ~/.hermes/config.yaml nemo_relay.* block (fallback) +Default: disabled. SMB-03 opt-in contract. +""" +from __future__ import annotations @@ -176,49 +176,49 @@ index 00000000..24c1c975 +from pathlib import Path + + -+def _load_nemo_flow_block() -> dict: ++def _load_nemo_relay_block() -> dict: + try: + from hermes_cli.config import load_config + -+ block = load_config().get("nemo_flow", {}) ++ block = load_config().get("nemo_relay", {}) + return dict(block) if isinstance(block, dict) else {} + except Exception: + return {} + + +def is_enabled() -> bool: -+ """Opt-in gate: HERMES_NEMO_FLOW_ENABLED env var OR yaml nemo_flow.enabled. ++ """Opt-in gate: HERMES_NEMO_RELAY_ENABLED env var OR yaml nemo_relay.enabled. + + Default False per locked decision (1008-RESEARCH.md user_constraints). + """ -+ env = os.environ.get("HERMES_NEMO_FLOW_ENABLED", "").strip().lower() ++ env = os.environ.get("HERMES_NEMO_RELAY_ENABLED", "").strip().lower() + if env in ("1", "true", "yes", "on"): + return True + if env in ("0", "false", "no", "off"): + return False -+ return bool(_load_nemo_flow_block().get("enabled", False)) ++ return bool(_load_nemo_relay_block().get("enabled", False)) + + +def atif_output_dir() -> Path: + """Resolve ATIF JSON output directory. + + Precedence: -+ 1. HERMES_NEMO_FLOW_ATIF_DIR env var -+ 2. config.yaml nemo_flow.atif_output_dir ++ 1. HERMES_NEMO_RELAY_ATIF_DIR env var ++ 2. config.yaml nemo_relay.atif_output_dir + 3. ${HERMES_HOME}/atif + Threat T-1008-S3: sanitize path, refuse directories outside HERMES_HOME ancestors. + """ -+ override = os.environ.get("HERMES_NEMO_FLOW_ATIF_DIR") ++ override = os.environ.get("HERMES_NEMO_RELAY_ATIF_DIR") + if override: + resolved = Path(override).expanduser().resolve() + # Path-traversal guard: reject paths with suspicious parents + # (absolute paths are allowed as long as they resolve cleanly). + if ".." in Path(override).parts: + raise ValueError( -+ "HERMES_NEMO_FLOW_ATIF_DIR must not contain '..' path components" ++ "HERMES_NEMO_RELAY_ATIF_DIR must not contain '..' path components" + ) + return resolved -+ yaml_dir = _load_nemo_flow_block().get("atif_output_dir") ++ yaml_dir = _load_nemo_relay_block().get("atif_output_dir") + if yaml_dir: + return Path(yaml_dir).expanduser().resolve() + try: @@ -230,9 +230,9 @@ index 00000000..24c1c975 + + +def acg_enabled() -> bool: -+ """ACG-specific sub-toggle. Default: True WHEN nemo_flow is enabled. ++ """ACG-specific sub-toggle. Default: True WHEN nemo_relay is enabled. + -+ Precedence: HERMES_NEMO_FLOW_ACG_ENABLED env > yaml nemo_flow.acg.enabled > True. ++ Precedence: HERMES_NEMO_RELAY_ACG_ENABLED env > yaml nemo_relay.acg.enabled > True. + + Master-gate contract (ACG-01): if is_enabled() is False, returns False + regardless of the ACG-specific env or yaml values. If is_enabled() is @@ -242,12 +242,12 @@ index 00000000..24c1c975 + """ + if not is_enabled(): # master switch must be on + return False -+ env = os.environ.get("HERMES_NEMO_FLOW_ACG_ENABLED", "").strip().lower() ++ env = os.environ.get("HERMES_NEMO_RELAY_ACG_ENABLED", "").strip().lower() + if env in ("1", "true", "yes", "on"): + return True + if env in ("0", "false", "no", "off"): + return False -+ block = _load_nemo_flow_block().get("acg", {}) ++ block = _load_nemo_relay_block().get("acg", {}) + if isinstance(block, dict): + # Default True — if ACG subsystem is present, assume user wants it on. + return bool(block.get("enabled", True)) @@ -263,7 +263,7 @@ index 00000000..24c1c975 + dict; only override._ensure_acg_initialized logs exception TYPES + short + messages, never the config body (which may carry Redis passwords). + """ -+ block = _load_nemo_flow_block().get("acg", {}) ++ block = _load_nemo_relay_block().get("acg", {}) + return dict(block) if isinstance(block, dict) else {} + + @@ -271,13 +271,13 @@ index 00000000..24c1c975 + """OpenInference export toggle. Default: off unless explicitly enabled.""" + if not is_enabled(): + return False -+ env = os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_ENABLED", "").strip().lower() ++ env = os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_ENABLED", "").strip().lower() + if env in ("1", "true", "yes", "on"): + return True + if env in ("0", "false", "no", "off"): + return False + -+ block = _load_nemo_flow_block().get("openinference", {}) ++ block = _load_nemo_relay_block().get("openinference", {}) + if isinstance(block, dict): + return bool(block.get("enabled", False)) + return False @@ -285,37 +285,37 @@ index 00000000..24c1c975 + +def openinference_config() -> dict: + """Return OpenInference exporter config with env overrides applied.""" -+ block = _load_nemo_flow_block().get("openinference", {}) ++ block = _load_nemo_relay_block().get("openinference", {}) + config = dict(block) if isinstance(block, dict) else {} + + env_overrides = { -+ "transport": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_TRANSPORT"), -+ "endpoint": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_ENDPOINT"), -+ "service_name": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_SERVICE_NAME"), -+ "service_namespace": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_SERVICE_NAMESPACE"), -+ "service_version": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_SERVICE_VERSION"), -+ "instrumentation_scope": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_INSTRUMENTATION_SCOPE"), -+ "timeout_millis": os.environ.get("HERMES_NEMO_FLOW_OPENINFERENCE_TIMEOUT_MILLIS"), ++ "transport": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_TRANSPORT"), ++ "endpoint": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_ENDPOINT"), ++ "service_name": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_SERVICE_NAME"), ++ "service_namespace": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_SERVICE_NAMESPACE"), ++ "service_version": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_SERVICE_VERSION"), ++ "instrumentation_scope": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_INSTRUMENTATION_SCOPE"), ++ "timeout_millis": os.environ.get("HERMES_NEMO_RELAY_OPENINFERENCE_TIMEOUT_MILLIS"), + } + for key, value in env_overrides.items(): + if value not in (None, ""): + config[key] = value + + return config -diff --git a/plugins/nemo_flow/observability.py b/plugins/nemo_flow/observability.py +diff --git a/plugins/nemo_relay/observability.py b/plugins/nemo_relay/observability.py new file mode 100644 index 00000000..909c489e --- /dev/null -+++ b/plugins/nemo_flow/observability.py ++++ b/plugins/nemo_relay/observability.py @@ -0,0 +1,712 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 -+"""Observability bridge for the NeMo-Flow Hermes plugin. ++"""Observability bridge for the NeMo-Relay Hermes plugin. + -+Translates Hermes's live plugin-hook fires into a NeMo-Flow session scope, ++Translates Hermes's live plugin-hook fires into a NeMo-Relay session scope, +manual LLM/tool lifecycle spans, and AtifExporter lifecycle calls. Python +analog of OpenClaw v1.1 ``patches/openclaw/0001-*.patch:1681-1822`` -+(``ensureSessionRootScope`` + ``endNemoFlowSession``). ++(``ensureSessionRootScope`` + ``endNemoRelaySession``). + +Hook asymmetry (Pitfall P-02): + * ``on_session_start`` — fires ONCE per brand-new session (run_agent.py:8426-8432). @@ -336,14 +336,14 @@ index 00000000..909c489e +logger = logging.getLogger(__name__) + +try: -+ import nemo_flow -+ from nemo_flow import AtifExporter, ScopeHandle, ScopeType ++ import nemo_relay ++ from nemo_relay import AtifExporter, ScopeHandle, ScopeType + -+ _NEMO_FLOW_OK = True ++ _NEMO_RELAY_OK = True +except ImportError as exc: -+ if getattr(exc, "name", None) not in ("nemo_flow", None): ++ if getattr(exc, "name", None) not in ("nemo_relay", None): + raise -+ _NEMO_FLOW_OK = False ++ _NEMO_RELAY_OK = False + AtifExporter = None # type: ignore[assignment] + ScopeHandle = None # type: ignore[assignment] + ScopeType = None # type: ignore[assignment] @@ -354,7 +354,7 @@ index 00000000..909c489e +_session_state: "dict[str, tuple[Any, Any, str]]" = {} +_active_llm_calls: "dict[tuple[str, int], Any]" = {} +_active_tool_calls: "dict[tuple[str, str], Any]" = {} -+_OPENINFERENCE_SUBSCRIBER_NAME = "nemo-flow-openinference" ++_OPENINFERENCE_SUBSCRIBER_NAME = "nemo-relay-openinference" +_openinference_subscriber: Any | None = None +_openinference_cleanup_registered = False + @@ -452,7 +452,7 @@ index 00000000..909c489e + content["system"] = _to_json_safe(system) + if tools is not None: + content["tools"] = _to_json_safe(tools) -+ return nemo_flow.LLMRequest({}, content) ++ return nemo_relay.LLMRequest({}, content) + + +def _build_llm_response( @@ -492,14 +492,14 @@ index 00000000..909c489e + for key in llm_keys: + handle = _active_llm_calls.pop(key) + try: -+ nemo_flow.llm.call_end( ++ nemo_relay.llm.call_end( + handle, + { + "role": "assistant", + "content": f"session_{reason}_before_llm_completion", + }, + data={"hook": f"session_{reason}", "api_call_count": key[1]}, -+ metadata={"source": "plugins.nemo_flow.observability"}, ++ metadata={"source": "plugins.nemo_relay.observability"}, + ) + except Exception as exc: + logger.warning("llm.call_end cleanup failed for %s/%s: %s", session_id, key[1], exc) @@ -508,11 +508,11 @@ index 00000000..909c489e + for key in tool_keys: + handle = _active_tool_calls.pop(key) + try: -+ nemo_flow.tools.call_end( ++ nemo_relay.tools.call_end( + handle, + {"status": f"session_{reason}_before_tool_completion"}, + data={"hook": f"session_{reason}", "tool_call_key": key[1]}, -+ metadata={"source": "plugins.nemo_flow.observability"}, ++ metadata={"source": "plugins.nemo_relay.observability"}, + ) + except Exception as exc: + logger.warning("tool.call_end cleanup failed for %s/%s: %s", session_id, key[1], exc) @@ -551,22 +551,22 @@ index 00000000..909c489e +def ensure_openinference_subscriber_registered() -> None: + global _openinference_subscriber, _openinference_cleanup_registered + -+ from plugins.nemo_flow.config import openinference_config, openinference_enabled ++ from plugins.nemo_relay.config import openinference_config, openinference_enabled + -+ if not _NEMO_FLOW_OK or not openinference_enabled(): ++ if not _NEMO_RELAY_OK or not openinference_enabled(): + return + if _openinference_subscriber is not None: + return + + raw_config = openinference_config() + try: -+ config = nemo_flow.OpenInferenceConfig() ++ config = nemo_relay.OpenInferenceConfig() + config.transport = str(raw_config.get("transport", config.transport)) + config.service_name = str(raw_config.get("service_name", "hermes-agent")) + config.instrumentation_scope = str( + raw_config.get( + "instrumentation_scope", -+ "hermes-agent/nemo-flow/openinference", ++ "hermes-agent/nemo-relay/openinference", + ) + ) + @@ -597,7 +597,7 @@ index 00000000..909c489e + if resource_attributes: + config.resource_attributes = resource_attributes + -+ subscriber = nemo_flow.OpenInferenceSubscriber(config) ++ subscriber = nemo_relay.OpenInferenceSubscriber(config) + subscriber.register(_OPENINFERENCE_SUBSCRIBER_NAME) + except Exception as exc: + logger.warning("OpenInference subscriber setup failed: %s", exc) @@ -618,24 +618,24 @@ index 00000000..909c489e + + +def ensure_session_scope(session_id: str, model: str, platform: str) -> None: -+ """Push the NeMo-Flow scope + register AtifExporter for a session. ++ """Push the NeMo-Relay scope + register AtifExporter for a session. + + Idempotent — subsequent calls for the same session_id are no-ops. Called + by ``on_session_start`` and (Pitfall P-03) by Plan 03's first-pre-api-request + lazy hook for gateway continuation sessions that skip ``on_session_start``. + """ -+ from plugins.nemo_flow.config import is_enabled ++ from plugins.nemo_relay.config import is_enabled + -+ if not _NEMO_FLOW_OK or not is_enabled(): ++ if not _NEMO_RELAY_OK or not is_enabled(): + return + if session_id in _session_state: + return + try: -+ handle = nemo_flow.scope.push( ++ handle = nemo_relay.scope.push( + name=f"hermes-session-{session_id}", + scope_type=ScopeType.Agent, + data={"session_id": session_id, "model": model, "platform": platform}, -+ metadata={"source": "plugins.nemo_flow.observability"}, ++ metadata={"source": "plugins.nemo_relay.observability"}, + ) + exporter = AtifExporter( + session_id=session_id, @@ -643,11 +643,11 @@ index 00000000..909c489e + agent_version=_hermes_version(), + model_name=model, + ) -+ exporter_name = f"nemo-flow-atif-{session_id}" ++ exporter_name = f"nemo-relay-atif-{session_id}" + exporter.register(exporter_name) + _session_state[session_id] = (handle, exporter, exporter_name) + logger.info( -+ "NeMo-Flow session scope pushed: %s (model=%s, platform=%s)", ++ "NeMo-Relay session scope pushed: %s (model=%s, platform=%s)", + session_id, + model, + platform, @@ -677,14 +677,14 @@ index 00000000..909c489e + + +def _finalize(session_id: str, reason: str) -> None: -+ from plugins.nemo_flow.config import atif_output_dir ++ from plugins.nemo_relay.config import atif_output_dir + + state = _session_state.pop(session_id, None) + # Phase 1009: drop all ACG override ledger entries for this session. + # Threat T-1009-I1 (memory leak across sessions). Soft-imported so + # observability still works if override.py is absent (partial install). + try: -+ from plugins.nemo_flow.override import cleanup_session as _acg_cleanup ++ from plugins.nemo_relay.override import cleanup_session as _acg_cleanup + + _acg_cleanup(session_id) + except ImportError: @@ -694,7 +694,7 @@ index 00000000..909c489e + handle, exporter, exporter_name = state + _close_active_session_children(session_id, reason) + try: -+ nemo_flow.scope.pop(handle) ++ nemo_relay.scope.pop(handle) + except Exception as exc: + logger.warning("scope.pop failed for %s: %s", session_id, exc) + _force_flush_openinference_subscriber() @@ -703,7 +703,7 @@ index 00000000..909c489e + out_dir.mkdir(parents=True, exist_ok=True) + out_path = out_dir / f"{session_id}.json" + out_path.write_text(exporter.export_json(), encoding="utf-8") -+ logger.info("NeMo-Flow ATIF exported (%s): %s", reason, out_path) ++ logger.info("NeMo-Relay ATIF exported (%s): %s", reason, out_path) + except Exception as exc: + logger.warning("ATIF export failed for %s: %s", session_id, exc) + try: @@ -715,13 +715,13 @@ index 00000000..909c489e + +def on_session_finalize(session_id: str | None = None, platform: str = "cli", **_: Any) -> None: + """Hermes fires this on CLI exit (cli.py:642) and /new (cli.py:4119).""" -+ if _NEMO_FLOW_OK and session_id: ++ if _NEMO_RELAY_OK and session_id: + _finalize(session_id, reason="finalize") + + +def on_session_reset(session_id: str | None = None, platform: str = "cli", **_: Any) -> None: + """Hermes fires this on /reset (cli.py:4167).""" -+ if _NEMO_FLOW_OK and session_id: ++ if _NEMO_RELAY_OK and session_id: + _finalize(session_id, reason="reset") + + @@ -758,9 +758,9 @@ index 00000000..909c489e + fire ``on_session_start`` — if this is the first time we see the + session, push the scope and register the exporter now. + """ -+ from plugins.nemo_flow.config import is_enabled ++ from plugins.nemo_relay.config import is_enabled + -+ if not _NEMO_FLOW_OK or not is_enabled(): ++ if not _NEMO_RELAY_OK or not is_enabled(): + return + # Pitfall P-03: lazy-push for continuation sessions that skipped on_session_start. + if session_id and session_id not in _session_state: @@ -780,7 +780,7 @@ index 00000000..909c489e + # raised), default "none" is returned — matches the "no ACG + # attribution available" semantic. + try: -+ from plugins.nemo_flow.override import _pop_cache_control_owner ++ from plugins.nemo_relay.override import _pop_cache_control_owner + + _cc_owner = _pop_cache_control_owner(session_id, api_call_count) + except ImportError: @@ -826,7 +826,7 @@ index 00000000..909c489e + # (mark-step conversion drops metadata but other subscriber types read it). + "cache_control.owner": _cc_owner, + } -+ llm_handle = nemo_flow.llm.call( ++ llm_handle = nemo_relay.llm.call( + provider or "llm", + request, + handle=handle, @@ -864,9 +864,9 @@ index 00000000..909c489e + No dedup needed: retries that fail exit via the exception path and never + reach post_api_request — only successful attempts get here. + """ -+ from plugins.nemo_flow.config import is_enabled ++ from plugins.nemo_relay.config import is_enabled + -+ if not _NEMO_FLOW_OK or not is_enabled(): ++ if not _NEMO_RELAY_OK or not is_enabled(): + return + if not session_id or session_id not in _session_state: + return @@ -900,7 +900,7 @@ index 00000000..909c489e + "api_call_count": api_call_count, + "hook": "post_api_request", + } -+ nemo_flow.llm.call_end( ++ nemo_relay.llm.call_end( + llm_handle, + response, + data=data, @@ -926,9 +926,9 @@ index 00000000..909c489e + Returns ``None`` — this plugin is observability-only and never gates + tool execution. A non-None return would BLOCK the tool call. + """ -+ from plugins.nemo_flow.config import is_enabled ++ from plugins.nemo_relay.config import is_enabled + -+ if not _NEMO_FLOW_OK or not is_enabled(): ++ if not _NEMO_RELAY_OK or not is_enabled(): + return None + if not session_id or session_id not in _session_state: + return None @@ -948,7 +948,7 @@ index 00000000..909c489e + "tool_call_id": tool_call_id, + "hook": "pre_tool_call", + } -+ tool_handle = nemo_flow.tools.call( ++ tool_handle = nemo_relay.tools.call( + tool_name, + args or {}, + handle=handle, @@ -971,9 +971,9 @@ index 00000000..909c489e + **_: Any, +) -> None: + """Hermes fires this after tool dispatch.""" -+ from plugins.nemo_flow.config import is_enabled ++ from plugins.nemo_relay.config import is_enabled + -+ if not _NEMO_FLOW_OK or not is_enabled(): ++ if not _NEMO_RELAY_OK or not is_enabled(): + return + if not session_id or session_id not in _session_state: + return @@ -995,7 +995,7 @@ index 00000000..909c489e + "tool_call_id": tool_call_id, + "hook": "post_tool_call", + } -+ nemo_flow.tools.call_end( ++ nemo_relay.tools.call_end( + tool_handle, + _normalize_tool_result(result), + data=data, @@ -1020,15 +1020,15 @@ index 00000000..909c489e + "_active_llm_calls", + "_active_tool_calls", +] -diff --git a/plugins/nemo_flow/override.py b/plugins/nemo_flow/override.py +diff --git a/plugins/nemo_relay/override.py b/plugins/nemo_relay/override.py new file mode 100644 index 00000000..6b8f5661 --- /dev/null -+++ b/plugins/nemo_flow/override.py ++++ b/plugins/nemo_relay/override.py @@ -0,0 +1,621 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 -+"""ACG override helper for the NeMo-Flow Hermes plugin. ++"""ACG override helper for the NeMo-Relay Hermes plugin. + +Phase 1009 glue: when Hermes's outbound request has ``api_mode == +"anthropic_messages"`` AND ACG is enabled, this helper authoritatively owns @@ -1057,8 +1057,8 @@ index 00000000..6b8f5661 + +# Soft-import guard (same pattern as observability.py:26-37). +try: -+ import nemo_flow # noqa: F401 -+ from nemo_flow.adaptive import ( # noqa: F401 ++ import nemo_relay # noqa: F401 ++ from nemo_relay.adaptive import ( # noqa: F401 + AcgConfig, + AdaptiveConfig, + AdaptiveRuntime, @@ -1067,18 +1067,18 @@ index 00000000..6b8f5661 + TelemetryConfig, + ) + -+ _NEMO_FLOW_OK = True ++ _NEMO_RELAY_OK = True +except ImportError as exc: # noqa: BLE001 — see Threat T-1008-S4 -+ if getattr(exc, "name", None) not in ("nemo_flow", None): ++ if getattr(exc, "name", None) not in ("nemo_relay", None): + raise -+ _NEMO_FLOW_OK = False ++ _NEMO_RELAY_OK = False + AcgConfig = None # type: ignore[assignment] + AdaptiveConfig = None # type: ignore[assignment] + AdaptiveRuntime = None # type: ignore[assignment] + BackendSpec = None # type: ignore[assignment] + StateConfig = None # type: ignore[assignment] + TelemetryConfig = None # type: ignore[assignment] -+ logger.info("nemo-flow package not installed; ACG override disabled") ++ logger.info("nemo-relay package not installed; ACG override disabled") + + +Owner = Literal["acg", "native", "none"] @@ -1128,7 +1128,7 @@ index 00000000..6b8f5661 + """Apply ACG cache_control override when eligible; otherwise pass through. + + ACG fires only when ALL of: -+ 1. ``_NEMO_FLOW_OK`` (nemo-flow package importable) ++ 1. ``_NEMO_RELAY_OK`` (nemo-relay package importable) + 2. ``api_mode == "anthropic_messages"`` (per-request gate — Pitfall P-04) + 3. ``acg_enabled()`` (config says ACG is on — master-gated by is_enabled) + 4. ``session_id not in _acg_init_failed`` (fail-open on prior init failure) @@ -1152,12 +1152,12 @@ index 00000000..6b8f5661 + if api_mode != "anthropic_messages": + return api_kwargs, "none" + -+ # Soft-import fallback: if nemo-flow is absent, native runs as-is. -+ if not _NEMO_FLOW_OK: ++ # Soft-import fallback: if nemo-relay is absent, native runs as-is. ++ if not _NEMO_RELAY_OK: + return api_kwargs, "native" + + # Master + ACG gate check. -+ from plugins.nemo_flow.config import acg_enabled ++ from plugins.nemo_relay.config import acg_enabled + + if not acg_enabled(): + return api_kwargs, "native" @@ -1192,7 +1192,7 @@ index 00000000..6b8f5661 + # Per-request translation failure: fall back to native for THIS + # request ONLY. Do NOT poison the session (different failure class + # from init). Next request in this session will retry translation. -+ if not getattr(exc, "_nemo_flow_logged", False): ++ if not getattr(exc, "_nemo_relay_logged", False): + logger.warning( + "ACG translation failed for session %s api_call_count %d — " + "falling back to native for this request. Reason: %s", @@ -1260,7 +1260,7 @@ index 00000000..6b8f5661 + + thread = threading.Thread( + target=_thread_runner, -+ name="nemo-flow-acg-sync-bridge", ++ name="nemo-relay-acg-sync-bridge", + daemon=True, + ) + thread.start() @@ -1290,13 +1290,13 @@ index 00000000..6b8f5661 + +def _ensure_acg_scope_binding(session_id: str, model: str) -> None: + """Ensure the session scope exists and the runtime is bound to it.""" -+ from plugins.nemo_flow.observability import _session_state, ensure_session_scope ++ from plugins.nemo_relay.observability import _session_state, ensure_session_scope + + if session_id not in _session_state: + ensure_session_scope(session_id, model, "") + state = _session_state.get(session_id) + if state is None: -+ raise RuntimeError(f"NeMo Flow session scope is unavailable for session {session_id!r}") ++ raise RuntimeError(f"NeMo Relay session scope is unavailable for session {session_id!r}") + handle, _, _ = state + _get_session_runtime(session_id).bind_scope(handle) + @@ -1308,9 +1308,9 @@ index 00000000..6b8f5661 + """Initialize a session-owned AdaptiveRuntime once per session. Idempotent.""" + if session_id in _acg_initialized: + return -+ from plugins.nemo_flow.config import acg_config ++ from plugins.nemo_relay.config import acg_config + -+ cfg = acg_config() # reads nemo_flow.acg.* yaml block + env overrides ++ cfg = acg_config() # reads nemo_relay.acg.* yaml block + env overrides + runtime = AdaptiveRuntime( + AdaptiveConfig( + agent_id=cfg.get("agent_id", "hermes-agent"), @@ -1411,7 +1411,7 @@ index 00000000..6b8f5661 + if session_id not in _acg_runtimes: + return + -+ from nemo_flow import LLMRequest, ScopeType, codecs, llm, scope ++ from nemo_relay import LLMRequest, ScopeType, codecs, llm, scope + + runtime = _get_session_runtime(session_id) + agent_id = _acg_config_cache.get(session_id, {}).get("agent_id", "hermes-agent") @@ -1419,14 +1419,14 @@ index 00000000..6b8f5661 + + async def _record(_request): # noqa: ANN202 + _ = _request -+ return {"id": f"nemo-flow-acg-observation-{session_id}", "type": "message"} ++ return {"id": f"nemo-relay-acg-observation-{session_id}", "type": "message"} + + async def _execute_observation(): # noqa: ANN202 + with scope.scope( + f"{agent_id}-acg-observation", + ScopeType.Agent, -+ data={"session_id": session_id, "source": "plugins.nemo_flow.override"}, -+ metadata={"source": "plugins.nemo_flow.override"}, ++ data={"session_id": session_id, "source": "plugins.nemo_relay.override"}, ++ metadata={"source": "plugins.nemo_relay.override"}, + ): + return await llm.execute( + "anthropic", @@ -1454,13 +1454,13 @@ index 00000000..6b8f5661 + 4. Asserting <= 4 markers total (Anthropic's breakpoint budget). + + Translation backend choice: -+ - **Option A (preferred):** nemo_flow.adaptive codec round-trip via ++ - **Option A (preferred):** nemo_relay.adaptive codec round-trip via + AnthropicMessagesCodec — Assumption A1 in 1009-RESEARCH.md L793. + If the codec exposes a callable Python entry point that accepts + an Anthropic-shape api_kwargs and returns an annotated request + with cache_control decisions, use it. + - **Option B (fallback):** if the codec is not directly callable from -+ Python in the current nemo-flow build, place markers on the last ++ Python in the current nemo-relay build, place markers on the last + cacheable block of the system + last 3 non-system message boundaries + (mirrors the native Hermes semantic at + agent/prompt_caching.py:41-72 but via ACG-owned placement logic). @@ -1496,13 +1496,13 @@ index 00000000..6b8f5661 + + # Step 4: Post-condition — assert <= 4 breakpoints (ACG-06). + # In production: WARNING log + drop excess. In test mode -+ # (HERMES_NEMO_FLOW_ACG_ASSERT=1): raise AssertionError so tests ++ # (HERMES_NEMO_RELAY_ACG_ASSERT=1): raise AssertionError so tests + # catch regressions loudly. + import os as _os + + count = _count_cache_markers(working_kwargs) + if count > 4: -+ if _os.environ.get("HERMES_NEMO_FLOW_ACG_ASSERT", "").strip().lower() in ("1", "true", "yes", "on"): ++ if _os.environ.get("HERMES_NEMO_RELAY_ACG_ASSERT", "").strip().lower() in ("1", "true", "yes", "on"): + raise AssertionError( + f"ACG-06 violated: {count} cache_control markers exceed Anthropic's 4-breakpoint budget" + ) @@ -1522,14 +1522,14 @@ index 00000000..6b8f5661 + """Write ACG-authored cache_control markers onto the payload. + + Option A binds the per-session ``AdaptiveRuntime`` to the long-lived Hermes -+ session scope, then explicitly invokes ``nemo_flow.llm.request_intercepts`` -+ on the provider-native request. That keeps Hermes on the normal NeMo Flow ++ session scope, then explicitly invokes ``nemo_relay.llm.request_intercepts`` ++ on the provider-native request. That keeps Hermes on the normal NeMo Relay + request-intercept surface instead of exposing a runtime-owned execution + intercept. ImportError still falls through to the 1009 Python fallback for + defense-in-depth. + """ + try: -+ from nemo_flow import LLMRequest, llm ++ from nemo_relay import LLMRequest, llm + + _ensure_acg_scope_binding(session_id, str(api_kwargs.get("model", ""))) + translated_request = llm.request_intercepts( @@ -1545,7 +1545,7 @@ index 00000000..6b8f5661 + "ACG scope-bound request intercept raised; falling back to native for this request. Reason: %s", + exc, + ) -+ setattr(exc, "_nemo_flow_logged", True) ++ setattr(exc, "_nemo_relay_logged", True) + raise + except ImportError: + pass diff --git a/patches/hermes-agent/notes.md b/patches/hermes-agent/notes.md index cf39d2085..a9e03aae3 100644 --- a/patches/hermes-agent/notes.md +++ b/patches/hermes-agent/notes.md @@ -3,16 +3,16 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# NeMo-Flow Hermes Integration — Operator Notes +# NeMo-Relay Hermes Integration — Operator Notes These notes are the operator runbook for installing the tracked Hermes + -NeMo-Flow integration from a fresh NeMo-Flow checkout. The maintained patch is -runtime-only: it wires Hermes to the NeMo-Flow plugin entry point, hooks, and +NeMo-Relay integration from a fresh NeMo-Relay checkout. The maintained patch is +runtime-only: it wires Hermes to the NeMo-Relay plugin entry point, hooks, and ACG override seam, but it does not carry Hermes-side tests or smoke harnesses. -At runtime, the plugin emits a NeMo-Flow session scope plus manual LLM/tool +At runtime, the plugin emits a NeMo-Relay session scope plus manual LLM/tool lifecycle spans and uses `AtifExporter` to materialize trajectory JSON on session finalization. -All commands assume your working directory is the NeMo-Flow repo root unless a +All commands assume your working directory is the NeMo-Relay repo root unless a step says otherwise. ## Prerequisites @@ -34,7 +34,7 @@ or any other secret-bearing `.env` file into the repo. ### Step 1: Prepare the pinned Hermes checkout The maintained Hermes baseline is pinned in `third_party/sources.lock`. Clone -Hermes and detach at that exact commit before you apply the NeMo-Flow patch. +Hermes and detach at that exact commit before you apply the NeMo-Relay patch. ```bash HERMES_COMMIT=$(git config -f third_party/sources.lock --get submodule.third_party/hermes-agent.commit) @@ -47,28 +47,28 @@ git -C third_party/hermes-agent log --oneline -1 Success signal: `git log --oneline -1` prints the same commit you read from `third_party/sources.lock`. -### Step 2: Apply the tracked NeMo-Flow patch +### Step 2: Apply the tracked NeMo-Relay patch Check that the patch applies cleanly, then apply it. ```bash -git -C third_party/hermes-agent apply --check ../../patches/hermes-agent/0001-add-nemo-flow-integration.patch -git -C third_party/hermes-agent apply ../../patches/hermes-agent/0001-add-nemo-flow-integration.patch +git -C third_party/hermes-agent apply --check ../../patches/hermes-agent/0001-add-nemo-relay-integration.patch +git -C third_party/hermes-agent apply ../../patches/hermes-agent/0001-add-nemo-relay-integration.patch ``` Success signal: `git apply --check` prints no errors, and the second command returns to the shell without conflicts. -### Step 3: Bootstrap Hermes with the `nemo-flow` extra +### Step 3: Bootstrap Hermes with the `nemo-relay` extra Hermes discovers this integration through its plugin entry points, so reinstall -the editable package with the `nemo-flow` extra after the patch is applied. +the editable package with the `nemo-relay` extra after the patch is applied. ```bash cd third_party/hermes-agent uv venv .venv --python 3.11 . .venv/bin/activate -uv pip install -e '.[nemo-flow]' --force-reinstall +uv pip install -e '.[nemo-relay]' --force-reinstall uv run hermes --help ``` @@ -89,37 +89,37 @@ mkdir -p "${HERMES_HOME:-$HOME/.hermes}" cat > "${HERMES_HOME:-$HOME/.hermes}/.env" <<'EOF' # Optional: required only for a real Anthropic-backed agent turn. ANTHROPIC_API_KEY= -HERMES_NEMO_FLOW_ENABLED=1 -HERMES_NEMO_FLOW_ACG_ENABLED=1 -HERMES_NEMO_FLOW_ATIF_DIR=${HERMES_HOME:-$HOME/.hermes}/atif -HERMES_NEMO_FLOW_OPENINFERENCE_ENABLED=1 -HERMES_NEMO_FLOW_OPENINFERENCE_TRANSPORT=grpc -HERMES_NEMO_FLOW_OPENINFERENCE_ENDPOINT=http://127.0.0.1:4317 -HERMES_NEMO_FLOW_OPENINFERENCE_SERVICE_NAME=hermes-agent -HERMES_NEMO_FLOW_OPENINFERENCE_INSTRUMENTATION_SCOPE=hermes-agent/nemo-flow/openinference +HERMES_NEMO_RELAY_ENABLED=1 +HERMES_NEMO_RELAY_ACG_ENABLED=1 +HERMES_NEMO_RELAY_ATIF_DIR=${HERMES_HOME:-$HOME/.hermes}/atif +HERMES_NEMO_RELAY_OPENINFERENCE_ENABLED=1 +HERMES_NEMO_RELAY_OPENINFERENCE_TRANSPORT=grpc +HERMES_NEMO_RELAY_OPENINFERENCE_ENDPOINT=http://127.0.0.1:4317 +HERMES_NEMO_RELAY_OPENINFERENCE_SERVICE_NAME=hermes-agent +HERMES_NEMO_RELAY_OPENINFERENCE_INSTRUMENTATION_SCOPE=hermes-agent/nemo-relay/openinference EOF ``` Use these knobs as the operator contract: -- `HERMES_NEMO_FLOW_ENABLED=1` enables the integration. If it is unset, - Hermes falls back to `nemo_flow.enabled` in `~/.hermes/config.yaml`. The +- `HERMES_NEMO_RELAY_ENABLED=1` enables the integration. If it is unset, + Hermes falls back to `nemo_relay.enabled` in `~/.hermes/config.yaml`. The default is off. -- `HERMES_NEMO_FLOW_ACG_ENABLED=1` turns on the ACG override path. If the +- `HERMES_NEMO_RELAY_ACG_ENABLED=1` turns on the ACG override path. If the master switch is on and this sub-toggle is unset, Hermes defaults ACG to on. -- `HERMES_NEMO_FLOW_ACG_ENABLED=0` keeps the plugin loaded but preserves native +- `HERMES_NEMO_RELAY_ACG_ENABLED=0` keeps the plugin loaded but preserves native Hermes prompt-caching behavior. -- `HERMES_NEMO_FLOW_ATIF_DIR` overrides the ATIF output directory. If it is - unset, Hermes falls back to `nemo_flow.atif_output_dir` in YAML and then to +- `HERMES_NEMO_RELAY_ATIF_DIR` overrides the ATIF output directory. If it is + unset, Hermes falls back to `nemo_relay.atif_output_dir` in YAML and then to `${HERMES_HOME}/atif`. -- `HERMES_NEMO_FLOW_OPENINFERENCE_ENABLED=1` turns on OTLP export for the - emitted NeMo-Flow events. -- `HERMES_NEMO_FLOW_OPENINFERENCE_TRANSPORT=grpc` selects the OTLP gRPC +- `HERMES_NEMO_RELAY_OPENINFERENCE_ENABLED=1` turns on OTLP export for the + emitted NeMo-Relay events. +- `HERMES_NEMO_RELAY_OPENINFERENCE_TRANSPORT=grpc` selects the OTLP gRPC exporter path that Phoenix expects on port `4317`. -- `HERMES_NEMO_FLOW_OPENINFERENCE_ENDPOINT` points the plugin at the OTLP +- `HERMES_NEMO_RELAY_OPENINFERENCE_ENDPOINT` points the plugin at the OTLP collector endpoint, for example `http://127.0.0.1:4317`. -- `HERMES_NEMO_FLOW_OPENINFERENCE_SERVICE_NAME` and - `HERMES_NEMO_FLOW_OPENINFERENCE_INSTRUMENTATION_SCOPE` control how the spans +- `HERMES_NEMO_RELAY_OPENINFERENCE_SERVICE_NAME` and + `HERMES_NEMO_RELAY_OPENINFERENCE_INSTRUMENTATION_SCOPE` control how the spans show up in the OpenInference-aware backend. ### Step 5: Use YAML only as a fallback for non-secret settings @@ -129,7 +129,7 @@ If you prefer to keep non-secret toggles in YAML, put them in file. ```yaml -nemo_flow: +nemo_relay: enabled: true atif_output_dir: /absolute/path/to/atif acg: @@ -139,7 +139,7 @@ nemo_flow: transport: grpc endpoint: http://127.0.0.1:4317 service_name: hermes-agent - instrumentation_scope: hermes-agent/nemo-flow/openinference + instrumentation_scope: hermes-agent/nemo-relay/openinference ``` Recommendation: keep credentials and the primary on/off switches in @@ -147,7 +147,7 @@ Recommendation: keep credentials and the primary on/off switches in ## Smoke Validation -You are now in a patched Hermes checkout with the `nemo-flow` extra installed +You are now in a patched Hermes checkout with the `nemo-relay` extra installed and the enablement knobs set in `~/.hermes/.env`. ### Structural validation @@ -169,10 +169,10 @@ elif isinstance(eps, dict): else: group = [ep for ep in eps if ep.group == "hermes_agent.plugins"] -matches = [ep.value for ep in group if ep.name == "nemo_flow"] -assert matches == ["plugins.nemo_flow"], matches +matches = [ep.value for ep in group if ep.name == "nemo_relay"] +assert matches == ["plugins.nemo_relay"], matches -import plugins.nemo_flow as plugin +import plugins.nemo_relay as plugin assert callable(getattr(plugin, "register", None)) print("entrypoint:", matches[0]) @@ -182,7 +182,7 @@ PY Success signal: -- The snippet prints `entrypoint: plugins.nemo_flow` +- The snippet prints `entrypoint: plugins.nemo_relay` - The snippet prints `register(): ok` ### Lifecycle smoke without a model key @@ -195,7 +195,7 @@ OpenInference OTLP export over gRPC. ```bash cd third_party/hermes-agent . .venv/bin/activate -ATIF_DIR="${HERMES_NEMO_FLOW_ATIF_DIR:-${HERMES_HOME:-$HOME/.hermes}/atif}" +ATIF_DIR="${HERMES_NEMO_RELAY_ATIF_DIR:-${HERMES_HOME:-$HOME/.hermes}/atif}" mkdir -p "$ATIF_DIR" python - <<'PY' @@ -204,7 +204,7 @@ from hermes_cli.plugins import discover_plugins, get_plugin_manager, invoke_hook discover_plugins() plugins = get_plugin_manager().list_plugins() -assert any(plugin["name"] == "nemo_flow" and plugin["enabled"] for plugin in plugins), plugins +assert any(plugin["name"] == "nemo_relay" and plugin["enabled"] for plugin in plugins), plugins session_id = f"phoenix-smoke-{uuid.uuid4().hex[:8]}" model = "anthropic/claude-sonnet-4" @@ -271,7 +271,7 @@ Success signal: - The Python snippet prints a fresh `phoenix-smoke-...` session ID - `ls -lt "$ATIF_DIR"` shows a fresh session JSON written by the finalize hook -- The plugin manager reports `nemo_flow` as enabled before the smoke emits any +- The plugin manager reports `nemo_relay` as enabled before the smoke emits any events ### Verify ingestion in Phoenix @@ -301,12 +301,12 @@ Success signal: When an Anthropic API key is available, run one real Hermes turn and explicitly finalize the plugin session so the trajectory exporter flushes to disk. This also exercises the Anthropic ACG override seam when -`HERMES_NEMO_FLOW_ACG_ENABLED=1`. +`HERMES_NEMO_RELAY_ACG_ENABLED=1`. ```bash cd third_party/hermes-agent . .venv/bin/activate -ATIF_DIR="${HERMES_NEMO_FLOW_ATIF_DIR:-${HERMES_HOME:-$HOME/.hermes}/atif}" +ATIF_DIR="${HERMES_NEMO_RELAY_ATIF_DIR:-${HERMES_HOME:-$HOME/.hermes}/atif}" mkdir -p "$ATIF_DIR" python - <<'PY' @@ -337,8 +337,8 @@ PY When the integration is enabled, exported trajectory JSON lands in this precedence order: -1. `HERMES_NEMO_FLOW_ATIF_DIR` -2. `nemo_flow.atif_output_dir` in `~/.hermes/config.yaml` +1. `HERMES_NEMO_RELAY_ATIF_DIR` +2. `nemo_relay.atif_output_dir` in `~/.hermes/config.yaml` 3. `${HERMES_HOME:-$HOME/.hermes}/atif` After the smoke suite finishes, confirm that the expected directory contains a @@ -346,12 +346,12 @@ fresh session JSON for the run you just exercised. ## Disable -To keep Hermes patched but turn off NeMo-Flow completely, set -`HERMES_NEMO_FLOW_ENABLED=0` in `~/.hermes/.env` or remove the `nemo_flow` +To keep Hermes patched but turn off NeMo-Relay completely, set +`HERMES_NEMO_RELAY_ENABLED=0` in `~/.hermes/.env` or remove the `nemo_relay` block from `~/.hermes/config.yaml`. To keep observability installed but disable only ACG ownership, leave -`HERMES_NEMO_FLOW_ENABLED=1` and set `HERMES_NEMO_FLOW_ACG_ENABLED=0`. +`HERMES_NEMO_RELAY_ENABLED=1` and set `HERMES_NEMO_RELAY_ACG_ENABLED=0`. After changing either switch, start a new shell or reactivate the `.venv` before rerunning Hermes. If you want a quick post-change check, rerun the CLI @@ -359,8 +359,8 @@ smoke command from the previous section before you continue operator work. ## Uninstall -To return this checkout to native Hermes, remove the NeMo-Flow-specific config, -delete the patched virtualenv, and reinstall Hermes without the `nemo-flow` +To return this checkout to native Hermes, remove the NeMo-Relay-specific config, +delete the patched virtualenv, and reinstall Hermes without the `nemo-relay` extra. ```bash @@ -373,11 +373,11 @@ uv pip install -e . --force-reinstall If you also want a clean upstream tree, reclone `third_party/hermes-agent` from the pinned commit in `third_party/sources.lock`, skip the patch-apply step, and -leave the `HERMES_NEMO_FLOW_*` variables out of `~/.hermes/.env`. +leave the `HERMES_NEMO_RELAY_*` variables out of `~/.hermes/.env`. ## Patch Refresh -Patch maintenance always starts from the NeMo-Flow repo root. The checked-in +Patch maintenance always starts from the NeMo-Relay repo root. The checked-in scripts are tracked `100644`, so invoke them with `bash` rather than trying to execute them directly. @@ -406,7 +406,7 @@ bash ./scripts/apply-patches.sh --check Success signal: -- `patches/hermes-agent/0001-add-nemo-flow-integration.patch` contains your new +- `patches/hermes-agent/0001-add-nemo-relay-integration.patch` contains your new Hermes delta - `bash ./scripts/apply-patches.sh --check` still returns without patch failures diff --git a/patches/langchain-nvidia/0001-add-nemo-flow-integration.patch b/patches/langchain-nvidia/0001-add-nemo-relay-integration.patch similarity index 77% rename from patches/langchain-nvidia/0001-add-nemo-flow-integration.patch rename to patches/langchain-nvidia/0001-add-nemo-relay-integration.patch index b8f9ca4d8..ab049897c 100644 --- a/patches/langchain-nvidia/0001-add-nemo-flow-integration.patch +++ b/patches/langchain-nvidia/0001-add-nemo-relay-integration.patch @@ -6,7 +6,7 @@ index 07df9ab..4525133 100644 from langchain_core.utils.utils import _build_model_kwargs from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator -+from langchain_nvidia_ai_endpoints import _nemo_flow ++from langchain_nvidia_ai_endpoints import _nemo_relay from langchain_nvidia_ai_endpoints._common import _NVIDIAClient from langchain_nvidia_ai_endpoints._statics import Model from langchain_nvidia_ai_endpoints._utils import convert_message_to_dict @@ -16,8 +16,8 @@ index 07df9ab..4525133 100644 ) + structured_output = _is_structured_output(payload) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload, extra_headers) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload, extra_headers) + + async def _call(req: Any) -> dict: + raw = await self._client.aget_req( @@ -26,8 +26,8 @@ index 07df9ab..4525133 100644 + resp, _ = self._client.postprocess(raw) + return resp + -+ resp_dict = _nemo_flow.run_sync( -+ _nemo_flow.llm_execute(self.model, request, _call) ++ resp_dict = _nemo_relay.run_sync( ++ _nemo_relay.llm_execute(self.model, request, _call) + ) + self._set_callback_out(resp_dict, run_manager) + parsed = self._custom_postprocess( @@ -49,8 +49,8 @@ index 07df9ab..4525133 100644 ) structured_output = _is_structured_output(payload) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload, extra_headers) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload, extra_headers) + collected: list[dict] = [] + + async def _call(req: Any) -> Any: @@ -66,7 +66,7 @@ index 07df9ab..4525133 100644 + return collected[-1] if collected else {} + + async def _run() -> list[dict]: -+ stream = await _nemo_flow.llm_stream_execute( ++ stream = await _nemo_relay.llm_stream_execute( + self.model, request, _call, _collector, _finalizer + ) + chunks: list[dict] = [] @@ -74,7 +74,7 @@ index 07df9ab..4525133 100644 + chunks.append(chunk_dict) + return chunks + -+ chunk_dicts = _nemo_flow.run_sync(_run()) ++ chunk_dicts = _nemo_relay.run_sync(_run()) + for chunk_dict in chunk_dicts: + lc_chunk = self._process_stream_chunk( + chunk_dict, run_manager, structured_output @@ -93,8 +93,8 @@ index 07df9ab..4525133 100644 ) + structured_output = _is_structured_output(payload) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload, extra_headers) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload, extra_headers) + + async def _call(req: Any) -> dict: + raw = await self._client.aget_req( @@ -103,7 +103,7 @@ index 07df9ab..4525133 100644 + resp, _ = self._client.postprocess(raw) + return resp + -+ resp_dict = await _nemo_flow.llm_execute(self.model, request, _call) ++ resp_dict = await _nemo_relay.llm_execute(self.model, request, _call) + self._set_callback_out(resp_dict, run_manager) + parsed = self._custom_postprocess( + resp_dict, streaming=False, structured_output=structured_output @@ -126,8 +126,8 @@ index 07df9ab..4525133 100644 ) structured_output = _is_structured_output(payload) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload, extra_headers) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload, extra_headers) + collected: list[dict] = [] + + async def _call(req: Any) -> Any: @@ -142,7 +142,7 @@ index 07df9ab..4525133 100644 + def _finalizer() -> dict: + return collected[-1] if collected else {} + -+ stream = await _nemo_flow.llm_stream_execute( ++ stream = await _nemo_relay.llm_stream_execute( + self.model, request, _call, _collector, _finalizer + ) + async for chunk_dict in stream: @@ -157,23 +157,23 @@ index 07df9ab..4525133 100644 async for response in self._client.aget_req_stream( payload=payload, extra_headers=extra_headers ): -diff --git a/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_flow.py b/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_flow.py +diff --git a/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_relay.py b/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_relay.py new file mode 100644 index 0000000..fbd0818 --- /dev/null -+++ b/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_flow.py ++++ b/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_relay.py @@ -0,0 +1,126 @@ -+"""Thin bridge module for optional NeMo Flow integration. ++"""Thin bridge module for optional NeMo Relay integration. + -+When nemo_flow is installed and a scope stack has been initialized by the ++When nemo_relay is installed and a scope stack has been initialized by the +caller, the helpers in this module route LLM calls through the full -+NeMo Flow middleware pipeline (guardrails, intercepts, execution intercepts). -+If nemo_flow is not installed or no scope stack is active, ``available()`` ++NeMo Relay middleware pipeline (guardrails, intercepts, execution intercepts). ++If nemo_relay is not installed or no scope stack is active, ``available()`` +returns ``False`` and ChatNVIDIA falls back to its vanilla code path. + -+LLM calls use the standard NeMo Flow API (``nemo_flow.llm.execute`` / -+``nemo_flow.llm.stream_execute``) with ``codec=nemo_flow.codecs.OpenAIChatCodec()`` -+and ``response_codec=nemo_flow.codecs.OpenAIChatCodec()`` to get structured ++LLM calls use the standard NeMo Relay API (``nemo_relay.llm.execute`` / ++``nemo_relay.llm.stream_execute``) with ``codec=nemo_relay.codecs.OpenAIChatCodec()`` ++and ``response_codec=nemo_relay.codecs.OpenAIChatCodec()`` to get structured +``AnnotatedLLMRequest`` / ``AnnotatedLLMResponse`` on LLM start/end events via +the built-in OpenAI Chat codec (NIM uses OpenAI-compatible format). +""" @@ -186,22 +186,22 @@ index 0000000..fbd0818 +from typing import Any, Callable + +try: -+ import nemo_flow -+ from nemo_flow import LLMRequest ++ import nemo_relay ++ from nemo_relay import LLMRequest + -+ _HAS_NEMO_FLOW = True ++ _HAS_NEMO_RELAY = True +except ImportError: -+ _HAS_NEMO_FLOW = False ++ _HAS_NEMO_RELAY = False + + +def available() -> bool: -+ """Return True when nemo_flow is importable *and* a scope stack is active.""" -+ if not _HAS_NEMO_FLOW: ++ """Return True when nemo_relay is importable *and* a scope stack is active.""" ++ if not _HAS_NEMO_RELAY: + return False + try: -+ # Only consider nemo_flow available if the caller has explicitly ++ # Only consider nemo_relay available if the caller has explicitly + # initialised a scope stack (we don't want to auto-create one). -+ return nemo_flow.scope_stack_active() ++ return nemo_relay.scope_stack_active() + except Exception: + return False + @@ -222,7 +222,7 @@ index 0000000..fbd0818 + + When offloading to a ThreadPoolExecutor worker, this helper propagates + both Python contextvars and the Rust thread-local scope stack so that -+ NeMo Flow telemetry is preserved on the worker thread. ++ NeMo Relay telemetry is preserved on the worker thread. + """ + try: + asyncio.get_running_loop() @@ -232,12 +232,12 @@ index 0000000..fbd0818 + # Loop already running -- offload to a worker thread so we don't block. + # Propagate contextvars and scope stack to the worker thread. + ctx = contextvars.copy_context() -+ if _HAS_NEMO_FLOW: ++ if _HAS_NEMO_RELAY: + try: -+ scope_stack = nemo_flow.get_scope_stack() ++ scope_stack = nemo_relay.get_scope_stack() + + def _run_with_scope_stack() -> Any: -+ nemo_flow.set_thread_scope_stack(scope_stack) ++ nemo_relay.set_thread_scope_stack(scope_stack) + return asyncio.run(coro) + + with ThreadPoolExecutor(max_workers=1) as pool: @@ -260,14 +260,14 @@ index 0000000..fbd0818 + request: "LLMRequest", + func: Callable[..., Any], +) -> Any: -+ """Execute a non-streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.execute( ++ """Execute a non-streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.execute( + model_name, + request, + func, + model_name=model_name, -+ codec=nemo_flow.codecs.OpenAIChatCodec(), -+ response_codec=nemo_flow.codecs.OpenAIChatCodec(), ++ codec=nemo_relay.codecs.OpenAIChatCodec(), ++ response_codec=nemo_relay.codecs.OpenAIChatCodec(), + ) + + @@ -278,14 +278,14 @@ index 0000000..fbd0818 + collector: Callable[[Any], None], + finalizer: Callable[[], Any], +) -> Any: -+ """Execute a streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.stream_execute( ++ """Execute a streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.stream_execute( + model_name, + request, + func, + collector, + finalizer, + model_name=model_name, -+ codec=nemo_flow.codecs.OpenAIChatCodec(), -+ response_codec=nemo_flow.codecs.OpenAIChatCodec(), ++ codec=nemo_relay.codecs.OpenAIChatCodec(), ++ response_codec=nemo_relay.codecs.OpenAIChatCodec(), + ) diff --git a/patches/langchain/0001-add-nemo-flow-integration.patch b/patches/langchain/0001-add-nemo-relay-integration.patch similarity index 79% rename from patches/langchain/0001-add-nemo-flow-integration.patch rename to patches/langchain/0001-add-nemo-relay-integration.patch index 9bf58a5e7..f2149f40c 100644 --- a/patches/langchain/0001-add-nemo-flow-integration.patch +++ b/patches/langchain/0001-add-nemo-relay-integration.patch @@ -6,7 +6,7 @@ index e1f1775248..f3ebc8b9e6 100644 ToolManagerMixin, ) from langchain_core.callbacks.file import FileCallbackHandler -+ from langchain_core.callbacks.nemo_flow_handler import NemoFlowCallbackHandler ++ from langchain_core.callbacks.nemo_relay_handler import NemoRelayCallbackHandler from langchain_core.callbacks.manager import ( AsyncCallbackManager, AsyncCallbackManagerForChainGroup, @@ -14,7 +14,7 @@ index e1f1775248..f3ebc8b9e6 100644 "ChainManagerMixin", "FileCallbackHandler", "LLMManagerMixin", -+ "NemoFlowCallbackHandler", ++ "NemoRelayCallbackHandler", "ParentRunManager", "RetrieverManagerMixin", "RunManager", @@ -22,7 +22,7 @@ index e1f1775248..f3ebc8b9e6 100644 "RunManagerMixin": "base", "ToolManagerMixin": "base", "FileCallbackHandler": "file", -+ "NemoFlowCallbackHandler": "nemo_flow_handler", ++ "NemoRelayCallbackHandler": "nemo_relay_handler", "AsyncCallbackManager": "manager", "AsyncCallbackManagerForChainGroup": "manager", "AsyncCallbackManagerForChainRun": "manager", @@ -34,7 +34,7 @@ index 7026a2e8fb..80a650f218 100644 _parse_google_docstring, _py_38_safe_origin, ) -+from langchain_core.utils._nemo_flow import get_nemo_flow ++from langchain_core.utils._nemo_relay import get_nemo_relay from langchain_core.utils.pydantic import ( TypeBaseModel, _create_subset_model, @@ -46,7 +46,7 @@ index 7026a2e8fb..80a650f218 100644 + def _func(_args: Any) -> Any: + return context.run(self._run, *tool_args, **tool_kwargs) + -+ if (nnex := get_nemo_flow()) is not None: ++ if (nnex := get_nemo_relay()) is not None: + import asyncio + import contextvars + from concurrent.futures import ThreadPoolExecutor @@ -57,7 +57,7 @@ index 7026a2e8fb..80a650f218 100644 + # to the worker thread's Rust thread-local storage. + scope_stack = nnex.get_scope_stack() + -+ async def _nemo_flow_run() -> Any: ++ async def _nemo_relay_run() -> Any: + return await nnex.typed.tool_execute( + self.name, + tool_input, @@ -69,9 +69,9 @@ index 7026a2e8fb..80a650f218 100644 + def _run_with_scope_stack() -> Any: + # Bind the parent's scope stack to this thread's + # Rust-side thread-local before running the async -+ # nemo_flow pipeline. ++ # nemo_relay pipeline. + nnex.set_thread_scope_stack(scope_stack) -+ return asyncio.run(_nemo_flow_run()) ++ return asyncio.run(_nemo_relay_run()) + + try: + asyncio.get_running_loop() @@ -80,7 +80,7 @@ index 7026a2e8fb..80a650f218 100644 + ctx.run, _run_with_scope_stack + ).result() + except RuntimeError: -+ response = asyncio.run(_nemo_flow_run()) ++ response = asyncio.run(_nemo_relay_run()) + else: + response = _func(tool_input) if self.response_format == "content_and_artifact": @@ -96,7 +96,7 @@ index 7026a2e8fb..80a650f218 100644 + coro = self._arun(*tool_args, **tool_kwargs) + return await coro_with_context(coro, context) + -+ if (nnex := get_nemo_flow()) is not None: ++ if (nnex := get_nemo_relay()) is not None: + codec = nnex.typed.BestEffortAnyCodec() + response = await nnex.typed.tool_execute( + self.name, @@ -132,7 +132,7 @@ index ee9f480427..8ec8db6541 100644 from typing_extensions import NotRequired, Self, TypedDict -from langchain_anthropic import __version__ -+from langchain_anthropic import __version__, _nemo_flow ++from langchain_anthropic import __version__, _nemo_relay from langchain_anthropic._client_utils import ( _get_default_async_httpx_client, _get_default_httpx_client, @@ -141,8 +141,8 @@ index ee9f480427..8ec8db6541 100644 kwargs["stream"] = True payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload) + collected_events: list = [] + collected_dicts: list[dict] = [] + @@ -159,15 +159,15 @@ index ee9f480427..8ec8db6541 100644 + return collected_dicts[-1] if collected_dicts else {} + + async def _run() -> list[dict]: -+ nemo_flow_stream = await _nemo_flow.llm_stream_execute( ++ nemo_relay_stream = await _nemo_relay.llm_stream_execute( + self.model, request, _call, _collector, _finalizer + ) + chunks: list[dict] = [] -+ async for chunk_dict in nemo_flow_stream: ++ async for chunk_dict in nemo_relay_stream: + chunks.append(chunk_dict) + return chunks + -+ _nemo_flow.run_sync(_run()) ++ _nemo_relay.run_sync(_run()) + coerce_content_to_string = ( + not _tools_in_params(payload) + and not _documents_in_params(payload) @@ -197,8 +197,8 @@ index ee9f480427..8ec8db6541 100644 kwargs["stream"] = True payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload) + collected_events: list = [] + collected_dicts: list[dict] = [] + @@ -214,10 +214,10 @@ index ee9f480427..8ec8db6541 100644 + def _finalizer() -> dict: + return collected_dicts[-1] if collected_dicts else {} + -+ nemo_flow_stream = await _nemo_flow.llm_stream_execute( ++ nemo_relay_stream = await _nemo_relay.llm_stream_execute( + self.model, request, _call, _collector, _finalizer + ) -+ async for _chunk_dict in nemo_flow_stream: ++ async for _chunk_dict in nemo_relay_stream: + pass # Stream consumed; events captured in collected_events + + coerce_content_to_string = ( @@ -249,8 +249,8 @@ index ee9f480427..8ec8db6541 100644 ) -> ChatResult: payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload) + _sdk_data: list = [] + + async def _call(req: Any) -> dict: @@ -258,8 +258,8 @@ index ee9f480427..8ec8db6541 100644 + _sdk_data.append(data) + return data.model_dump() + -+ _nemo_flow.run_sync( -+ _nemo_flow.llm_execute(self.model, request, _call) ++ _nemo_relay.run_sync( ++ _nemo_relay.llm_execute(self.model, request, _call) + ) + return self._format_output(_sdk_data[0], **kwargs) + @@ -271,8 +271,8 @@ index ee9f480427..8ec8db6541 100644 ) -> ChatResult: payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): -+ request = _nemo_flow.make_request(payload) ++ if _nemo_relay.available(): ++ request = _nemo_relay.make_request(payload) + _sdk_data: list = [] + + async def _call(req: Any) -> dict: @@ -280,7 +280,7 @@ index ee9f480427..8ec8db6541 100644 + _sdk_data.append(data) + return data.model_dump() + -+ await _nemo_flow.llm_execute(self.model, request, _call) ++ await _nemo_relay.llm_execute(self.model, request, _call) + return self._format_output(_sdk_data[0], **kwargs) + try: @@ -294,7 +294,7 @@ index c74c40f3c5..bb834e5c1d 100644 from pydantic.v1 import BaseModel as BaseModelV1 from typing_extensions import Self -+from langchain_openai.chat_models import _nemo_flow ++from langchain_openai.chat_models import _nemo_relay from langchain_openai.chat_models._client_utils import ( _get_default_async_httpx_client, _get_default_httpx_client, @@ -305,12 +305,12 @@ index c74c40f3c5..bb834e5c1d 100644 - base_generation_info = {} + base_generation_info: dict = {} + -+ # NeMo Flow path: standard chat completions only. ++ # NeMo Relay path: standard chat completions only. + if ( -+ _nemo_flow.available() ++ _nemo_relay.available() + and "response_format" not in payload + ): -+ request = _nemo_flow.make_request(payload) ++ request = _nemo_relay.make_request(payload) + collected: list[dict] = [] + + async def _call(req: Any) -> Any: @@ -326,7 +326,7 @@ index c74c40f3c5..bb834e5c1d 100644 + return collected[-1] if collected else {} + + async def _run() -> list[dict]: -+ stream = await _nemo_flow.llm_stream_execute( ++ stream = await _nemo_relay.llm_stream_execute( + self.model_name, request, _call, _collector, _finalizer + ) + chunks: list[dict] = [] @@ -334,7 +334,7 @@ index c74c40f3c5..bb834e5c1d 100644 + chunks.append(chunk_dict) + return chunks + -+ chunk_dicts = _nemo_flow.run_sync(_run()) ++ chunk_dicts = _nemo_relay.run_sync(_run()) + is_first_chunk = True + for chunk_dict in chunk_dicts: + generation_chunk = self._convert_chunk_to_generation_chunk( @@ -363,11 +363,11 @@ index c74c40f3c5..bb834e5c1d 100644 self._ensure_sync_client_available() payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): ++ if _nemo_relay.available(): + use_responses = self._use_responses_api(payload) + has_response_format = "response_format" in payload + original_schema_obj = kwargs.get("response_format") -+ request = _nemo_flow.make_request(payload) ++ request = _nemo_relay.make_request(payload) + # Capture the SDK response for post-processing paths that + # require it (responses API, structured output .parsed). + _sdk_response: list = [] @@ -398,8 +398,8 @@ index c74c40f3c5..bb834e5c1d 100644 + _sdk_response.append((sdk_resp, raw)) + return sdk_resp.model_dump() + -+ resp_dict = _nemo_flow.run_sync( -+ _nemo_flow.llm_execute(self.model_name, request, _call) ++ resp_dict = _nemo_relay.run_sync( ++ _nemo_relay.llm_execute(self.model_name, request, _call) + ) + sdk_resp, raw_resp = _sdk_response[0] + generation_info = None @@ -427,12 +427,12 @@ index c74c40f3c5..bb834e5c1d 100644 - base_generation_info = {} + base_generation_info: dict = {} + -+ # NeMo Flow path: standard chat completions only. ++ # NeMo Relay path: standard chat completions only. + if ( -+ _nemo_flow.available() ++ _nemo_relay.available() + and "response_format" not in payload + ): -+ request = _nemo_flow.make_request(payload) ++ request = _nemo_relay.make_request(payload) + collected: list[dict] = [] + + async def _call(req: Any) -> Any: @@ -447,7 +447,7 @@ index c74c40f3c5..bb834e5c1d 100644 + def _finalizer() -> dict: + return collected[-1] if collected else {} + -+ stream = await _nemo_flow.llm_stream_execute( ++ stream = await _nemo_relay.llm_stream_execute( + self.model_name, request, _call, _collector, _finalizer + ) + is_first_chunk = True @@ -478,11 +478,11 @@ index c74c40f3c5..bb834e5c1d 100644 ) -> ChatResult: payload = self._get_request_payload(messages, stop=stop, **kwargs) + -+ if _nemo_flow.available(): ++ if _nemo_relay.available(): + use_responses = self._use_responses_api(payload) + has_response_format = "response_format" in payload + original_schema_obj = kwargs.get("response_format") -+ request = _nemo_flow.make_request(payload) ++ request = _nemo_relay.make_request(payload) + _sdk_response: list = [] + + async def _call(req: Any) -> dict: @@ -511,7 +511,7 @@ index c74c40f3c5..bb834e5c1d 100644 + _sdk_response.append((sdk_resp, raw)) + return sdk_resp.model_dump() + -+ resp_dict = await _nemo_flow.llm_execute(self.model_name, request, _call) ++ resp_dict = await _nemo_relay.llm_execute(self.model_name, request, _call) + sdk_resp, raw_resp = _sdk_response[0] + generation_info = None + if ( @@ -531,22 +531,22 @@ index c74c40f3c5..bb834e5c1d 100644 generation_info = None raw_response = None try: -diff --git a/libs/core/langchain_core/callbacks/nemo_flow_handler.py b/libs/core/langchain_core/callbacks/nemo_flow_handler.py +diff --git a/libs/core/langchain_core/callbacks/nemo_relay_handler.py b/libs/core/langchain_core/callbacks/nemo_relay_handler.py new file mode 100644 index 0000000000..72e9614607 --- /dev/null -+++ b/libs/core/langchain_core/callbacks/nemo_flow_handler.py ++++ b/libs/core/langchain_core/callbacks/nemo_relay_handler.py @@ -0,0 +1,145 @@ -+"""NeMo Flow callback handler for LangChain. ++"""NeMo Relay callback handler for LangChain. + -+Maps LangChain's ``run_id`` / ``parent_run_id`` hierarchy to NeMo Flow ++Maps LangChain's ``run_id`` / ``parent_run_id`` hierarchy to NeMo Relay +scopes. + +Tool-call lifecycle events are handled at the ``ToolNode`` level via +``tools.execute``. LLM-level events are captured at the provider level +(OpenAI, Anthropic, …) where HTTP request details are available. + -+All NeMo Flow errors are caught and logged at DEBUG level so they never ++All NeMo Relay errors are caught and logged at DEBUG level so they never +propagate to LangChain users. +""" + @@ -568,29 +568,29 @@ index 0000000000..72e9614607 +_logger = logging.getLogger(__name__) + + -+class NemoFlowCallbackHandler(BaseCallbackHandler): -+ """LangChain callback handler that bridges to the NeMo Flow runtime. ++class NemoRelayCallbackHandler(BaseCallbackHandler): ++ """LangChain callback handler that bridges to the NeMo Relay runtime. + + Responsibilities: + -+ * **Scope management** — ``on_chain_start`` pushes a new NeMo Flow ++ * **Scope management** — ``on_chain_start`` pushes a new NeMo Relay + ``Agent`` scope (parented to the LangChain ``parent_run_id`` scope if + one exists); ``on_chain_end`` / ``on_chain_error`` pop it. + + Tool lifecycle is handled by ``ToolNode`` via ``tools.execute``. + + The handler keeps an internal dict that maps LangChain ``run_id`` -+ (UUID) to the corresponding NeMo Flow scope handle: ++ (UUID) to the corresponding NeMo Relay scope handle: + + * ``_scope_handles: dict[UUID, ScopeHandle]`` + -+ If NeMo Flow is not installed the handler is a silent no-op. ++ If NeMo Relay is not installed the handler is a silent no-op. + + Example:: + -+ from langchain_core.callbacks import NemoFlowCallbackHandler ++ from langchain_core.callbacks import NemoRelayCallbackHandler + -+ handler = NemoFlowCallbackHandler() ++ handler = NemoRelayCallbackHandler() + llm.invoke("Hello", config={"callbacks": [handler]}) + """ + @@ -614,7 +614,7 @@ index 0000000000..72e9614607 + metadata: dict[str, Any] | None = None, + **kwargs: Any, + ) -> Any: -+ """Push an NeMo Flow ``Agent`` scope for this chain run.""" ++ """Push an NeMo Relay ``Agent`` scope for this chain run.""" + if self._nnex is None: + return + try: @@ -628,7 +628,7 @@ index 0000000000..72e9614607 + ) + self._scope_handles[run_id] = handle + except Exception: -+ _logger.debug("NeMo Flow: on_chain_start failed", exc_info=True) ++ _logger.debug("NeMo Relay: on_chain_start failed", exc_info=True) + + def on_chain_end( + self, @@ -638,7 +638,7 @@ index 0000000000..72e9614607 + parent_run_id: UUID | None = None, + **kwargs: Any, + ) -> Any: -+ """Pop the NeMo Flow scope for this chain run.""" ++ """Pop the NeMo Relay scope for this chain run.""" + self._pop_scope(run_id) + + def on_chain_error( @@ -649,7 +649,7 @@ index 0000000000..72e9614607 + parent_run_id: UUID | None = None, + **kwargs: Any, + ) -> Any: -+ """Pop the NeMo Flow scope on chain error.""" ++ """Pop the NeMo Relay scope on chain error.""" + self._pop_scope(run_id) + + # ------------------------------------------------------------------ @@ -666,7 +666,7 @@ index 0000000000..72e9614607 + try: + self._nnex.scope.pop(handle) + except Exception: -+ _logger.debug("NeMo Flow: scope.pop failed", exc_info=True) ++ _logger.debug("NeMo Relay: scope.pop failed", exc_info=True) + + +# ------------------------------------------------------------------ @@ -675,23 +675,23 @@ index 0000000000..72e9614607 + + +def _try_import() -> Any: -+ """Attempt to import ``nemo_flow``; return the module or ``None``.""" ++ """Attempt to import ``nemo_relay``; return the module or ``None``.""" + try: -+ from langchain_core.utils._nemo_flow import get_nemo_flow ++ from langchain_core.utils._nemo_relay import get_nemo_relay + -+ return get_nemo_flow() ++ return get_nemo_relay() + except Exception: + return None -diff --git a/libs/core/langchain_core/utils/_nemo_flow.py b/libs/core/langchain_core/utils/_nemo_flow.py +diff --git a/libs/core/langchain_core/utils/_nemo_relay.py b/libs/core/langchain_core/utils/_nemo_relay.py new file mode 100644 index 0000000000..10f21c21d9 --- /dev/null -+++ b/libs/core/langchain_core/utils/_nemo_flow.py ++++ b/libs/core/langchain_core/utils/_nemo_relay.py @@ -0,0 +1,35 @@ -+"""Lazy import helper for optional NeMo Flow integration. ++"""Lazy import helper for optional NeMo Relay integration. + -+NeMo Flow is an optional dependency. All functions in this module are safe to -+call regardless of whether NeMo Flow is installed — they return ``None`` or ++NeMo Relay is an optional dependency. All functions in this module are safe to ++call regardless of whether NeMo Relay is installed — they return ``None`` or +``False`` when the package is not available. +""" + @@ -701,35 +701,35 @@ index 0000000000..10f21c21d9 +from types import ModuleType + +_logger = logging.getLogger(__name__) -+_nemo_flow: ModuleType | None | bool = False # False = not yet attempted ++_nemo_relay: ModuleType | None | bool = False # False = not yet attempted + + -+def get_nemo_flow() -> ModuleType | None: -+ """Return the ``nemo_flow`` module, or ``None`` if not installed. ++def get_nemo_relay() -> ModuleType | None: ++ """Return the ``nemo_relay`` module, or ``None`` if not installed. + + The import is performed lazily on first call and cached thereafter. + """ -+ global _nemo_flow # noqa: PLW0603 -+ if _nemo_flow is False: ++ global _nemo_relay # noqa: PLW0603 ++ if _nemo_relay is False: + try: -+ import nemo_flow # type: ignore[import-untyped] ++ import nemo_relay # type: ignore[import-untyped] + -+ _nemo_flow = nemo_flow ++ _nemo_relay = nemo_relay + except ImportError: -+ _nemo_flow = None -+ return _nemo_flow # type: ignore[return-value] ++ _nemo_relay = None ++ return _nemo_relay # type: ignore[return-value] + + +def is_available() -> bool: -+ """Return ``True`` if NeMo Flow is installed and importable.""" -+ return get_nemo_flow() is not None -diff --git a/libs/core/tests/unit_tests/callbacks/test_nemo_flow_handler.py b/libs/core/tests/unit_tests/callbacks/test_nemo_flow_handler.py ++ """Return ``True`` if NeMo Relay is installed and importable.""" ++ return get_nemo_relay() is not None +diff --git a/libs/core/tests/unit_tests/callbacks/test_nemo_relay_handler.py b/libs/core/tests/unit_tests/callbacks/test_nemo_relay_handler.py new file mode 100644 index 0000000000..e7796d7825 --- /dev/null -+++ b/libs/core/tests/unit_tests/callbacks/test_nemo_flow_handler.py ++++ b/libs/core/tests/unit_tests/callbacks/test_nemo_relay_handler.py @@ -0,0 +1,197 @@ -+"""Tests for the NeMo Flow callback handler.""" ++"""Tests for the NeMo Relay callback handler.""" + +from __future__ import annotations + @@ -740,19 +740,19 @@ index 0000000000..e7796d7825 + +import pytest + -+from langchain_core.callbacks.nemo_flow_handler import ( -+ NemoFlowCallbackHandler, ++from langchain_core.callbacks.nemo_relay_handler import ( ++ NemoRelayCallbackHandler, +) + + +# --------------------------------------------------------------------------- -+# Fixtures — mock NeMo Flow module ++# Fixtures — mock NeMo Relay module +# --------------------------------------------------------------------------- + + +def _make_mock_nnex() -> ModuleType: -+ """Build a minimal mock of the ``nemo_flow`` module.""" -+ nnex = ModuleType("nemo_flow") ++ """Build a minimal mock of the ``nemo_relay`` module.""" ++ nnex = ModuleType("nemo_relay") + + # ScopeType enum + scope_type = SimpleNamespace(Agent="Agent") @@ -775,8 +775,8 @@ index 0000000000..e7796d7825 + + +@pytest.fixture() -+def handler(mock_nnex: ModuleType) -> NemoFlowCallbackHandler: -+ h = NemoFlowCallbackHandler() ++def handler(mock_nnex: ModuleType) -> NemoRelayCallbackHandler: ++ h = NemoRelayCallbackHandler() + h._nnex = mock_nnex + return h + @@ -790,7 +790,7 @@ index 0000000000..e7796d7825 + """Verify that chain start/end/error map to scope push/pop.""" + + def test_on_chain_start_pushes_scope( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + run_id = uuid4() + handler.on_chain_start( @@ -802,7 +802,7 @@ index 0000000000..e7796d7825 + assert run_id in handler._scope_handles + + def test_on_chain_end_pops_scope( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + run_id = uuid4() + handler.on_chain_start( @@ -818,7 +818,7 @@ index 0000000000..e7796d7825 + assert run_id not in handler._scope_handles + + def test_on_chain_error_pops_scope( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + run_id = uuid4() + handler.on_chain_start( @@ -834,7 +834,7 @@ index 0000000000..e7796d7825 + assert run_id not in handler._scope_handles + + def test_parent_scope_passed_to_push( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + parent_id = uuid4() + child_id = uuid4() @@ -855,7 +855,7 @@ index 0000000000..e7796d7825 + assert call_kwargs.kwargs.get("handle") is parent_handle + + def test_chain_end_without_start_is_noop( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + """Ending a scope that was never started should not raise.""" + handler.on_chain_end( @@ -865,7 +865,7 @@ index 0000000000..e7796d7825 + mock_nnex.scope.pop.assert_not_called() + + def test_name_fallback_to_id( -+ self, handler: NemoFlowCallbackHandler, mock_nnex: ModuleType ++ self, handler: NemoRelayCallbackHandler, mock_nnex: ModuleType + ) -> None: + """If 'name' is missing, fall back to last element of 'id'.""" + run_id = uuid4() @@ -879,25 +879,25 @@ index 0000000000..e7796d7825 + + +# --------------------------------------------------------------------------- -+# Tests — graceful no-op when NeMo Flow is not installed ++# Tests — graceful no-op when NeMo Relay is not installed +# --------------------------------------------------------------------------- + + +class TestGracefulNoOp: -+ """Verify the handler is a silent no-op when NeMo Flow is absent.""" ++ """Verify the handler is a silent no-op when NeMo Relay is absent.""" + + def test_no_nnex_on_chain_start(self) -> None: -+ h = NemoFlowCallbackHandler() ++ h = NemoRelayCallbackHandler() + h._nnex = None + h.on_chain_start({"name": "x"}, {}, run_id=uuid4()) + + def test_no_nnex_on_chain_end(self) -> None: -+ h = NemoFlowCallbackHandler() ++ h = NemoRelayCallbackHandler() + h._nnex = None + h.on_chain_end({}, run_id=uuid4()) + + def test_no_nnex_on_chain_error(self) -> None: -+ h = NemoFlowCallbackHandler() ++ h = NemoRelayCallbackHandler() + h._nnex = None + h.on_chain_error(RuntimeError("e"), run_id=uuid4()) + @@ -908,42 +908,42 @@ index 0000000000..e7796d7825 + + +class TestErrorSwallowing: -+ """Ensure NeMo Flow errors never propagate.""" ++ """Ensure NeMo Relay errors never propagate.""" + + def test_scope_push_error_swallowed(self, mock_nnex: ModuleType) -> None: + mock_nnex.scope.push.side_effect = RuntimeError("nnex failure") -+ h = NemoFlowCallbackHandler() ++ h = NemoRelayCallbackHandler() + h._nnex = mock_nnex + # Should not raise + h.on_chain_start({"name": "x"}, {}, run_id=uuid4()) + + def test_scope_pop_error_swallowed(self, mock_nnex: ModuleType) -> None: + mock_nnex.scope.pop.side_effect = RuntimeError("nnex failure") -+ h = NemoFlowCallbackHandler() ++ h = NemoRelayCallbackHandler() + h._nnex = mock_nnex + run_id = uuid4() + h.on_chain_start({"name": "x"}, {}, run_id=run_id) + # Reset the push side effect for pop to work + mock_nnex.scope.pop.side_effect = RuntimeError("nnex failure") + h.on_chain_end({}, run_id=run_id) -diff --git a/libs/partners/anthropic/langchain_anthropic/_nemo_flow.py b/libs/partners/anthropic/langchain_anthropic/_nemo_flow.py +diff --git a/libs/partners/anthropic/langchain_anthropic/_nemo_relay.py b/libs/partners/anthropic/langchain_anthropic/_nemo_relay.py new file mode 100644 index 0000000000..66644f74ad --- /dev/null -+++ b/libs/partners/anthropic/langchain_anthropic/_nemo_flow.py ++++ b/libs/partners/anthropic/langchain_anthropic/_nemo_relay.py @@ -0,0 +1,127 @@ -+"""Thin bridge module for optional NeMo Flow integration. ++"""Thin bridge module for optional NeMo Relay integration. + -+When nemo_flow is installed and a scope stack has been initialized by the ++When nemo_relay is installed and a scope stack has been initialized by the +caller, the helpers in this module route LLM calls through the full -+NeMo Flow middleware pipeline (guardrails, intercepts, execution intercepts). -+If nemo_flow is not installed or no scope stack is active, ``available()`` ++NeMo Relay middleware pipeline (guardrails, intercepts, execution intercepts). ++If nemo_relay is not installed or no scope stack is active, ``available()`` +returns ``False`` and ChatAnthropic falls back to its vanilla code path. + -+LLM calls use the standard NeMo Flow API (``nemo_flow.llm.execute`` / -+``nemo_flow.llm.stream_execute``) with -+``codec=nemo_flow.codecs.AnthropicMessagesCodec()`` and -+``response_codec=nemo_flow.codecs.AnthropicMessagesCodec()`` to get structured ++LLM calls use the standard NeMo Relay API (``nemo_relay.llm.execute`` / ++``nemo_relay.llm.stream_execute``) with ++``codec=nemo_relay.codecs.AnthropicMessagesCodec()`` and ++``response_codec=nemo_relay.codecs.AnthropicMessagesCodec()`` to get structured +``AnnotatedLLMRequest`` / ``AnnotatedLLMResponse`` on LLM start/end events via +the built-in Anthropic Messages codec. +""" @@ -956,22 +956,22 @@ index 0000000000..66644f74ad +from typing import Any, Callable + +try: -+ import nemo_flow -+ from nemo_flow import LLMRequest ++ import nemo_relay ++ from nemo_relay import LLMRequest + -+ _HAS_NEMO_FLOW = True ++ _HAS_NEMO_RELAY = True +except ImportError: -+ _HAS_NEMO_FLOW = False ++ _HAS_NEMO_RELAY = False + + +def available() -> bool: -+ """Return True when nemo_flow is importable *and* a scope stack is active.""" -+ if not _HAS_NEMO_FLOW: ++ """Return True when nemo_relay is importable *and* a scope stack is active.""" ++ if not _HAS_NEMO_RELAY: + return False + try: -+ # Only consider nemo_flow available if the caller has explicitly ++ # Only consider nemo_relay available if the caller has explicitly + # initialised a scope stack (we don't want to auto-create one). -+ return nemo_flow.scope_stack_active() ++ return nemo_relay.scope_stack_active() + except Exception: + return False + @@ -992,7 +992,7 @@ index 0000000000..66644f74ad + + When offloading to a ThreadPoolExecutor worker, this helper propagates + both Python contextvars and the Rust thread-local scope stack so that -+ NeMo Flow telemetry is preserved on the worker thread. ++ NeMo Relay telemetry is preserved on the worker thread. + """ + try: + asyncio.get_running_loop() @@ -1002,12 +1002,12 @@ index 0000000000..66644f74ad + # Loop already running -- offload to a worker thread so we don't block. + # Propagate contextvars and scope stack to the worker thread. + ctx = contextvars.copy_context() -+ if _HAS_NEMO_FLOW: ++ if _HAS_NEMO_RELAY: + try: -+ scope_stack = nemo_flow.get_scope_stack() ++ scope_stack = nemo_relay.get_scope_stack() + + def _run_with_scope_stack() -> Any: -+ nemo_flow.set_thread_scope_stack(scope_stack) ++ nemo_relay.set_thread_scope_stack(scope_stack) + return asyncio.run(coro) + + with ThreadPoolExecutor(max_workers=1) as pool: @@ -1030,14 +1030,14 @@ index 0000000000..66644f74ad + request: "LLMRequest", + func: Callable[..., Any], +) -> Any: -+ """Execute a non-streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.execute( ++ """Execute a non-streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.execute( + model_name, + request, + func, + model_name=model_name, -+ codec=nemo_flow.codecs.AnthropicMessagesCodec(), -+ response_codec=nemo_flow.codecs.AnthropicMessagesCodec(), ++ codec=nemo_relay.codecs.AnthropicMessagesCodec(), ++ response_codec=nemo_relay.codecs.AnthropicMessagesCodec(), + ) + + @@ -1048,35 +1048,35 @@ index 0000000000..66644f74ad + collector: Callable[[Any], None], + finalizer: Callable[[], Any], +) -> Any: -+ """Execute a streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.stream_execute( ++ """Execute a streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.stream_execute( + model_name, + request, + func, + collector, + finalizer, + model_name=model_name, -+ codec=nemo_flow.codecs.AnthropicMessagesCodec(), -+ response_codec=nemo_flow.codecs.AnthropicMessagesCodec(), ++ codec=nemo_relay.codecs.AnthropicMessagesCodec(), ++ response_codec=nemo_relay.codecs.AnthropicMessagesCodec(), + ) -diff --git a/libs/partners/openai/langchain_openai/chat_models/_nemo_flow.py b/libs/partners/openai/langchain_openai/chat_models/_nemo_flow.py +diff --git a/libs/partners/openai/langchain_openai/chat_models/_nemo_relay.py b/libs/partners/openai/langchain_openai/chat_models/_nemo_relay.py new file mode 100644 index 0000000000..58cdfb6d18 --- /dev/null -+++ b/libs/partners/openai/langchain_openai/chat_models/_nemo_flow.py ++++ b/libs/partners/openai/langchain_openai/chat_models/_nemo_relay.py @@ -0,0 +1,105 @@ -+"""Thin bridge module for optional NeMo Flow integration. ++"""Thin bridge module for optional NeMo Relay integration. + -+When nemo_flow is installed and a scope stack has been initialized by the ++When nemo_relay is installed and a scope stack has been initialized by the +caller, the helpers in this module route LLM calls through the full -+NeMo Flow middleware pipeline (guardrails, intercepts, execution intercepts). -+If nemo_flow is not installed or no scope stack is active, ``available()`` ++NeMo Relay middleware pipeline (guardrails, intercepts, execution intercepts). ++If nemo_relay is not installed or no scope stack is active, ``available()`` +returns ``False`` and ChatOpenAI falls back to its vanilla code path. + -+LLM calls use the standard NeMo Flow API (``nemo_flow.llm.execute`` / -+``nemo_flow.llm.stream_execute``) with -+``codec=nemo_flow.codecs.OpenAIChatCodec()`` and -+``response_codec=nemo_flow.codecs.OpenAIChatCodec()`` to get structured ++LLM calls use the standard NeMo Relay API (``nemo_relay.llm.execute`` / ++``nemo_relay.llm.stream_execute``) with ++``codec=nemo_relay.codecs.OpenAIChatCodec()`` and ++``response_codec=nemo_relay.codecs.OpenAIChatCodec()`` to get structured +``AnnotatedLLMRequest`` / ``AnnotatedLLMResponse`` on LLM start/end events via +the built-in OpenAI Chat codec. +""" @@ -1088,22 +1088,22 @@ index 0000000000..58cdfb6d18 +from typing import Any, Callable + +try: -+ import nemo_flow -+ from nemo_flow import LLMRequest ++ import nemo_relay ++ from nemo_relay import LLMRequest + -+ _HAS_NEMO_FLOW = True ++ _HAS_NEMO_RELAY = True +except ImportError: -+ _HAS_NEMO_FLOW = False ++ _HAS_NEMO_RELAY = False + + +def available() -> bool: -+ """Return True when nemo_flow is importable *and* a scope stack is active.""" -+ if not _HAS_NEMO_FLOW: ++ """Return True when nemo_relay is importable *and* a scope stack is active.""" ++ if not _HAS_NEMO_RELAY: + return False + try: -+ # Only consider nemo_flow available if the caller has explicitly ++ # Only consider nemo_relay available if the caller has explicitly + # initialised a scope stack (we don't want to auto-create one). -+ return nemo_flow.scope_stack_active() ++ return nemo_relay.scope_stack_active() + except Exception: + return False + @@ -1141,14 +1141,14 @@ index 0000000000..58cdfb6d18 + request: "LLMRequest", + func: Callable[..., Any], +) -> Any: -+ """Execute a non-streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.execute( ++ """Execute a non-streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.execute( + model_name, + request, + func, + model_name=model_name, -+ codec=nemo_flow.codecs.OpenAIChatCodec(), -+ response_codec=nemo_flow.codecs.OpenAIChatCodec(), ++ codec=nemo_relay.codecs.OpenAIChatCodec(), ++ response_codec=nemo_relay.codecs.OpenAIChatCodec(), + ) + + @@ -1159,14 +1159,14 @@ index 0000000000..58cdfb6d18 + collector: Callable[[Any], None], + finalizer: Callable[[], Any], +) -> Any: -+ """Execute a streaming LLM call through the NeMo Flow pipeline.""" -+ return await nemo_flow.llm.stream_execute( ++ """Execute a streaming LLM call through the NeMo Relay pipeline.""" ++ return await nemo_relay.llm.stream_execute( + model_name, + request, + func, + collector, + finalizer, + model_name=model_name, -+ codec=nemo_flow.codecs.OpenAIChatCodec(), -+ response_codec=nemo_flow.codecs.OpenAIChatCodec(), ++ codec=nemo_relay.codecs.OpenAIChatCodec(), ++ response_codec=nemo_relay.codecs.OpenAIChatCodec(), + ) diff --git a/patches/langgraph/0001-add-nemo-flow-integration.patch b/patches/langgraph/0001-add-nemo-relay-integration.patch similarity index 86% rename from patches/langgraph/0001-add-nemo-flow-integration.patch rename to patches/langgraph/0001-add-nemo-relay-integration.patch index ee02c43bb..718212fd9 100644 --- a/patches/langgraph/0001-add-nemo-flow-integration.patch +++ b/patches/langgraph/0001-add-nemo-relay-integration.patch @@ -1,43 +1,43 @@ -diff --git a/libs/langgraph/langgraph/_nemo_flow.py b/libs/langgraph/langgraph/_nemo_flow.py +diff --git a/libs/langgraph/langgraph/_nemo_relay.py b/libs/langgraph/langgraph/_nemo_relay.py new file mode 100644 index 00000000..ad15faba --- /dev/null -+++ b/libs/langgraph/langgraph/_nemo_flow.py ++++ b/libs/langgraph/langgraph/_nemo_relay.py @@ -0,0 +1,456 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + -+"""Optional NeMo Flow integration guard and scope helpers for LangGraph. ++"""Optional NeMo Relay integration guard and scope helpers for LangGraph. + -+When ``nemo_flow`` is installed and a scope stack has been initialized, ++When ``nemo_relay`` is installed and a scope stack has been initialized, +``available()`` returns ``True`` and instrumentation hooks in patched -+LangGraph modules can safely call NeMo Flow APIs. When ``nemo_flow`` is not ++LangGraph modules can safely call NeMo Relay APIs. When ``nemo_relay`` is not +installed, ``available()`` returns ``False`` and all instrumentation is +silently skipped -- LangGraph behaves identically to an unpatched build. + +This module follows the same pattern as -+``langchain_nvidia_ai_endpoints/_nemo_flow.py`` and -+``langchain_openai/chat_models/_nemo_flow.py``. ++``langchain_nvidia_ai_endpoints/_nemo_relay.py`` and ++``langchain_openai/chat_models/_nemo_relay.py``. + +Scope helpers +------------- +``push_graph_scope`` / ``pop_graph_scope`` -+ Manage the graph-level NeMo Flow scope in ``Pregel.stream()`` / ``astream()``. ++ Manage the graph-level NeMo Relay scope in ``Pregel.stream()`` / ``astream()``. +``push_subgraph_scope`` / ``pop_subgraph_scope`` + Manage subgraph-level scopes with ContextVar save/restore for correct + nesting when a graph is invoked as a subgraph within another graph. +``push_node_scope`` / ``pop_node_scope`` -+ Manage per-node NeMo Flow scopes with isolated scope stacks for parallel ++ Manage per-node NeMo Relay scopes with isolated scope stacks for parallel + branch safety in ``run_with_retry()`` / ``arun_with_retry()``. +``push_graph_scope`` (optional ``graph_topology`` kwarg) + Store graph topology as named metadata on the graph scope. + +Double-wrap prevention +---------------------- -+``_langgraph_nemo_flow_active`` is a ``ContextVar[bool]`` set to ``True`` while ++``_langgraph_nemo_relay_active`` is a ``ContextVar[bool]`` set to ``True`` while +the LangGraph patch is actively managing scopes. External consumers (e.g. -+``NemoFlowCallbackHandler.on_chain_start`` in the langchain patch) should -+call ``langgraph_nemo_flow_active()`` and skip their own scope push when it ++``NemoRelayCallbackHandler.on_chain_start`` in the langchain patch) should ++call ``langgraph_nemo_relay_active()`` and skip their own scope push when it +returns ``True``. + +Lifecycle events @@ -61,21 +61,21 @@ index 00000000..ad15faba +_logger = logging.getLogger(__name__) + +try: -+ import nemo_flow ++ import nemo_relay + -+ _HAS_NEMO_FLOW = True ++ _HAS_NEMO_RELAY = True +except ImportError: # pragma: no cover -+ nemo_flow = None # type: ignore[assignment] -+ _HAS_NEMO_FLOW = False ++ nemo_relay = None # type: ignore[assignment] ++ _HAS_NEMO_RELAY = False + +# --------------------------------------------------------------------------- +# ContextVars for cross-module coordination +# --------------------------------------------------------------------------- + +# Flag: True when the LangGraph patch is managing scopes -- tells -+# NemoFlowCallbackHandler.on_chain_start to skip its own scope push. -+_langgraph_nemo_flow_active: contextvars.ContextVar[bool] = contextvars.ContextVar( -+ "_langgraph_nemo_flow_active", default=False ++# NemoRelayCallbackHandler.on_chain_start to skip its own scope push. ++_langgraph_nemo_relay_active: contextvars.ContextVar[bool] = contextvars.ContextVar( ++ "_langgraph_nemo_relay_active", default=False +) + + @@ -100,28 +100,28 @@ index 00000000..ad15faba + + +def available() -> bool: -+ """Return True when nemo_flow is importable *and* a scope stack is active. ++ """Return True when nemo_relay is importable *and* a scope stack is active. + + This two-part check ensures instrumentation only fires when the caller -+ has explicitly created a NeMo Flow scope stack. A bare ``import nemo_flow`` ++ has explicitly created a NeMo Relay scope stack. A bare ``import nemo_relay`` + is not sufficient -- the scope stack must be active. + """ -+ if not _HAS_NEMO_FLOW: ++ if not _HAS_NEMO_RELAY: + return False + try: -+ return nemo_flow.scope_stack_active() ++ return nemo_relay.scope_stack_active() + except Exception: + return False + + -+def langgraph_nemo_flow_active() -> bool: ++def langgraph_nemo_relay_active() -> bool: + """Return True when LangGraph patch is actively managing scopes. + -+ External consumers (e.g. ``NemoFlowCallbackHandler``) should call this ++ External consumers (e.g. ``NemoRelayCallbackHandler``) should call this + and skip their own scope push/pop when it returns ``True`` to avoid + double-wrapping. + """ -+ return _langgraph_nemo_flow_active.get(False) ++ return _langgraph_nemo_relay_active.get(False) + + +def get_graph_response_codec() -> object | None: @@ -148,7 +148,7 @@ index 00000000..ad15faba + response_codec: object | None = None, + graph_topology: dict | None = None, +) -> Any: -+ """Push a graph-level NeMo Flow scope and set coordination ContextVars. ++ """Push a graph-level NeMo Relay scope and set coordination ContextVars. + + Must only be called after ``available()`` returns ``True``. + @@ -165,12 +165,12 @@ index 00000000..ad15faba + metadata: dict[str, Any] = {"langgraph.graph": True} + if graph_topology is not None: + metadata["graph_topology"] = graph_topology -+ handle = nemo_flow.scope.push( ++ handle = nemo_relay.scope.push( + graph_name, -+ nemo_flow.ScopeType.Agent, ++ nemo_relay.ScopeType.Agent, + metadata=metadata, + ) -+ _langgraph_nemo_flow_active.set(True) ++ _langgraph_nemo_relay_active.set(True) + _graph_scope_info.set( + _GraphScopeInfo(graph_name=graph_name, metadata=metadata, response_codec=response_codec) + ) @@ -178,12 +178,12 @@ index 00000000..ad15faba + + +def pop_graph_scope(handle: Any) -> None: -+ """Pop a graph-level NeMo Flow scope and reset coordination ContextVars. ++ """Pop a graph-level NeMo Relay scope and reset coordination ContextVars. + + Must only be called after ``available()`` returns ``True``. + """ -+ nemo_flow.scope.pop(handle) -+ _langgraph_nemo_flow_active.set(False) ++ nemo_relay.scope.pop(handle) ++ _langgraph_nemo_relay_active.set(False) + _graph_scope_info.set(None) + + @@ -195,7 +195,7 @@ index 00000000..ad15faba +def push_node_scope( + task_name: str, task_id: str +) -> tuple[Any, Any | None, Any | None]: -+ """Push a node-level NeMo Flow scope on an isolated per-branch scope stack. ++ """Push a node-level NeMo Relay scope on an isolated per-branch scope stack. + + Creates a new scope stack for this parallel branch, sets it in the + Python ContextVar (so ``_ensure_scope_stack`` re-syncs it to the Rust @@ -209,25 +209,25 @@ index 00000000..ad15faba + """ + # Create a fresh scope stack for this parallel branch and install it + # in the ContextVar. The Token lets us restore the parent on pop. -+ branch_stack = nemo_flow.create_scope_stack() -+ saved_token = nemo_flow._scope_stack_var.set(branch_stack) ++ branch_stack = nemo_relay.create_scope_stack() ++ saved_token = nemo_relay._scope_stack_var.set(branch_stack) + # Sync the new branch stack to the Rust thread-local immediately -+ nemo_flow.set_thread_scope_stack(branch_stack) ++ nemo_relay.set_thread_scope_stack(branch_stack) + + # Push the graph-level scope on the branch stack (mirrors the parent) + info = _graph_scope_info.get(None) + graph_name = info.graph_name if info else "graph" + graph_metadata = info.metadata if info else {"langgraph.graph": True} -+ graph_handle = nemo_flow.scope.push( ++ graph_handle = nemo_relay.scope.push( + graph_name, -+ nemo_flow.ScopeType.Agent, ++ nemo_relay.ScopeType.Agent, + metadata=graph_metadata, + ) + + # Push the node scope as a child of the branch graph scope -+ node_handle = nemo_flow.scope.push( ++ node_handle = nemo_relay.scope.push( + task_name, -+ nemo_flow.ScopeType.Agent, ++ nemo_relay.ScopeType.Agent, + metadata={"langgraph.node": True, "langgraph.task_id": task_id}, + ) + return node_handle, graph_handle, saved_token @@ -238,11 +238,11 @@ index 00000000..ad15faba + + Must only be called after ``available()`` returns ``True``. + """ -+ nemo_flow.scope.pop(node_handle) ++ nemo_relay.scope.pop(node_handle) + if graph_handle is not None: -+ nemo_flow.scope.pop(graph_handle) ++ nemo_relay.scope.pop(graph_handle) + if saved_token is not None: -+ nemo_flow._scope_stack_var.reset(saved_token) ++ nemo_relay._scope_stack_var.reset(saved_token) + + +# --------------------------------------------------------------------------- @@ -268,7 +268,7 @@ index 00000000..ad15faba + used by ``pop_subgraph_scope`` to restore parent ContextVar values. + """ + # Save previous ContextVar values for restoration after subgraph completes -+ active_token = _langgraph_nemo_flow_active.set(True) ++ active_token = _langgraph_nemo_relay_active.set(True) + info_token = _graph_scope_info.set( + _GraphScopeInfo( + graph_name=graph_name, @@ -276,9 +276,9 @@ index 00000000..ad15faba + response_codec=response_codec, + ) + ) -+ handle = nemo_flow.scope.push( ++ handle = nemo_relay.scope.push( + graph_name, -+ nemo_flow.ScopeType.Agent, ++ nemo_relay.ScopeType.Agent, + metadata={"langgraph.graph": True, "langgraph.subgraph": True}, + ) + return handle, active_token, info_token @@ -295,8 +295,8 @@ index 00000000..ad15faba + this restores the previous values so the parent graph continues + correctly after the subgraph completes. + """ -+ nemo_flow.scope.pop(handle) -+ _langgraph_nemo_flow_active.reset(active_token) ++ nemo_relay.scope.pop(handle) ++ _langgraph_nemo_relay_active.reset(active_token) + _graph_scope_info.reset(info_token) + + @@ -308,14 +308,14 @@ index 00000000..ad15faba +def emit_checkpoint_save( + source: str, step: int, thread_id: str | None, checkpoint_id: str +) -> None: -+ """Emit a 'Checkpoint Save' NeMo Flow event. ++ """Emit a 'Checkpoint Save' NeMo Relay event. + + Called from _put_checkpoint() when a checkpoint is actually persisted. + The ``source`` field distinguishes input/loop/exit checkpoints (D-02). + """ + if not available(): + return -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Checkpoint Save", + data={ + "source": source, @@ -329,14 +329,14 @@ index 00000000..ad15faba +def emit_checkpoint_restore( + checkpoint_id: str, thread_id: str | None, step: int +) -> None: -+ """Emit a 'Checkpoint Restore' NeMo Flow event. ++ """Emit a 'Checkpoint Restore' NeMo Relay event. + + Called from __enter__/__aenter__ when a real checkpoint is loaded + (not on first run with empty checkpoint). + """ + if not available(): + return -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Checkpoint Restore", + data={ + "checkpoint_id": checkpoint_id, @@ -349,7 +349,7 @@ index 00000000..ad15faba +def emit_graph_interrupt( + trigger: str, interrupts: list, +) -> None: -+ """Emit a 'Graph Interrupt' NeMo Flow event. ++ """Emit a 'Graph Interrupt' NeMo Relay event. + + Called just before ``raise GraphInterrupt()`` in tick() or after_tick(). + ``trigger`` is ``"before"`` or ``"after"`` (D-07). @@ -364,7 +364,7 @@ index 00000000..ad15faba + serialized.append({"value": str(intr.value), "id": getattr(intr, "id", None)}) + except Exception: + serialized.append({"value": "", "id": None}) -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Graph Interrupt", + data={ + "trigger": trigger, @@ -374,7 +374,7 @@ index 00000000..ad15faba + + +def emit_graph_resume(resume_values: object) -> None: -+ """Emit a 'Graph Resume' NeMo Flow event. ++ """Emit a 'Graph Resume' NeMo Relay event. + + Called in _first() when Command(resume=...) is detected. + Fires after checkpoint restoration but before node execution (D-09). @@ -386,7 +386,7 @@ index 00000000..ad15faba + serialized = str(resume_values) + except Exception: + serialized = "" -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Graph Resume", + data={ + "resume_values": serialized, @@ -400,7 +400,7 @@ index 00000000..ad15faba + + +def emit_edge_write(source_node: str, channels: list, write_count: int) -> None: -+ """Emit an 'Edge Write' NeMo Flow event when ChannelWrite._write/_awrite fires. ++ """Emit an 'Edge Write' NeMo Relay event when ChannelWrite._write/_awrite fires. + + Called from _write() and _awrite() after the writes list is built and + before self.do_write() is called. Fires within the active node scope @@ -415,7 +415,7 @@ index 00000000..ad15faba + """ + if not available(): + return -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Edge Write", + data={ + "source_node": source_node, @@ -426,7 +426,7 @@ index 00000000..ad15faba + + +def emit_superstep_start(step: int, task_count: int) -> None: -+ """Emit a 'Superstep Start' NeMo Flow event at the beginning of a Pregel superstep. ++ """Emit a 'Superstep Start' NeMo Relay event at the beginning of a Pregel superstep. + + Called from tick() just before returning True (after all early returns for + out_of_steps, done, and interrupt_before). At this point self.tasks is populated @@ -437,14 +437,14 @@ index 00000000..ad15faba + """ + if not available(): + return -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Superstep Start", + data={"step": step, "task_count": task_count}, + ) + + +def emit_superstep_end(step: int, task_count: int) -> None: -+ """Emit a 'Superstep End' NeMo Flow event after a Pregel superstep completes. ++ """Emit a 'Superstep End' NeMo Relay event after a Pregel superstep completes. + + Called from after_tick() immediately after apply_writes() returns and before + _put_checkpoint() (which increments self.step). At this point all task writes @@ -455,7 +455,7 @@ index 00000000..ad15faba + """ + if not available(): + return -+ nemo_flow.scope.event( ++ nemo_relay.scope.event( + "Superstep End", + data={"step": step, "task_count": task_count}, + ) @@ -468,8 +468,8 @@ index 4f9c55d2..cabe5d3d 100644 if self.interrupt_before and should_interrupt( self.checkpoint, self.interrupt_before, self.tasks.values() ): -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_graph_interrupt( ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_graph_interrupt( + trigger="before", + interrupts=[], + ) @@ -480,8 +480,8 @@ index 4f9c55d2..cabe5d3d 100644 if task.writes: self.output_writes(task.id, task.writes, cached=True) -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_superstep_start(step=self.step, task_count=len(self.tasks)) ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_superstep_start(step=self.step, task_count=len(self.tasks)) + return True @@ -490,8 +490,8 @@ index 4f9c55d2..cabe5d3d 100644 self.checkpointer_get_next_version, self.trigger_to_nodes, ) -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_superstep_end(step=self.step, task_count=len(self.tasks)) ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_superstep_end(step=self.step, task_count=len(self.tasks)) # produce values output if not self.updated_channels.isdisjoint( (self.output_keys,) @@ -499,7 +499,7 @@ index 4f9c55d2..cabe5d3d 100644 if self.interrupt_after and should_interrupt( self.checkpoint, self.interrupt_after, self.tasks.values() ): -+ from langgraph import _nemo_flow ++ from langgraph import _nemo_relay + # Collect interrupt payloads from task writes (Pitfall 5) + _interrupts = [] + try: @@ -509,7 +509,7 @@ index 4f9c55d2..cabe5d3d 100644 + ] + except Exception: + pass -+ _nemo_flow.emit_graph_interrupt( ++ _nemo_relay.emit_graph_interrupt( + trigger="after", + interrupts=_interrupts, + ) @@ -520,8 +520,8 @@ index 4f9c55d2..cabe5d3d 100644 "Docs: https://docs.langchain.com/oss/python/langgraph/add-human-in-the-loop#resume-multiple-interrupts-with-one-invocation." ) -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_graph_resume(resume_values=resume) ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_graph_resume(resume_values=resume) + writes: defaultdict[str, list[tuple[str, Any]]] = defaultdict(list) # group writes by task ID @@ -530,8 +530,8 @@ index 4f9c55d2..cabe5d3d 100644 # bail if no checkpointer if do_checkpoint and self._checkpointer_put_after_previous is not None: -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_checkpoint_save( ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_checkpoint_save( + source="exit" if exiting else metadata.get("source", "unknown"), + step=metadata.get("step", self.step), + thread_id=self.config.get(CONF, {}).get(CONFIG_KEY_THREAD_ID), @@ -545,8 +545,8 @@ index 4f9c55d2..cabe5d3d 100644 self.checkpoint = saved.checkpoint self.checkpoint_metadata = saved.metadata + if saved.checkpoint.get("channel_versions"): -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_checkpoint_restore( ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_checkpoint_restore( + checkpoint_id=saved.checkpoint.get("id", ""), + thread_id=saved.config.get(CONF, {}).get(CONFIG_KEY_THREAD_ID) if saved.config else None, + step=saved.metadata.get("step", -1) if saved.metadata else -1, @@ -559,8 +559,8 @@ index 4f9c55d2..cabe5d3d 100644 self.checkpoint = saved.checkpoint self.checkpoint_metadata = saved.metadata + if saved.checkpoint.get("channel_versions"): -+ from langgraph import _nemo_flow -+ _nemo_flow.emit_checkpoint_restore( ++ from langgraph import _nemo_relay ++ _nemo_relay.emit_checkpoint_restore( + checkpoint_id=saved.checkpoint.get("id", ""), + thread_id=saved.config.get(CONF, {}).get(CONFIG_KEY_THREAD_ID) if saved.config else None, + step=saved.metadata.get("step", -1) if saved.metadata else -1, @@ -616,8 +616,8 @@ index 3c60f478..c92bccd7 100644 - exc.add_note(f"During task with name '{task.name}' and id '{task.id}'") - if not retry_policy: - raise -+ # --- NeMo Flow: node-level scope with per-branch isolation --- -+ from langgraph import _nemo_flow ++ # --- NeMo Relay: node-level scope with per-branch isolation --- ++ from langgraph import _nemo_relay - # Check which retry policy applies to this exception - matching_policy = None @@ -627,8 +627,8 @@ index 3c60f478..c92bccd7 100644 + _node_handle = None + _branch_graph_handle = None + _saved_stack = None -+ if _nemo_flow.available(): -+ _node_handle, _branch_graph_handle, _saved_stack = _nemo_flow.push_node_scope( ++ if _nemo_relay.available(): ++ _node_handle, _branch_graph_handle, _saved_stack = _nemo_relay.push_node_scope( + task.name, task.id + ) + try: @@ -737,7 +737,7 @@ index 3c60f478..c92bccd7 100644 + config = patch_configurable(config, {CONFIG_KEY_RESUMING: True}) + finally: + if _node_handle is not None: -+ _nemo_flow.pop_node_scope(_node_handle, _branch_graph_handle, _saved_stack) ++ _nemo_relay.pop_node_scope(_node_handle, _branch_graph_handle, _saved_stack) async def arun_with_retry( @@ -791,8 +791,8 @@ index 3c60f478..c92bccd7 100644 - exc.add_note(f"During task with name '{task.name}' and id '{task.id}'") - if not retry_policy: - raise -+ # --- NeMo Flow: node-level scope with per-branch isolation --- -+ from langgraph import _nemo_flow ++ # --- NeMo Relay: node-level scope with per-branch isolation --- ++ from langgraph import _nemo_relay - # Check which retry policy applies to this exception - matching_policy = None @@ -802,8 +802,8 @@ index 3c60f478..c92bccd7 100644 + _node_handle = None + _branch_graph_handle = None + _saved_stack = None -+ if _nemo_flow.available(): -+ _node_handle, _branch_graph_handle, _saved_stack = _nemo_flow.push_node_scope( ++ if _nemo_relay.available(): ++ _node_handle, _branch_graph_handle, _saved_stack = _nemo_relay.push_node_scope( + task.name, task.id + ) + try: @@ -920,7 +920,7 @@ index 3c60f478..c92bccd7 100644 + config = patch_configurable(config, {CONFIG_KEY_RESUMING: True}) + finally: + if _node_handle is not None: -+ _nemo_flow.pop_node_scope(_node_handle, _branch_graph_handle, _saved_stack) ++ _nemo_relay.pop_node_scope(_node_handle, _branch_graph_handle, _saved_stack) def _should_retry_on(retry_policy: RetryPolicy, exc: Exception) -> bool: @@ -941,8 +941,8 @@ index 8b450825..01201606 100644 else write for write in self.writes ] -+ from langgraph import _nemo_flow -+ if _nemo_flow.available(): ++ from langgraph import _nemo_relay ++ if _nemo_relay.available(): + ns = config.get(CONF, {}).get(CONFIG_KEY_CHECKPOINT_NS, "") + source_node = ns.split(":")[0].split("|")[-1] if ns else "unknown" + channels = [ @@ -951,7 +951,7 @@ index 8b450825..01201606 100644 + else "..." + for w in writes + ] -+ _nemo_flow.emit_edge_write( ++ _nemo_relay.emit_edge_write( + source_node=source_node, + channels=channels, + write_count=len(writes), @@ -963,8 +963,8 @@ index 8b450825..01201606 100644 else write for write in self.writes ] -+ from langgraph import _nemo_flow -+ if _nemo_flow.available(): ++ from langgraph import _nemo_relay ++ if _nemo_relay.available(): + ns = config.get(CONF, {}).get(CONFIG_KEY_CHECKPOINT_NS, "") + source_node = ns.split(":")[0].split("|")[-1] if ns else "unknown" + channels = [ @@ -973,7 +973,7 @@ index 8b450825..01201606 100644 + else "..." + for w in writes + ] -+ _nemo_flow.emit_edge_write( ++ _nemo_relay.emit_edge_write( + source_node=source_node, + channels=channels, + write_count=len(writes), @@ -989,14 +989,14 @@ index 8de321b8..64c0fd7f 100644 stream = SyncQueue() -+ # --- NeMo Flow: graph-level scope --- -+ from langgraph import _nemo_flow ++ # --- NeMo Relay: graph-level scope --- ++ from langgraph import _nemo_relay + from langgraph._internal._constants import CONFIG_KEY_TASK_ID, CONF + + _graph_handle = None + _subgraph_tokens = None # (active_token, info_token) if subgraph -+ if _nemo_flow.available(): -+ import nemo_flow ++ if _nemo_relay.available(): ++ import nemo_relay + + graph_name = (config or {}).get("run_name") or self.get_name() + is_subgraph = ( @@ -1005,7 +1005,7 @@ index 8de321b8..64c0fd7f 100644 + ) + if is_subgraph: + _graph_handle, _active_tok, _info_tok = ( -+ _nemo_flow.push_subgraph_scope(graph_name) ++ _nemo_relay.push_subgraph_scope(graph_name) + ) + _subgraph_tokens = (_active_tok, _info_tok) + else: @@ -1015,7 +1015,7 @@ index 8de321b8..64c0fd7f 100644 + _topo = self.get_graph().to_json() + except Exception: + pass -+ _graph_handle = _nemo_flow.push_graph_scope( ++ _graph_handle = _nemo_relay.push_graph_scope( + graph_name, graph_topology=_topo + ) + @@ -1029,11 +1029,11 @@ index 8de321b8..64c0fd7f 100644 + finally: + if _graph_handle is not None: + if _subgraph_tokens is not None: -+ _nemo_flow.pop_subgraph_scope( ++ _nemo_relay.pop_subgraph_scope( + _graph_handle, _subgraph_tokens[0], _subgraph_tokens[1] + ) + else: -+ _nemo_flow.pop_graph_scope(_graph_handle) ++ _nemo_relay.pop_graph_scope(_graph_handle) @overload def astream( @@ -1041,14 +1041,14 @@ index 8de321b8..64c0fd7f 100644 partial(aioloop.call_soon_threadsafe, stream.put_nowait), ) -+ # --- NeMo Flow: graph-level scope --- -+ from langgraph import _nemo_flow ++ # --- NeMo Relay: graph-level scope --- ++ from langgraph import _nemo_relay + from langgraph._internal._constants import CONFIG_KEY_TASK_ID, CONF + + _graph_handle = None + _subgraph_tokens = None # (active_token, info_token) if subgraph -+ if _nemo_flow.available(): -+ import nemo_flow ++ if _nemo_relay.available(): ++ import nemo_relay + + graph_name = (config or {}).get("run_name") or self.get_name() + is_subgraph = ( @@ -1057,7 +1057,7 @@ index 8de321b8..64c0fd7f 100644 + ) + if is_subgraph: + _graph_handle, _active_tok, _info_tok = ( -+ _nemo_flow.push_subgraph_scope(graph_name) ++ _nemo_relay.push_subgraph_scope(graph_name) + ) + _subgraph_tokens = (_active_tok, _info_tok) + else: @@ -1067,7 +1067,7 @@ index 8de321b8..64c0fd7f 100644 + _topo = self.get_graph().to_json() + except Exception: + pass -+ _graph_handle = _nemo_flow.push_graph_scope( ++ _graph_handle = _nemo_relay.push_graph_scope( + graph_name, graph_topology=_topo + ) + @@ -1081,11 +1081,11 @@ index 8de321b8..64c0fd7f 100644 + finally: + if _graph_handle is not None: + if _subgraph_tokens is not None: -+ _nemo_flow.pop_subgraph_scope( ++ _nemo_relay.pop_subgraph_scope( + _graph_handle, _subgraph_tokens[0], _subgraph_tokens[1] + ) + else: -+ _nemo_flow.pop_graph_scope(_graph_handle) ++ _nemo_relay.pop_graph_scope(_graph_handle) @overload def invoke( diff --git a/patches/openclaw/0001-add-nemo-flow-integration.patch b/patches/openclaw/0001-add-nemo-relay-integration.patch similarity index 91% rename from patches/openclaw/0001-add-nemo-flow-integration.patch rename to patches/openclaw/0001-add-nemo-relay-integration.patch index 7d9f6c610..ea54de2c4 100644 --- a/patches/openclaw/0001-add-nemo-flow-integration.patch +++ b/patches/openclaw/0001-add-nemo-relay-integration.patch @@ -1,17 +1,17 @@ -diff --git a/extensions/nemo-flow/README.md b/extensions/nemo-flow/README.md +diff --git a/extensions/nemo-relay/README.md b/extensions/nemo-relay/README.md new file mode 100644 index 00000000..5fbc09d9 --- /dev/null -+++ b/extensions/nemo-flow/README.md ++++ b/extensions/nemo-relay/README.md @@ -0,0 +1,42 @@ -+# NeMo Flow ++# NeMo Relay + -+OpenClaw plugin for NeMo Flow plugin-host initialization and execution wrapping. ++OpenClaw plugin for NeMo Relay plugin-host initialization and execution wrapping. + +## Install + +```bash -+openclaw plugins add @openclaw/nemo-flow ++openclaw plugins add @openclaw/nemo-relay +``` + +## Config @@ -20,7 +20,7 @@ index 00000000..5fbc09d9 +{ + "plugins": { + "entries": { -+ "nemo-flow": { ++ "nemo-relay": { + "enabled": true, + "config": { + "version": 1, @@ -45,26 +45,26 @@ index 00000000..5fbc09d9 + +## Local Dev + -+To test against a local checkout of `nemo-flow-node`, build the Node package first and then override the dependency to the local path from the OpenClaw workspace. -diff --git a/extensions/nemo-flow/index.ts b/extensions/nemo-flow/index.ts ++To test against a local checkout of `nemo-relay-node`, build the Node package first and then override the dependency to the local path from the OpenClaw workspace. +diff --git a/extensions/nemo-relay/index.ts b/extensions/nemo-relay/index.ts new file mode 100644 index 00000000..77ae6b4d --- /dev/null -+++ b/extensions/nemo-flow/index.ts ++++ b/extensions/nemo-relay/index.ts @@ -0,0 +1,92 @@ +import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -+import { NEMO_FLOW_PLUGIN_CONFIG_JSON_SCHEMA, resolveNemoFlowPluginConfig } from "./src/config.js"; ++import { NEMO_RELAY_PLUGIN_CONFIG_JSON_SCHEMA, resolveNemoRelayPluginConfig } from "./src/config.js"; +import { -+ executeToolWithNemoFlow, -+ initializeNemoFlowGateway, -+ shutdownNemoFlowGateway, -+ wrapStreamFnWithNemoFlow, ++ executeToolWithNemoRelay, ++ initializeNemoRelayGateway, ++ shutdownNemoRelayGateway, ++ wrapStreamFnWithNemoRelay, +} from "./src/runtime.js"; + -+const nemoFlowConfigSchema = { ++const nemoRelayConfigSchema = { + safeParse(value: unknown) { + try { -+ return { success: true, data: resolveNemoFlowPluginConfig(value) }; ++ return { success: true, data: resolveNemoRelayPluginConfig(value) }; + } catch (error) { + return { + success: false, @@ -74,38 +74,38 @@ index 00000000..77ae6b4d + }; + } + }, -+ jsonSchema: NEMO_FLOW_PLUGIN_CONFIG_JSON_SCHEMA, ++ jsonSchema: NEMO_RELAY_PLUGIN_CONFIG_JSON_SCHEMA, + uiHints: { + components: { + label: "Components", -+ help: "NeMo Flow plugin-host components to activate.", ++ help: "NeMo Relay plugin-host components to activate.", + }, + policy: { + label: "Policy", -+ help: "Optional NeMo Flow plugin-host validation policy.", ++ help: "Optional NeMo Relay plugin-host validation policy.", + advanced: true, + }, + }, +}; + +export default definePluginEntry({ -+ id: "nemo-flow", -+ name: "NeMo Flow", -+ description: "Tool and streaming LLM execution wrapping through NeMo Flow plugins.", -+ configSchema: nemoFlowConfigSchema, ++ id: "nemo-relay", ++ name: "NeMo Relay", ++ description: "Tool and streaming LLM execution wrapping through NeMo Relay plugins.", ++ configSchema: nemoRelayConfigSchema, + register(api: OpenClawPluginApi) { -+ const config = resolveNemoFlowPluginConfig(api.pluginConfig); ++ const config = resolveNemoRelayPluginConfig(api.pluginConfig); + + api.registerService({ -+ id: "nemo-flow-runtime", ++ id: "nemo-relay-runtime", + async start() { -+ await initializeNemoFlowGateway({ ++ await initializeNemoRelayGateway({ + logger: api.logger, + config, + }); + }, + async stop() { -+ await shutdownNemoFlowGateway({ ++ await shutdownNemoRelayGateway({ + logger: api.logger, + }); + }, @@ -113,7 +113,7 @@ index 00000000..77ae6b4d + + api.registerAgentStreamingLlmMiddleware( + (ctx) => -+ wrapStreamFnWithNemoFlow({ ++ wrapStreamFnWithNemoRelay({ + logger: api.logger, + config, + provider: ctx.provider, @@ -129,7 +129,7 @@ index 00000000..77ae6b4d + + api.registerAgentToolCallMiddleware( + async (ctx) => -+ await executeToolWithNemoFlow({ ++ await executeToolWithNemoRelay({ + logger: api.logger, + config, + toolName: ctx.toolName, @@ -144,16 +144,16 @@ index 00000000..77ae6b4d + ); + }, +}); -diff --git a/extensions/nemo-flow/openclaw.plugin.json b/extensions/nemo-flow/openclaw.plugin.json +diff --git a/extensions/nemo-relay/openclaw.plugin.json b/extensions/nemo-relay/openclaw.plugin.json new file mode 100644 index 00000000..620bdef1 --- /dev/null -+++ b/extensions/nemo-flow/openclaw.plugin.json ++++ b/extensions/nemo-relay/openclaw.plugin.json @@ -0,0 +1,70 @@ +{ -+ "id": "nemo-flow", -+ "name": "NeMo Flow", -+ "description": "NeMo Flow plugin-host initialization and execution wrapping for OpenClaw.", ++ "id": "nemo-relay", ++ "name": "NeMo Relay", ++ "description": "NeMo Relay plugin-host initialization and execution wrapping for OpenClaw.", + "contracts": { + "agentStreamingLlmMiddleware": ["pi"], + "agentToolCallMiddleware": ["pi"] @@ -211,28 +211,28 @@ index 00000000..620bdef1 + "uiHints": { + "components": { + "label": "Components", -+ "help": "NeMo Flow plugin-host components to activate." ++ "help": "NeMo Relay plugin-host components to activate." + }, + "policy": { + "label": "Policy", -+ "help": "Optional NeMo Flow plugin-host validation policy.", ++ "help": "Optional NeMo Relay plugin-host validation policy.", + "advanced": true + } + } +} -diff --git a/extensions/nemo-flow/package.json b/extensions/nemo-flow/package.json +diff --git a/extensions/nemo-relay/package.json b/extensions/nemo-relay/package.json new file mode 100644 index 00000000..a322441f --- /dev/null -+++ b/extensions/nemo-flow/package.json ++++ b/extensions/nemo-relay/package.json @@ -0,0 +1,22 @@ +{ -+ "name": "@openclaw/nemo-flow", ++ "name": "@openclaw/nemo-relay", + "version": "2026.3.14", -+ "description": "OpenClaw NeMo Flow plugin-host and execution middleware integration", ++ "description": "OpenClaw NeMo Relay plugin-host and execution middleware integration", + "type": "module", + "optionalDependencies": { -+ "nemo-flow-node": "file:../../../../crates/node" ++ "nemo-relay-node": "file:../../../../crates/node" + }, + "devDependencies": { + "openclaw": "workspace:*" @@ -242,36 +242,36 @@ index 00000000..a322441f + "./index.ts" + ], + "install": { -+ "npmSpec": "@openclaw/nemo-flow", -+ "localPath": "extensions/nemo-flow", ++ "npmSpec": "@openclaw/nemo-relay", ++ "localPath": "extensions/nemo-relay", + "defaultChoice": "npm" + } + } +} -diff --git a/extensions/nemo-flow/src/config.ts b/extensions/nemo-flow/src/config.ts +diff --git a/extensions/nemo-relay/src/config.ts b/extensions/nemo-relay/src/config.ts new file mode 100644 index 00000000..c2924575 --- /dev/null -+++ b/extensions/nemo-flow/src/config.ts ++++ b/extensions/nemo-relay/src/config.ts @@ -0,0 +1,171 @@ -+export type NemoFlowPluginComponentConfig = Record; ++export type NemoRelayPluginComponentConfig = Record; + -+export type NemoFlowPluginComponent = { ++export type NemoRelayPluginComponent = { + kind: string; + enabled?: boolean; -+ config?: NemoFlowPluginComponentConfig; ++ config?: NemoRelayPluginComponentConfig; +}; + -+export type NemoFlowPluginPolicy = { ++export type NemoRelayPluginPolicy = { + unknown_component?: "ignore" | "warn" | "error"; + unknown_field?: "ignore" | "warn" | "error"; + unsupported_value?: "ignore" | "warn" | "error"; +}; + -+export type NemoFlowPluginConfig = { ++export type NemoRelayPluginConfig = { + version: 1; -+ components: NemoFlowPluginComponent[]; -+ policy?: NemoFlowPluginPolicy; ++ components: NemoRelayPluginComponent[]; ++ policy?: NemoRelayPluginPolicy; +}; + +const UNSUPPORTED_WRAPPER_FIELDS = new Set([ @@ -280,17 +280,17 @@ index 00000000..c2924575 + "capture", + "correlation", + "plugins", -+ "nemoFlow", ++ "nemoRelay", + "atif", + "telemetry", +]); + -+export const DEFAULT_NEMO_FLOW_PLUGIN_CONFIG: NemoFlowPluginConfig = { ++export const DEFAULT_NEMO_RELAY_PLUGIN_CONFIG: NemoRelayPluginConfig = { + version: 1, + components: [], +}; + -+export const NEMO_FLOW_PLUGIN_CONFIG_JSON_SCHEMA = { ++export const NEMO_RELAY_PLUGIN_CONFIG_JSON_SCHEMA = { + type: "object", + additionalProperties: false, + required: ["version", "components"], @@ -347,18 +347,18 @@ index 00000000..c2924575 + for (const key of Object.keys(record)) { + if (UNSUPPORTED_WRAPPER_FIELDS.has(key)) { + throw new Error( -+ `nemo-flow config.${key} is no longer supported; configure NeMo Flow components at the plugin config root`, ++ `nemo-relay config.${key} is no longer supported; configure NeMo Relay components at the plugin config root`, + ); + } + } +} + -+function validatePolicy(value: unknown): NemoFlowPluginPolicy | undefined { ++function validatePolicy(value: unknown): NemoRelayPluginPolicy | undefined { + if (value === undefined) { + return undefined; + } + const policy = asRecord(value, "policy"); -+ const normalized: NemoFlowPluginPolicy = {}; ++ const normalized: NemoRelayPluginPolicy = {}; + for (const key of Object.keys(policy)) { + if (key !== "unknown_component" && key !== "unknown_field" && key !== "unsupported_value") { + throw new Error(`policy.${key} is not supported`); @@ -372,7 +372,7 @@ index 00000000..c2924575 + return normalized; +} + -+function validateComponents(value: unknown): NemoFlowPluginComponent[] { ++function validateComponents(value: unknown): NemoRelayPluginComponent[] { + if (!Array.isArray(value)) { + throw new Error("components must be an array"); + } @@ -401,17 +401,17 @@ index 00000000..c2924575 + }); +} + -+export function resolveNemoFlowPluginConfig(value: unknown): NemoFlowPluginConfig { ++export function resolveNemoRelayPluginConfig(value: unknown): NemoRelayPluginConfig { + if (value === undefined || value === null) { -+ return { ...DEFAULT_NEMO_FLOW_PLUGIN_CONFIG, components: [] }; ++ return { ...DEFAULT_NEMO_RELAY_PLUGIN_CONFIG, components: [] }; + } + -+ const record = asRecord(value, "nemo-flow config"); ++ const record = asRecord(value, "nemo-relay config"); + rejectUnsupportedWrapperFields(record); + + for (const key of Object.keys(record)) { + if (key !== "version" && key !== "components" && key !== "policy") { -+ throw new Error(`nemo-flow config.${key} is not supported`); ++ throw new Error(`nemo-relay config.${key} is not supported`); + } + } + @@ -425,18 +425,18 @@ index 00000000..c2924575 + ...(record.policy !== undefined ? { policy: validatePolicy(record.policy) } : {}), + }; +} -diff --git a/extensions/nemo-flow/src/runtime.test.ts b/extensions/nemo-flow/src/runtime.test.ts +diff --git a/extensions/nemo-relay/src/runtime.test.ts b/extensions/nemo-relay/src/runtime.test.ts new file mode 100644 index 00000000..96b5555d --- /dev/null -+++ b/extensions/nemo-flow/src/runtime.test.ts ++++ b/extensions/nemo-relay/src/runtime.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, it } from "vitest"; -+import { resolveNemoFlowPluginConfig } from "./config.js"; ++import { resolveNemoRelayPluginConfig } from "./config.js"; + -+describe("nemo-flow config", () => { -+ it("defaults to an empty NeMo Flow plugin-host config", () => { -+ expect(resolveNemoFlowPluginConfig(undefined)).toEqual({ ++describe("nemo-relay config", () => { ++ it("defaults to an empty NeMo Relay plugin-host config", () => { ++ expect(resolveNemoRelayPluginConfig(undefined)).toEqual({ + version: 1, + components: [], + }); @@ -444,7 +444,7 @@ index 00000000..96b5555d + + it("accepts the hoisted plugin-host config shape", () => { + expect( -+ resolveNemoFlowPluginConfig({ ++ resolveNemoRelayPluginConfig({ + version: 1, + components: [ + { @@ -484,12 +484,12 @@ index 00000000..96b5555d + "capture", + "correlation", + "plugins", -+ "nemoFlow", ++ "nemoRelay", + "atif", + "telemetry", + ])("rejects old wrapper field %s", (field) => { + expect(() => -+ resolveNemoFlowPluginConfig({ ++ resolveNemoRelayPluginConfig({ + version: 1, + components: [], + [field]: {}, @@ -497,14 +497,14 @@ index 00000000..96b5555d + ).toThrow(`config.${field} is no longer supported`); + }); +}); -diff --git a/extensions/nemo-flow/src/runtime.ts b/extensions/nemo-flow/src/runtime.ts +diff --git a/extensions/nemo-relay/src/runtime.ts b/extensions/nemo-relay/src/runtime.ts new file mode 100644 index 00000000..9642147e --- /dev/null -+++ b/extensions/nemo-flow/src/runtime.ts ++++ b/extensions/nemo-relay/src/runtime.ts @@ -0,0 +1,479 @@ +import type { AgentStreamingLlmMiddlewareContext } from "openclaw/plugin-sdk/core"; -+import type { NemoFlowPluginConfig } from "./config.js"; ++import type { NemoRelayPluginConfig } from "./config.js"; + +type JsonRecord = Record; +type StreamFn = AgentStreamingLlmMiddlewareContext["streamFn"]; @@ -513,26 +513,26 @@ index 00000000..9642147e + result?: () => Promise; +}; + -+type NemoFlowScopeHandle = unknown; -+type NemoFlowScopeStack = unknown; ++type NemoRelayScopeHandle = unknown; ++type NemoRelayScopeStack = unknown; + -+type NemoFlowBindings = { -+ createScopeStack: () => NemoFlowScopeStack; -+ setThreadScopeStack: (stack: NemoFlowScopeStack) => void; ++type NemoRelayBindings = { ++ createScopeStack: () => NemoRelayScopeStack; ++ setThreadScopeStack: (stack: NemoRelayScopeStack) => void; + pushScope: ( + name: string, + scopeType: number, -+ handle?: NemoFlowScopeHandle | null, ++ handle?: NemoRelayScopeHandle | null, + attributes?: number | null, + data?: unknown, + metadata?: unknown, -+ ) => NemoFlowScopeHandle; -+ popScope: (handle: NemoFlowScopeHandle) => void; ++ ) => NemoRelayScopeHandle; ++ popScope: (handle: NemoRelayScopeHandle) => void; + toolCallExecuteAsync: ( + name: string, + args: unknown, + func: (arg: unknown) => unknown, -+ handle?: NemoFlowScopeHandle | null, ++ handle?: NemoRelayScopeHandle | null, + attributes?: number | null, + data?: unknown, + metadata?: unknown, @@ -543,7 +543,7 @@ index 00000000..9642147e + func: (request: unknown) => unknown, + collector?: (chunk: unknown) => unknown, + finalizer?: () => unknown, -+ handle?: NemoFlowScopeHandle | null, ++ handle?: NemoRelayScopeHandle | null, + attributes?: number | null, + data?: unknown, + metadata?: unknown, @@ -556,9 +556,9 @@ index 00000000..9642147e + }; +}; + -+type NemoFlowPluginHost = { -+ defaultConfig: () => NemoFlowPluginConfig; -+ validate: (config: NemoFlowPluginConfig) => { ++type NemoRelayPluginHost = { ++ defaultConfig: () => NemoRelayPluginConfig; ++ validate: (config: NemoRelayPluginConfig) => { + diagnostics?: Array<{ + level?: string; + code?: string; @@ -566,7 +566,7 @@ index 00000000..9642147e + message?: string; + }>; + }; -+ initialize: (config: NemoFlowPluginConfig) => Promise; ++ initialize: (config: NemoRelayPluginConfig) => Promise; + clear: () => void; +}; + @@ -576,21 +576,21 @@ index 00000000..9642147e + error: (message: string) => void; +}; + -+type NemoFlowModules = { -+ bindings: NemoFlowBindings; -+ pluginHost: NemoFlowPluginHost; ++type NemoRelayModules = { ++ bindings: NemoRelayBindings; ++ pluginHost: NemoRelayPluginHost; +}; + +type RuntimeState = { -+ modules?: NemoFlowModules; -+ loadPromise?: Promise; ++ modules?: NemoRelayModules; ++ loadPromise?: Promise; + initPromise?: Promise; + initialized: boolean; -+ activeConfig?: NemoFlowPluginConfig; ++ activeConfig?: NemoRelayPluginConfig; + unavailableReason?: string; + unavailableLogged: boolean; -+ sessionScopes: Map; -+ sessionRootScopes: Map; ++ sessionScopes: Map; ++ sessionRootScopes: Map; +}; + +const TOOL_ATTR_LOCAL = 0b01; @@ -611,15 +611,15 @@ index 00000000..9642147e + return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {}; +} + -+async function loadModules(): Promise { ++async function loadModules(): Promise { + try { + const [bindingsModule, pluginHostModule] = await Promise.all([ -+ import("nemo-flow-node"), -+ import("nemo-flow-node/plugin"), ++ import("nemo-relay-node"), ++ import("nemo-relay-node/plugin"), + ]); + return { -+ bindings: bindingsModule as unknown as NemoFlowBindings, -+ pluginHost: pluginHostModule as unknown as NemoFlowPluginHost, ++ bindings: bindingsModule as unknown as NemoRelayBindings, ++ pluginHost: pluginHostModule as unknown as NemoRelayPluginHost, + }; + } catch (error) { + state.unavailableReason = String(error); @@ -627,7 +627,7 @@ index 00000000..9642147e + } +} + -+async function ensureModules(logger: Logger): Promise { ++async function ensureModules(logger: Logger): Promise { + if (state.modules) { + return state.modules; + } @@ -641,7 +641,7 @@ index 00000000..9642147e + } + if (!state.unavailableLogged) { + logger.warn( -+ `nemo-flow unavailable; execution wrapping disabled (${state.unavailableReason ?? "unknown error"})`, ++ `nemo-relay unavailable; execution wrapping disabled (${state.unavailableReason ?? "unknown error"})`, + ); + state.unavailableLogged = true; + } @@ -659,15 +659,15 @@ index 00000000..9642147e + .join(" "); + if (diagnostic.level === "error") { + hasErrors = true; -+ logger.warn(`nemo-flow host config error: ${summary}`); ++ logger.warn(`nemo-relay host config error: ${summary}`); + continue; + } -+ logger.info(`nemo-flow host config warning: ${summary}`); ++ logger.info(`nemo-relay host config warning: ${summary}`); + } + return hasErrors; +} + -+export function getNemoFlowRuntimeStatus(): { ++export function getNemoRelayRuntimeStatus(): { + initialized: boolean; + wrappingActive: boolean; + unavailableReason?: string; @@ -679,9 +679,9 @@ index 00000000..9642147e + }; +} + -+export async function initializeNemoFlowGateway(params: { ++export async function initializeNemoRelayGateway(params: { + logger: Logger; -+ config: NemoFlowPluginConfig; ++ config: NemoRelayPluginConfig; +}): Promise { + const modules = await ensureModules(params.logger); + if (!modules) { @@ -702,7 +702,7 @@ index 00000000..9642147e + state.activeConfig = params.config; + return true; + } catch (error) { -+ params.logger.warn(`nemo-flow initialization failed; wrapping disabled (${String(error)})`); ++ params.logger.warn(`nemo-relay initialization failed; wrapping disabled (${String(error)})`); + return false; + } + })(); @@ -710,11 +710,11 @@ index 00000000..9642147e + return await state.initPromise; +} + -+export async function shutdownNemoFlowGateway(params: { logger: Logger }): Promise { ++export async function shutdownNemoRelayGateway(params: { logger: Logger }): Promise { + try { + state.modules?.pluginHost.clear(); + } catch (error) { -+ params.logger.warn(`nemo-flow shutdown failed (${String(error)})`); ++ params.logger.warn(`nemo-relay shutdown failed (${String(error)})`); + } + for (const rootHandle of state.sessionRootScopes.values()) { + try { @@ -732,9 +732,9 @@ index 00000000..9642147e + +async function ensureInitialized( + logger: Logger, -+ config: NemoFlowPluginConfig, -+): Promise { -+ const initialized = await initializeNemoFlowGateway({ logger, config }); ++ config: NemoRelayPluginConfig, ++): Promise { ++ const initialized = await initializeNemoRelayGateway({ logger, config }); + return initialized ? (state.modules ?? null) : null; +} + @@ -742,7 +742,7 @@ index 00000000..9642147e + return sessionId?.trim() || sessionKey?.trim() || "__openclaw_default__"; +} + -+function ensureSessionScope(modules: NemoFlowModules, sessionId?: string, sessionKey?: string) { ++function ensureSessionScope(modules: NemoRelayModules, sessionId?: string, sessionKey?: string) { + const key = sessionScopeKey(sessionId, sessionKey); + let stack = state.sessionScopes.get(key); + if (!stack) { @@ -753,8 +753,8 @@ index 00000000..9642147e +} + +function ensureSessionRootScope( -+ modules: NemoFlowModules, -+ stack: NemoFlowScopeStack, ++ modules: NemoRelayModules, ++ stack: NemoRelayScopeStack, + sessionId?: string, + sessionKey?: string, +) { @@ -768,7 +768,7 @@ index 00000000..9642147e + return rootHandle; +} + -+function withSessionScope(modules: NemoFlowModules, sessionId?: string, sessionKey?: string): void { ++function withSessionScope(modules: NemoRelayModules, sessionId?: string, sessionKey?: string): void { + const stack = ensureSessionScope(modules, sessionId, sessionKey); + ensureSessionRootScope(modules, stack, sessionId, sessionKey); + modules.bindings.setThreadScopeStack(stack); @@ -814,9 +814,9 @@ index 00000000..9642147e + }; +} + -+export async function executeToolWithNemoFlow(params: { ++export async function executeToolWithNemoRelay(params: { + logger: Logger; -+ config: NemoFlowPluginConfig; ++ config: NemoRelayPluginConfig; + toolName: string; + args: unknown; + sessionId?: string; @@ -848,9 +848,9 @@ index 00000000..9642147e + ); +} + -+export function wrapStreamFnWithNemoFlow(params: { ++export function wrapStreamFnWithNemoRelay(params: { + logger: Logger; -+ config: NemoFlowPluginConfig; ++ config: NemoRelayPluginConfig; + provider: string; + modelId: string; + agentId?: string; @@ -887,9 +887,9 @@ index 00000000..9642147e + request, + (rawWrapper: unknown) => { + const wrapper = asRecord(rawWrapper); -+ const streamId = wrapper.__nemo_flow_stream_id as number; ++ const streamId = wrapper.__nemo_relay_stream_id as number; + const effective = applyRequestToStreamCall({ -+ request: wrapper.__nemo_flow_native ?? request, ++ request: wrapper.__nemo_relay_native ?? request, + context, + options, + }); @@ -940,7 +940,7 @@ index 00000000..9642147e + let completed = false; + const consume = async function* () { + if (iterated) { -+ throw new Error("nemo-flow wrapped stream already consumed"); ++ throw new Error("nemo-relay wrapped stream already consumed"); + } + iterated = true; + const llmStream = await llmStreamPromise; @@ -962,7 +962,7 @@ index 00000000..9642147e + if (!completed) { + for await (const chunk of consume()) { + void chunk; -+ // drain stream so NeMo Flow finalizers run before result() resolves ++ // drain stream so NeMo Relay finalizers run before result() resolves + } + } + const underlying = await underlyingStreamPromise; @@ -990,9 +990,9 @@ index 48b6819d..c03718ab 100644 specifier: workspace:* version: link:../../packages/plugin-sdk -+ extensions/nemo-flow: ++ extensions/nemo-relay: + optionalDependencies: -+ nemo-flow-node: ++ nemo-relay-node: + specifier: file:../../../../crates/node + version: file:../../crates/node + devDependencies: @@ -1007,7 +1007,7 @@ index 48b6819d..c03718ab 100644 resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} -+ nemo-flow-node@file:../../crates/node: ++ nemo-relay-node@file:../../crates/node: + resolution: {directory: ../../crates/node, type: directory} + engines: {node: '>=20.0.0'} + @@ -1018,7 +1018,7 @@ index 48b6819d..c03718ab 100644 negotiator@1.0.0: {} -+ nemo-flow-node@file:../../crates/node: ++ nemo-relay-node@file:../../crates/node: + optional: true + netmask@2.1.1: {} diff --git a/patches/opencode/0001-add-nemo-flow-integration.patch b/patches/opencode/0001-add-nemo-relay-integration.patch similarity index 93% rename from patches/opencode/0001-add-nemo-flow-integration.patch rename to patches/opencode/0001-add-nemo-relay-integration.patch index 64fc123dc..3bb49a196 100644 --- a/patches/opencode/0001-add-nemo-flow-integration.patch +++ b/patches/opencode/0001-add-nemo-relay-integration.patch @@ -7,7 +7,7 @@ index 35841622b..1f99d0b39 100644 "turbo": "2.8.13", }, + "optionalDependencies": { -+ "nemo-flow-node": "file:../../crates/node", ++ "nemo-relay-node": "file:../../crates/node", + }, }, "packages/app": { @@ -17,7 +17,7 @@ index 35841622b..1f99d0b39 100644 "zod-to-json-schema": "3.24.5", }, + "optionalDependencies": { -+ "nemo-flow-node": "file:../../../../crates/node", ++ "nemo-relay-node": "file:../../../../crates/node", + }, }, "packages/plugin": { @@ -155,7 +155,7 @@ index 35841622b..1f99d0b39 100644 "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], -+ "nemo-flow-node": ["nemo-flow-node@file:../../crates/node", { "devDependencies": { "@napi-rs/cli": "^2", "c8": "^11.0.0", "prettier": "^3.8.2", "typedoc": "^0.28.0", "typescript": "^5.8.2" } }], ++ "nemo-relay-node": ["nemo-relay-node@file:../../crates/node", { "devDependencies": { "@napi-rs/cli": "^2", "c8": "^11.0.0", "prettier": "^3.8.2", "typedoc": "^0.28.0", "typescript": "^5.8.2" } }], + "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], @@ -259,7 +259,7 @@ index 35841622b..1f99d0b39 100644 "mssql/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], -+ "nemo-flow-node/prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], ++ "nemo-relay-node/prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], + "nitro/h3": ["h3@2.0.1-rc.5", "", { "dependencies": { "rou3": "^0.7.9", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qkohAzCab0nLzXNm78tBjZDvtKMTmtygS8BJLT3VPczAQofdqlFXDPkXdLMJN4r05+xqneG8snZJ0HgkERCZTg=="], @@ -268,7 +268,7 @@ index 35841622b..1f99d0b39 100644 "opencode/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.32", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-YspqqyJPzHjqWrjt4y/Wgc2aJgCcQj5uIJgZpq2Ar/lH30cEVhgE+keePDbjKpetD9UwNggCj7u6kO3unS23OQ=="], -+ "opencode/nemo-flow-node": ["nemo-flow-node@file:../../crates/node", { "devDependencies": { "@napi-rs/cli": "^2", "c8": "^11.0.0", "prettier": "^3.8.2", "typedoc": "^0.28.0", "typescript": "^5.8.2" } }], ++ "opencode/nemo-relay-node": ["nemo-relay-node@file:../../crates/node", { "devDependencies": { "@napi-rs/cli": "^2", "c8": "^11.0.0", "prettier": "^3.8.2", "typedoc": "^0.28.0", "typescript": "^5.8.2" } }], + "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], @@ -328,7 +328,7 @@ index 35841622b..1f99d0b39 100644 "opencode/@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], -+ "opencode/nemo-flow-node/prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], ++ "opencode/nemo-relay-node/prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], + "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], @@ -427,7 +427,7 @@ index 97087c0e7..aeaf6f23c 100644 "@openrouter/ai-sdk-provider@1.5.4": "patches/@openrouter%2Fai-sdk-provider@1.5.4.patch" + }, + "optionalDependencies": { -+ "nemo-flow-node": "file:../../crates/node" ++ "nemo-relay-node": "file:../../crates/node" } } diff --git a/packages/opencode/package.json b/packages/opencode/package.json @@ -439,7 +439,7 @@ index c462b1761..1fc4933b5 100644 "zod-to-json-schema": "3.24.5" }, + "optionalDependencies": { -+ "nemo-flow-node": "file:../../../../crates/node" ++ "nemo-relay-node": "file:../../../../crates/node" + }, "overrides": { "drizzle-orm": "1.0.0-beta.16-ea816b6" @@ -452,7 +452,7 @@ index 27ba4e186..84e548d29 100644 .object({ disable_paste_summary: z.boolean().optional(), batch_tool: z.boolean().optional().describe("Enable the batch tool"), -+ nemo_flow: z.boolean().optional().describe("Enable NemoFlow agent tracing and ATIF trajectory export"), ++ nemo_relay: z.boolean().optional().describe("Enable NemoRelay agent tracing and ATIF trajectory export"), openTelemetry: z .boolean() .optional() @@ -464,7 +464,7 @@ index a1cfd862b..597d417ca 100644 export const OPENCODE_ENABLE_QUESTION_TOOL = truthy("OPENCODE_ENABLE_QUESTION_TOOL") // Experimental -+ export const NEMO_FLOW_ENABLED = truthy("NEMO_FLOW_ENABLED") ++ export const NEMO_RELAY_ENABLED = truthy("NEMO_RELAY_ENABLED") export const OPENCODE_EXPERIMENTAL = truthy("OPENCODE_EXPERIMENTAL") export const OPENCODE_EXPERIMENTAL_FILEWATCHER = Config.boolean("OPENCODE_EXPERIMENTAL_FILEWATCHER").pipe( Config.withDefault(false), @@ -476,7 +476,7 @@ index 8790efac4..c4ff5c98b 100644 import { NamedError } from "@opencode-ai/util/error" import { CopilotAuthPlugin } from "./copilot" import { gitlabAuthPlugin as GitlabAuthPlugin } from "@gitlab/opencode-gitlab-auth" -+import { NemoFlowPlugin } from "./nemo_flow" ++import { NemoRelayPlugin } from "./nemo_relay" export namespace Plugin { const log = Log.create({ service: "plugin" }) @@ -485,7 +485,7 @@ index 8790efac4..c4ff5c98b 100644 // Built-in plugins that are directly imported (not installed from npm) - const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin, GitlabAuthPlugin] -+ const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin, GitlabAuthPlugin, NemoFlowPlugin] ++ const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin, GitlabAuthPlugin, NemoRelayPlugin] const state = Instance.state(async () => { const client = createOpencodeClient({ @@ -517,7 +517,7 @@ index 38dac41b0..09c692205 100644 import { Question } from "@/question" import { PartID } from "./schema" import type { SessionID, MessageID } from "./schema" -+import { NemoFlow } from "@/nemo_flow" ++import { NemoRelay } from "@/nemo_relay" export namespace SessionProcessor { const DOOM_LOOP_THRESHOLD = 3 @@ -528,7 +528,7 @@ index 38dac41b0..09c692205 100644 - const stream = await LLM.stream(streamInput) - - for await (const value of stream.fullStream) { -+ const eventStream = NemoFlow.wrapLlmStream( ++ const eventStream = NemoRelay.wrapLlmStream( + streamInput, + async function*() { + const stream = await LLM.stream(streamInput) @@ -549,7 +549,7 @@ index 5bde2608f..b2b087e12 100644 import { SessionSummary } from "./summary" import { NamedError } from "@opencode-ai/util/error" import { fn } from "@/util/fn" -+import { NemoFlow } from "../nemo_flow" ++import { NemoRelay } from "../nemo_relay" import { SessionProcessor } from "./processor" import { TaskTool } from "@/tool/task" import { Tool } from "@/tool/tool" @@ -558,7 +558,7 @@ index 5bde2608f..b2b087e12 100644 let step = 0 const session = await Session.get(sessionID) + let agentScopeHandle: unknown = null -+ using _nemo_flowScope = defer(() => NemoFlow.popScope(agentScopeHandle)) ++ using _nemo_relayScope = defer(() => NemoRelay.popScope(agentScopeHandle)) while (true) { SessionStatus.set(sessionID, { type: "busy" }) log.info("loop", { step, sessionID }) @@ -567,7 +567,7 @@ index 5bde2608f..b2b087e12 100644 // normal processing const agent = await Agent.get(lastUser.agent) + if (!agentScopeHandle) { -+ agentScopeHandle = NemoFlow.pushAgentScope(agent.name) ++ agentScopeHandle = NemoRelay.pushAgentScope(agent.name) + } const maxSteps = agent.steps ?? Infinity const isLastStep = step >= maxSteps @@ -577,7 +577,7 @@ index 5bde2608f..b2b087e12 100644 }, ) - const result = await item.execute(args, ctx) -+ const result = await NemoFlow.wrapToolExecute(item.id, args, async (a) => { ++ const result = await NemoRelay.wrapToolExecute(item.id, args, async (a) => { + return item.execute(a, ctx) + }) const output = { @@ -588,7 +588,7 @@ index 5bde2608f..b2b087e12 100644 }) - const result = await execute(args, opts) -+ const result = await NemoFlow.wrapToolExecute(key, args, async (a) => { ++ const result = await NemoRelay.wrapToolExecute(key, args, async (a) => { + return execute(a, opts) + }) @@ -602,7 +602,7 @@ index 00c22bfe6..343816b57 100644 import { Tool } from "./tool" import { ProviderID, ModelID } from "../provider/schema" import DESCRIPTION from "./batch.txt" -+import { NemoFlow } from "../nemo_flow" ++import { NemoRelay } from "../nemo_relay" const DISALLOWED = new Set(["batch"]) const FILTERED_FROM_SUGGESTIONS = new Set(["invalid", "patch", ...DISALLOWED]) @@ -611,7 +611,7 @@ index 00c22bfe6..343816b57 100644 }) - const result = await tool.execute(validatedParams, { ...ctx, callID: partID }) -+ const result = await NemoFlow.wrapToolExecute(call.tool, validatedParams, async (args) => { ++ const result = await NemoRelay.wrapToolExecute(call.tool, validatedParams, async (args) => { + return tool.execute(args, { ...ctx, callID: partID }) + }) const attachments = result.attachments?.map((attachment) => ({ @@ -622,27 +622,27 @@ index 00c22bfe6..343816b57 100644 } - const results = await Promise.all(toolCalls.map((call) => executeCall(call))) -+ const batchScope = NemoFlow.pushFunctionScope("batch-parallel", NemoFlow.SCOPE_ATTR_PARALLEL) ++ const batchScope = NemoRelay.pushFunctionScope("batch-parallel", NemoRelay.SCOPE_ATTR_PARALLEL) + let results: Awaited>[] + try { + results = await Promise.all(toolCalls.map((call) => executeCall(call))) + } finally { -+ NemoFlow.popScope(batchScope) ++ NemoRelay.popScope(batchScope) + } // Add discarded calls as errors const now = Date.now() -diff --git a/packages/opencode/src/nemo_flow/index.ts b/packages/opencode/src/nemo_flow/index.ts +diff --git a/packages/opencode/src/nemo_relay/index.ts b/packages/opencode/src/nemo_relay/index.ts new file mode 100644 index 000000000..f8cd52955 --- /dev/null -+++ b/packages/opencode/src/nemo_flow/index.ts ++++ b/packages/opencode/src/nemo_relay/index.ts @@ -0,0 +1,292 @@ +import { Log } from "../util/log" +import { Flag } from "../flag/flag" +import fsSync from "fs" + -+const log = Log.create({ service: "nemo_flow" }) ++const log = Log.create({ service: "nemo_relay" }) + +let lib: any = null +let typedLib: any = null @@ -661,17 +661,17 @@ index 000000000..f8cd52955 + } +} + -+export namespace NemoFlow { ++export namespace NemoRelay { + export let SCOPE_ATTR_PARALLEL = 0 + -+ export async function init(config?: { nemo_flow?: boolean }): Promise { ++ export async function init(config?: { nemo_relay?: boolean }): Promise { + if (initDone) return enabled + initDone = true -+ if (!Flag.NEMO_FLOW_ENABLED && !config?.nemo_flow) return false ++ if (!Flag.NEMO_RELAY_ENABLED && !config?.nemo_relay) return false + + try { -+ lib = await import("nemo-flow-node") -+ typedLib = await import("nemo-flow-node/typed") ++ lib = await import("nemo-relay-node") ++ typedLib = await import("nemo-relay-node/typed") + enabled = true + SCOPE_ATTR_PARALLEL = lib.SCOPE_ATTR_PARALLEL ?? 0 + log.info("initialized") @@ -745,7 +745,7 @@ index 000000000..f8cd52955 + // StreamInput codec — bidirectional serialization across the NAPI boundary + // --------------------------------------------------------------------------- + // Strips non-JSON-serializable fields (AbortSignal, Tool functions) during -+ // encoding. After NemoFlow intercepts potentially modify the serializable ++ // encoding. After NemoRelay intercepts potentially modify the serializable + // subset, applyIntercepted merges changes back while restoring the stripped + // fields from the original. + @@ -826,7 +826,7 @@ index 000000000..f8cd52955 + // Apply intercepted request changes back to streamInput before + // streamFn() reads it — streamFn captures streamInput by reference. + applyIntercepted(streamInput, interceptedReq?.content) -+ // Bridge NemoFlow-intercepted headers to the AI SDK HTTP request. ++ // Bridge NemoRelay-intercepted headers to the AI SDK HTTP request. + if (interceptedReq?.headers && Object.keys(interceptedReq.headers).length > 0) { + streamInput.extraHeaders = interceptedReq.headers + } @@ -853,7 +853,7 @@ index 000000000..f8cd52955 + }, + ) + -+ // Drain NemoFlow stream (drives lifecycle/intercepts) and yield collected events ++ // Drain NemoRelay stream (drives lifecycle/intercepts) and yield collected events + while ((await nvStream.next()) !== null) { + while (collected.length > 0) { + yield collected.shift() @@ -930,41 +930,41 @@ index 000000000..f8cd52955 + } + } +} -diff --git a/packages/opencode/src/plugin/nemo_flow.ts b/packages/opencode/src/plugin/nemo_flow.ts +diff --git a/packages/opencode/src/plugin/nemo_relay.ts b/packages/opencode/src/plugin/nemo_relay.ts new file mode 100644 index 000000000..5659fdd37 --- /dev/null -+++ b/packages/opencode/src/plugin/nemo_flow.ts ++++ b/packages/opencode/src/plugin/nemo_relay.ts @@ -0,0 +1,54 @@ +import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin" +import { Config } from "../config/config" -+import { NemoFlow } from "../nemo_flow" ++import { NemoRelay } from "../nemo_relay" +import { Global } from "../global" +import { Log } from "../util/log" +import path from "path" +import fs from "fs/promises" + -+const log = Log.create({ service: "plugin.nemo_flow" }) ++const log = Log.create({ service: "plugin.nemo_relay" }) + -+export const NemoFlowPlugin: PluginInstance = async (_input) => { ++export const NemoRelayPlugin: PluginInstance = async (_input) => { + const config = await Config.get() -+ const enabled = await NemoFlow.init({ nemo_flow: config.experimental?.nemo_flow }) ++ const enabled = await NemoRelay.init({ nemo_relay: config.experimental?.nemo_relay }) + if (!enabled) return {} + -+ const atofDir = process.env.NEMO_FLOW_ATOF_DIR ?? path.join(Global.Path.data, "atof") ++ const atofDir = process.env.NEMO_RELAY_ATOF_DIR ?? path.join(Global.Path.data, "atof") + await fs.mkdir(atofDir, { recursive: true }) -+ NemoFlow.createAtOfJsonlExporter(path.join(atofDir, "events.jsonl")) ++ NemoRelay.createAtOfJsonlExporter(path.join(atofDir, "events.jsonl")) + -+ const atifDir = process.env.NEMO_FLOW_ATIF_DIR ?? path.join(Global.Path.data, "atif") ++ const atifDir = process.env.NEMO_RELAY_ATIF_DIR ?? path.join(Global.Path.data, "atif") + await fs.mkdir(atifDir, { recursive: true }) + + return { + "chat.message": async (hookInput, _output) => { -+ if (!NemoFlow.hasExporter(hookInput.sessionID)) { ++ if (!NemoRelay.hasExporter(hookInput.sessionID)) { + const modelStr = hookInput.model + ? `${hookInput.model.providerID}/${hookInput.model.modelID}` + : undefined -+ NemoFlow.createExporter( ++ NemoRelay.createExporter( + hookInput.sessionID, + hookInput.agent ?? "opencode", + modelStr, @@ -977,15 +977,15 @@ index 000000000..5659fdd37 + const props = (event as any).properties + if ((event as any).type === "session.status" && props?.status?.type === "idle") { + const sessionID = props.sessionID as string -+ if (!sessionID || !NemoFlow.hasExporter(sessionID)) return ++ if (!sessionID || !NemoRelay.hasExporter(sessionID)) return + -+ const trajectory = NemoFlow.exportTrajectory(sessionID) ++ const trajectory = NemoRelay.exportTrajectory(sessionID) + if (!trajectory) return + + const filePath = path.join(atifDir, `${sessionID}.json`) + await fs.writeFile(filePath, trajectory) + log.info("exported ATIF trajectory", { sessionID, path: filePath }) -+ NemoFlow.clearExporter(sessionID) ++ NemoRelay.clearExporter(sessionID) + } + }, + } satisfies Hooks diff --git a/pyproject.toml b/pyproject.toml index c55c0ae94..8740fd53c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,10 @@ requires = ["maturin>=1.0,<2.0"] build-backend = "maturin" [project] -name = "nemo-flow" +name = "nemo-relay" dynamic = ["version"] -description = "Python bindings for the NeMo Flow agent runtime." -readme = "python/nemo_flow/README.md" +description = "Python bindings for the NeMo Relay agent runtime." +readme = "python/nemo_relay/README.md" requires-python = ">=3.11" license = "Apache-2.0" authors = [ @@ -20,7 +20,7 @@ keywords = [ "ai", "llm", "middleware", - "nemo-flow", + "nemo-relay", "observability", "runtime", "tools", @@ -36,10 +36,10 @@ classifiers = [ ] [project.urls] -Documentation = "https://nvidia.github.io/NeMo-Flow/" -Homepage = "https://github.com/NVIDIA/NeMo-Flow" -Issues = "https://github.com/NVIDIA/NeMo-Flow/issues" -Repository = "https://github.com/NVIDIA/NeMo-Flow" +Documentation = "https://nvidia.github.io/NeMo-Relay/" +Homepage = "https://github.com/NVIDIA/NeMo-Relay" +Issues = "https://github.com/NVIDIA/NeMo-Relay/issues" +Repository = "https://github.com/NVIDIA/NeMo-Relay" [dependency-groups] dev = [ @@ -81,24 +81,24 @@ langchain = [ ] langgraph = [ - "nemo-flow[langchain]", + "nemo-relay[langchain]", "langgraph>=1.2.0,<2.0.0", ] deepagents = [ - "nemo-flow[langgraph]", + "nemo-relay[langgraph]", "deepagents>=0.5.3,<0.6.0", ] langchain-nvidia = [ - "nemo-flow[langchain]", + "nemo-relay[langchain]", "langchain-nvidia-ai-endpoints~=1.0", ] [tool.maturin] manifest-path = "crates/python/Cargo.toml" python-source = "python" -module-name = "nemo_flow._native" +module-name = "nemo_relay._native" features = ["pyo3/extension-module"] [tool.maturin.sbom] @@ -115,14 +115,14 @@ asyncio_mode = "auto" [tool.coverage.run] # Exclude integration tests from coverage, since we don't run these by default -omit = ["python/nemo_flow/integrations/*"] +omit = ["python/nemo_relay/integrations/*"] [tool.ty.analysis] -# nemo_flow._native is a compiled Rust extension (built by maturin) that only +# nemo_relay._native is a compiled Rust extension (built by maturin) that only # exists after `uv sync` / `pip install -e .`. Suppress unresolved-import for it. # LangChain, LangGraph, and Deep Agents are optional integration dependencies # which aren't installed by default. -allowed-unresolved-imports = ["deepagents.**", "langchain.**", "langchain_*.**", "langgraph.**", "nemo_flow._native", "pytest"] +allowed-unresolved-imports = ["deepagents.**", "langchain.**", "langchain_*.**", "langgraph.**", "nemo_relay._native", "pytest"] [tool.ruff] line-length = 120 @@ -135,4 +135,4 @@ quote-style = "double" select = ["E", "F", "W", "I"] [tool.ruff.lint.isort] -known-first-party = ["nemo_flow"] +known-first-party = ["nemo_relay"] diff --git a/python/nemo_flow/integrations/langchain/__init__.py b/python/nemo_flow/integrations/langchain/__init__.py deleted file mode 100644 index 0fde8604d..000000000 --- a/python/nemo_flow/integrations/langchain/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -"""NeMo Flow integrations for LangChain.""" - -from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler -from nemo_flow.integrations.langchain.middleware import NemoFlowMiddleware - -__all__ = [ - "NemoFlowCallbackHandler", - "NemoFlowMiddleware", -] diff --git a/python/nemo_flow/integrations/langgraph/__init__.py b/python/nemo_flow/integrations/langgraph/__init__.py deleted file mode 100644 index d95db5b0e..000000000 --- a/python/nemo_flow/integrations/langgraph/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -"""NeMo Flow integrations for LangGraph.""" - -from nemo_flow.integrations.langchain import NemoFlowMiddleware -from nemo_flow.integrations.langgraph.callbacks import NemoFlowCallbackHandler - -__all__ = [ - "NemoFlowCallbackHandler", - "NemoFlowMiddleware", -] diff --git a/python/nemo_flow/README.md b/python/nemo_relay/README.md similarity index 56% rename from python/nemo_flow/README.md rename to python/nemo_relay/README.md index d76299165..3c72b88a8 100644 --- a/python/nemo_flow/README.md +++ b/python/nemo_relay/README.md @@ -3,21 +3,21 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Flow)](https://github.com/NVIDIA/NeMo-Flow/blob/main/LICENSE) -[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Flow/) -[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Flow?color=green)](https://github.com/NVIDIA/NeMo-Flow/releases) -[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Flow/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Flow) -[![PyPI](https://img.shields.io/pypi/v/nemo-flow?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-flow/) -[![npm node](https://img.shields.io/npm/v/nemo-flow-node?label=nemo-flow-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-node) -[![npm wasm](https://img.shields.io/npm/v/nemo-flow-wasm?label=nemo-flow-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-flow-wasm) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow?label=nemo-flow&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-adaptive?label=nemo-flow-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-adaptive) -[![Crates.io](https://img.shields.io/crates/v/nemo-flow-cli?label=nemo-flow-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-flow-cli) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Flow) - -# NeMo Flow - -`nemo-flow` is the NeMo Flow package for Python applications. It gives Python +[![License](https://img.shields.io/github/license/NVIDIA/NeMo-Relay)](https://github.com/NVIDIA/NeMo-Relay/blob/main/LICENSE) +[![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/NVIDIA/NeMo-Relay/) +[![Release](https://img.shields.io/github/v/release/NVIDIA/NeMo-Relay?color=green)](https://github.com/NVIDIA/NeMo-Relay/releases) +[![Codecov](https://codecov.io/gh/NVIDIA/NeMo-Relay/branch/main/graph/badge.svg)](https://app.codecov.io/gh/NVIDIA/NeMo-Relay) +[![PyPI](https://img.shields.io/pypi/v/nemo-relay?color=4B8BBE&logo=pypi)](https://pypi.org/project/nemo-relay/) +[![npm node](https://img.shields.io/npm/v/nemo-relay-node?label=nemo-relay-node&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-node) +[![npm wasm](https://img.shields.io/npm/v/nemo-relay-wasm?label=nemo-relay-wasm&color=CC3534&logo=npm)](https://www.npmjs.com/package/nemo-relay-wasm) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay?label=nemo-relay&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-adaptive?label=nemo-relay-adaptive&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-adaptive) +[![Crates.io](https://img.shields.io/crates/v/nemo-relay-cli?label=nemo-relay-cli&color=B7410E&logo=rust)](https://crates.io/crates/nemo-relay-cli) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/NVIDIA/NeMo-Relay) + +# NeMo Relay + +`nemo-relay` is the NeMo Relay package for Python applications. It gives Python code access to a portable agent runtime for execution scopes, middleware, plugins, lifecycle events, adaptive behavior, and observability around tool and LLM calls. @@ -55,13 +55,13 @@ runtime semantics as the Rust and Node.js surfaces. Install the published package with `uv`: ```bash -uv add nemo-flow +uv add nemo-relay ``` If you are not using `uv`, install it with `pip`: ```bash -pip install nemo-flow +pip install nemo-relay ``` ### Optional Dependencies @@ -72,10 +72,10 @@ pip install nemo-flow ```bash # With uv -uv add "nemo-flow[langchain]" +uv add "nemo-relay[langchain]" # With pip -pip install "nemo-flow[langchain]" +pip install "nemo-relay[langchain]" ``` #### LangGraph Integration @@ -84,10 +84,10 @@ pip install "nemo-flow[langchain]" ```bash # With uv -uv add "nemo-flow[langgraph]" +uv add "nemo-relay[langgraph]" # With pip -pip install "nemo-flow[langgraph]" +pip install "nemo-relay[langgraph]" ``` #### Deep Agents Integration @@ -98,10 +98,10 @@ with the `deepagents` extra. This extra builds upon and includes the ```bash # With uv -uv add "nemo-flow[deepagents]" +uv add "nemo-relay[deepagents]" # With pip -pip install "nemo-flow[deepagents]" +pip install "nemo-relay[deepagents]" ``` #### LangChain NVIDIA Integration @@ -110,19 +110,19 @@ The [LangChain NVIDIA](https://github.com/langchain-ai/langchain-nvidia) extra b ```bash # With uv -uv add "nemo-flow[langchain-nvidia]" +uv add "nemo-relay[langchain-nvidia]" # With pip -pip install "nemo-flow[langchain-nvidia]" +pip install "nemo-relay[langchain-nvidia]" ``` To install this along with the `langgraph` extra, use: ```bash # With uv -uv add "nemo-flow[langgraph,langchain-nvidia]" +uv add "nemo-relay[langgraph,langchain-nvidia]" # With pip -pip install "nemo-flow[langgraph,langchain-nvidia]" +pip install "nemo-relay[langgraph,langchain-nvidia]" ``` ## Getting Started @@ -130,19 +130,19 @@ pip install "nemo-flow[langgraph,langchain-nvidia]" Register a subscriber, create a scope, and emit a mark event: ```python -import nemo_flow +import nemo_relay def on_event(event) -> None: print(f"{event.kind} {event.name}") -nemo_flow.subscribers.register("printer", on_event) +nemo_relay.subscribers.register("printer", on_event) -with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope.event("initialized", handle=handle, data={"binding": "python"}) +with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope.event("initialized", handle=handle, data={"binding": "python"}) -nemo_flow.subscribers.deregister("printer") +nemo_relay.subscribers.deregister("printer") ``` For host integrations that need a serialized event shape, consume the @@ -150,7 +150,7 @@ canonical JSON payload from the subscriber event object: ```python import json -import nemo_flow +import nemo_relay def on_event(event) -> None: @@ -159,38 +159,38 @@ def on_event(event) -> None: assert json.loads(event.to_json()) == payload -nemo_flow.subscribers.register("host-exporter", on_event) +nemo_relay.subscribers.register("host-exporter", on_event) try: - with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent): - nemo_flow.scope.event("initialized", data={"binding": "python"}) + with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent): + nemo_relay.scope.event("initialized", data={"binding": "python"}) finally: - nemo_flow.subscribers.deregister("host-exporter") + nemo_relay.subscribers.deregister("host-exporter") ``` ## Package Surface The public package modules are: -- `nemo_flow.scope` -- `nemo_flow.tools` -- `nemo_flow.llm` -- `nemo_flow.guardrails` -- `nemo_flow.intercepts` -- `nemo_flow.subscribers` -- `nemo_flow.plugin` -- `nemo_flow.adaptive` -- `nemo_flow.observability` -- `nemo_flow.typed` -- `nemo_flow.codecs` +- `nemo_relay.scope` +- `nemo_relay.tools` +- `nemo_relay.llm` +- `nemo_relay.guardrails` +- `nemo_relay.intercepts` +- `nemo_relay.subscribers` +- `nemo_relay.plugin` +- `nemo_relay.adaptive` +- `nemo_relay.observability` +- `nemo_relay.typed` +- `nemo_relay.codecs` ### Integrations -- `nemo_flow.integrations.langchain` -- `nemo_flow.integrations.langgraph` -- `nemo_flow.integrations.deepagents` +- `nemo_relay.integrations.langchain` +- `nemo_relay.integrations.langgraph` +- `nemo_relay.integrations.deepagents` -The compiled extension is exposed as `nemo_flow._native`. +The compiled extension is exposed as `nemo_relay._native`. ## Documentation -NeMo Flow Documentation: https://nvidia.github.io/NeMo-Flow +NeMo Relay Documentation: https://nvidia.github.io/NeMo-Relay diff --git a/python/nemo_flow/__init__.py b/python/nemo_relay/__init__.py similarity index 84% rename from python/nemo_flow/__init__.py rename to python/nemo_relay/__init__.py index 85dce458e..733caeb35 100644 --- a/python/nemo_flow/__init__.py +++ b/python/nemo_relay/__init__.py @@ -1,21 +1,21 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Python bindings for the NeMo Flow runtime. +"""Python bindings for the NeMo Relay runtime. This package exposes the runtime's scope stack, lifecycle events, middleware registries, typed wrappers, and adaptive helpers from Python. The main entry points are: -- ``nemo_flow.scope`` for creating and nesting scopes -- ``nemo_flow.tools`` for tool lifecycle management -- ``nemo_flow.llm`` for non-streaming and streaming LLM lifecycle management -- ``nemo_flow.guardrails`` and ``nemo_flow.intercepts`` for global middleware -- ``nemo_flow.scope_local`` for middleware scoped to a specific ``ScopeHandle`` -- ``nemo_flow.typed`` for codec-based typed wrappers -- ``nemo_flow.plugin`` for global plugin configuration and custom plugin registration -- ``nemo_flow.adaptive`` for adaptive component configuration helpers -- ``nemo_flow.observability`` for observability component configuration helpers +- ``nemo_relay.scope`` for creating and nesting scopes +- ``nemo_relay.tools`` for tool lifecycle management +- ``nemo_relay.llm`` for non-streaming and streaming LLM lifecycle management +- ``nemo_relay.guardrails`` and ``nemo_relay.intercepts`` for global middleware +- ``nemo_relay.scope_local`` for middleware scoped to a specific ``ScopeHandle`` +- ``nemo_relay.typed`` for codec-based typed wrappers +- ``nemo_relay.plugin`` for global plugin configuration and custom plugin registration +- ``nemo_relay.adaptive`` for adaptive component configuration helpers +- ``nemo_relay.observability`` for observability component configuration helpers Top-level exports also include: @@ -32,7 +32,7 @@ import asyncio - import nemo_flow + import nemo_relay def redact_args(tool_name, args): return {**args, "api_key": "***"} @@ -48,14 +48,14 @@ async def llm_impl(request): return {"messages": request.content["messages"], "ok": True} async def main(): - nemo_flow.guardrails.register_tool_sanitize_request("redact", 10, redact_args) - nemo_flow.intercepts.register_llm_request("auth", 10, False, add_header) + nemo_relay.guardrails.register_tool_sanitize_request("redact", 10, redact_args) + nemo_relay.intercepts.register_llm_request("auth", 10, False, add_header) - with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent): - tool_result = await nemo_flow.tools.execute("search", {"query": "hello"}, tool_impl) - llm_result = await nemo_flow.llm.execute( + with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent): + tool_result = await nemo_relay.tools.execute("search", {"query": "hello"}, tool_impl) + llm_result = await nemo_relay.llm.execute( "demo-model", - nemo_flow.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), + nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), llm_impl, ) @@ -77,7 +77,7 @@ async def main(): # Native event classes delivered to subscribers and exporters. # Native observability exporters and subscriber configuration types. # Native scope stack handle and low-level synchronization functions. -from nemo_flow._native import ( +from nemo_relay._native import ( AnnotatedLLMRequest, AnnotatedLLMResponse, AtifExporter, @@ -100,12 +100,12 @@ async def main(): ToolAttributes, ToolHandle, ) -from nemo_flow._native import create_scope_stack as _create_scope_stack -from nemo_flow._native import scope_stack_active as _native_scope_stack_active -from nemo_flow._native import set_thread_scope_stack as _set_thread_scope_stack -from nemo_flow._native import sync_thread_scope_stack as _sync_thread_scope_stack +from nemo_relay._native import create_scope_stack as _create_scope_stack +from nemo_relay._native import scope_stack_active as _native_scope_stack_active +from nemo_relay._native import set_thread_scope_stack as _set_thread_scope_stack +from nemo_relay._native import sync_thread_scope_stack as _sync_thread_scope_stack -#: Scalar JSON leaf values accepted in NeMo Flow payloads. This alias has no +#: Scalar JSON leaf values accepted in NeMo Relay payloads. This alias has no #: runtime behavior; it exists to document and type JSON-compatible public API #: arguments and return values. JsonPrimitive: TypeAlias = str | int | float | bool | None @@ -176,7 +176,7 @@ async def main(): ] # intentionally not importing utils.py to avoid overhead of creating the ThreadPoolExecutor unless it is needed -from nemo_flow import ( # noqa: E402 +from nemo_relay import ( # noqa: E402 adaptive, codecs, guardrails, @@ -200,7 +200,7 @@ def get_scope_stack() -> ScopeStack: If the current async context does not yet own a scope stack, this function creates one and synchronizes it into the Rust thread-local storage used by the native runtime. Most callers do not need to invoke this directly - because higher-level helpers such as ``nemo_flow.scope.push()`` do it + because higher-level helpers such as ``nemo_relay.scope.push()`` do it automatically. Returns: @@ -223,9 +223,9 @@ def get_scope_stack() -> ScopeStack: Example:: - import nemo_flow + import nemo_relay - stack = nemo_flow.get_scope_stack() + stack = nemo_relay.get_scope_stack() assert stack is not None """ stack = _scope_stack_var.get(None) @@ -262,11 +262,11 @@ def scope_stack_active() -> bool: Example:: - import nemo_flow + import nemo_relay - assert nemo_flow.scope_stack_active() is False - nemo_flow.get_scope_stack() - assert nemo_flow.scope_stack_active() is True + assert nemo_relay.scope_stack_active() is False + nemo_relay.get_scope_stack() + assert nemo_relay.scope_stack_active() is True """ if _scope_stack_var.get(None) is not None: return True @@ -298,14 +298,14 @@ def propagate_scope_to_thread() -> ScopeStack: from concurrent.futures import ThreadPoolExecutor - import nemo_flow + import nemo_relay - with nemo_flow.scope.scope("parent", nemo_flow.ScopeType.Agent) as handle: - stack = nemo_flow.propagate_scope_to_thread() + with nemo_relay.scope.scope("parent", nemo_relay.ScopeType.Agent) as handle: + stack = nemo_relay.propagate_scope_to_thread() def worker() -> None: - nemo_flow.set_thread_scope_stack(stack) - nemo_flow.scope.event( + nemo_relay.set_thread_scope_stack(stack) + nemo_relay.scope.event( "worker-ran", handle=handle, data={"source": "thread"}, @@ -317,7 +317,8 @@ def worker() -> None: """ if not scope_stack_active(): raise RuntimeError( - "no active scope stack in current context; call nemo_flow.get_scope_stack() or nemo_flow.scope.push() first" + "no active scope stack in current context; call nemo_relay.get_scope_stack() " + "or nemo_relay.scope.push() first" ) # Return the ContextVar value directly if available, to avoid # calling get_scope_stack() which would sync to the Rust thread-local. @@ -353,10 +354,10 @@ def create_scope_stack() -> ScopeStack: Example:: - import nemo_flow + import nemo_relay - stack = nemo_flow.create_scope_stack() - nemo_flow.set_thread_scope_stack(stack) + stack = nemo_relay.create_scope_stack() + nemo_relay.set_thread_scope_stack(stack) """ return _create_scope_stack() @@ -365,7 +366,7 @@ def set_thread_scope_stack(stack: ScopeStack) -> None: """Install a scope stack into the current thread's native runtime context. Args: - stack: Scope stack that should become active for subsequent NeMo Flow + stack: Scope stack that should become active for subsequent NeMo Relay API calls on the current thread. Returns: @@ -389,13 +390,13 @@ def set_thread_scope_stack(stack: ScopeStack) -> None: from concurrent.futures import ThreadPoolExecutor - import nemo_flow + import nemo_relay - with nemo_flow.scope.scope("parent", nemo_flow.ScopeType.Agent): - stack = nemo_flow.propagate_scope_to_thread() + with nemo_relay.scope.scope("parent", nemo_relay.ScopeType.Agent): + stack = nemo_relay.propagate_scope_to_thread() def worker() -> None: - nemo_flow.set_thread_scope_stack(stack) + nemo_relay.set_thread_scope_stack(stack) with ThreadPoolExecutor() as pool: pool.submit(worker).result() diff --git a/python/nemo_flow/__init__.pyi b/python/nemo_relay/__init__.pyi similarity index 85% rename from python/nemo_flow/__init__.pyi rename to python/nemo_relay/__init__.pyi index c506b2d26..5ddde9b6e 100644 --- a/python/nemo_flow/__init__.pyi +++ b/python/nemo_relay/__init__.pyi @@ -1,16 +1,16 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Type stubs for the public ``nemo_flow`` package facade. +"""Type stubs for the public ``nemo_relay`` package facade. Summary: - ``nemo_flow`` exposes the Python entry point for scope tracking, lifecycle + ``nemo_relay`` exposes the Python entry point for scope tracking, lifecycle events, middleware registration, typed helpers, plugins, adaptive configuration, and native observability types. Description: The concrete implementations live in Python wrapper modules and in the - compiled ``nemo_flow._native`` extension. This stub intentionally keeps + compiled ``nemo_relay._native`` extension. This stub intentionally keeps native classes re-exported from ``_native.pyi`` so the native module remains the source of truth. @@ -25,84 +25,84 @@ import contextvars from collections.abc import AsyncIterator, Awaitable, Callable from typing import Literal, Optional, TypeAlias -from nemo_flow import adaptive as adaptive -from nemo_flow import codecs as codecs -from nemo_flow import guardrails as guardrails -from nemo_flow import intercepts as intercepts -from nemo_flow import llm as llm -from nemo_flow import observability as observability -from nemo_flow import plugin as plugin -from nemo_flow import scope as scope -from nemo_flow import scope_local as scope_local -from nemo_flow import subscribers as subscribers -from nemo_flow import tools as tools -from nemo_flow import typed as typed -from nemo_flow._native import ( +from nemo_relay import adaptive as adaptive +from nemo_relay import codecs as codecs +from nemo_relay import guardrails as guardrails +from nemo_relay import intercepts as intercepts +from nemo_relay import llm as llm +from nemo_relay import observability as observability +from nemo_relay import plugin as plugin +from nemo_relay import scope as scope +from nemo_relay import scope_local as scope_local +from nemo_relay import subscribers as subscribers +from nemo_relay import tools as tools +from nemo_relay import typed as typed +from nemo_relay._native import ( AnnotatedLLMRequest as AnnotatedLLMRequest, ) -from nemo_flow._native import ( +from nemo_relay._native import ( AnnotatedLLMResponse as AnnotatedLLMResponse, ) -from nemo_flow._native import ( +from nemo_relay._native import ( AtifExporter as AtifExporter, ) -from nemo_flow._native import ( +from nemo_relay._native import ( AtofExporter as AtofExporter, ) -from nemo_flow._native import ( +from nemo_relay._native import ( AtofExporterConfig as AtofExporterConfig, ) -from nemo_flow._native import ( +from nemo_relay._native import ( AtofExporterMode as AtofExporterMode, ) -from nemo_flow._native import ( +from nemo_relay._native import ( LLMAttributes as LLMAttributes, ) -from nemo_flow._native import ( +from nemo_relay._native import ( LLMHandle as LLMHandle, ) -from nemo_flow._native import ( +from nemo_relay._native import ( LLMRequest as LLMRequest, ) -from nemo_flow._native import ( +from nemo_relay._native import ( MarkEvent as MarkEvent, ) -from nemo_flow._native import ( +from nemo_relay._native import ( OpenInferenceConfig as OpenInferenceConfig, ) -from nemo_flow._native import ( +from nemo_relay._native import ( OpenInferenceSubscriber as OpenInferenceSubscriber, ) -from nemo_flow._native import ( +from nemo_relay._native import ( OpenTelemetryConfig as OpenTelemetryConfig, ) -from nemo_flow._native import ( +from nemo_relay._native import ( OpenTelemetrySubscriber as OpenTelemetrySubscriber, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ScopeAttributes as ScopeAttributes, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ScopeEvent as ScopeEvent, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ScopeHandle as ScopeHandle, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ScopeStack as ScopeStack, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ScopeType as ScopeType, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ToolAttributes as ToolAttributes, ) -from nemo_flow._native import ( +from nemo_relay._native import ( ToolHandle as ToolHandle, ) JsonPrimitive: TypeAlias = str | int | float | bool | None -"""Scalar JSON leaf values accepted in NeMo Flow payloads. +"""Scalar JSON leaf values accepted in NeMo Relay payloads. Description: This alias documents primitive values that can appear inside public diff --git a/python/nemo_flow/_native.pyi b/python/nemo_relay/_native.pyi similarity index 99% rename from python/nemo_flow/_native.pyi rename to python/nemo_relay/_native.pyi index 5b8917efe..5262919df 100644 --- a/python/nemo_flow/_native.pyi +++ b/python/nemo_relay/_native.pyi @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Stubs for the compiled ``nemo_flow._native`` extension module. +"""Stubs for the compiled ``nemo_relay._native`` extension module. Summary: Type and documentation surface for the compiled Rust extension. @@ -847,7 +847,7 @@ class OpenTelemetryConfig: ... class OpenTelemetrySubscriber: - """OpenTelemetry-backed NeMo Flow event subscriber. + """OpenTelemetry-backed NeMo Relay event subscriber. Summary: Native subscriber that exports lifecycle events as OpenTelemetry spans. @@ -919,7 +919,7 @@ class OpenInferenceConfig: ... class OpenInferenceSubscriber: - """OpenInference-backed NeMo Flow event subscriber. + """OpenInference-backed NeMo Relay event subscriber. Summary: Native subscriber that exports lifecycle events as OpenInference spans. diff --git a/python/nemo_flow/adaptive.py b/python/nemo_relay/adaptive.py similarity index 96% rename from python/nemo_flow/adaptive.py rename to python/nemo_relay/adaptive.py index 180c35097..e4f375457 100644 --- a/python/nemo_flow/adaptive.py +++ b/python/nemo_relay/adaptive.py @@ -4,7 +4,7 @@ """Adaptive plugin configuration helpers. Adaptive is configured as a single flat top-level plugin component. Hosted -plugins remain separate top-level components managed through ``nemo_flow.plugin``. +plugins remain separate top-level components managed through ``nemo_relay.plugin``. """ from __future__ import annotations @@ -12,11 +12,11 @@ from dataclasses import dataclass, field, fields, is_dataclass from typing import Literal, Protocol, TypedDict, cast -from nemo_flow import Json, JsonObject, UnsupportedBehavior -from nemo_flow._native import AdaptiveRuntime as AdaptiveRuntime -from nemo_flow._native import build_cache_telemetry_event as _build_cache_telemetry_event -from nemo_flow._native import set_latency_sensitivity as _set_latency_sensitivity -from nemo_flow._native import validate_adaptive_config as _validate_adaptive_config +from nemo_relay import Json, JsonObject, UnsupportedBehavior +from nemo_relay._native import AdaptiveRuntime as AdaptiveRuntime +from nemo_relay._native import build_cache_telemetry_event as _build_cache_telemetry_event +from nemo_relay._native import set_latency_sensitivity as _set_latency_sensitivity +from nemo_relay._native import validate_adaptive_config as _validate_adaptive_config class _ConfigDiagnosticRequired(TypedDict): @@ -103,7 +103,7 @@ def in_memory() -> "BackendSpec": return BackendSpec(kind="in_memory") @staticmethod - def redis(url: str, key_prefix: str = "nemo_flow:") -> "BackendSpec": + def redis(url: str, key_prefix: str = "nemo_relay:") -> "BackendSpec": """Return a Redis adaptive backend spec.""" return BackendSpec(kind="redis", config={"url": url, "key_prefix": key_prefix}) diff --git a/python/nemo_flow/adaptive.pyi b/python/nemo_relay/adaptive.pyi similarity index 96% rename from python/nemo_flow/adaptive.pyi rename to python/nemo_relay/adaptive.pyi index 1fbc067be..892f7260b 100644 --- a/python/nemo_flow/adaptive.pyi +++ b/python/nemo_relay/adaptive.pyi @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Type stubs for ``nemo_flow.adaptive``. +"""Type stubs for ``nemo_relay.adaptive``. This module exposes the canonical adaptive configuration helpers, the ``AdaptiveRuntime`` bridge used by external integrations, and cache-telemetry @@ -11,7 +11,7 @@ helpers that summarize ACG observations into structured JSON payloads. from dataclasses import dataclass from typing import Literal, TypedDict -from nemo_flow import JsonObject, ScopeHandle, UnsupportedBehavior +from nemo_relay import JsonObject, ScopeHandle, UnsupportedBehavior class ConfigDiagnostic(TypedDict, total=False): """One adaptive configuration diagnostic. @@ -232,7 +232,7 @@ class AdaptiveRuntime: """Hosted adaptive runtime wrapper used by external framework integrations. ``AdaptiveRuntime`` validates and stores one adaptive config, registers the - configured adaptive features into the shared NeMo Flow runtime, and exposes + configured adaptive features into the shared NeMo Relay runtime, and exposes helpers that depend on the runtime's hot cache and registered agent identity. """ @@ -242,7 +242,7 @@ class AdaptiveRuntime: ... async def register(self) -> None: - """Register the configured adaptive features with NeMo Flow.""" + """Register the configured adaptive features with NeMo Relay.""" ... def deregister(self) -> None: @@ -265,7 +265,7 @@ class AdaptiveRuntime: """Bind this runtime's ACG request rewriting to an active scope. After binding, requests emitted under ``scope_handle`` can explicitly - call ``nemo_flow.llm.request_intercepts(...)`` to apply the runtime's + call ``nemo_relay.llm.request_intercepts(...)`` to apply the runtime's provider-native ACG rewrite path. """ ... diff --git a/python/nemo_flow/codecs.py b/python/nemo_relay/codecs.py similarity index 87% rename from python/nemo_flow/codecs.py rename to python/nemo_relay/codecs.py index 80c11f8d5..7e9877fb6 100644 --- a/python/nemo_flow/codecs.py +++ b/python/nemo_relay/codecs.py @@ -1,19 +1,19 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Protocol definitions for request and response codecs used by ``nemo_flow.llm``. +"""Protocol definitions for request and response codecs used by ``nemo_relay.llm``. ``LlmCodec`` is used for request-side translation. It lets intercepts work against ``AnnotatedLLMRequest`` instead of provider-specific raw payloads. -``LlmResponseCodec`` is used for response-side translation. It lets NeMo Flow attach +``LlmResponseCodec`` is used for response-side translation. It lets NeMo Relay attach an ``AnnotatedLLMResponse`` to emitted ``LLMEnd`` events without changing the return value of ``llm.execute()`` or ``llm.stream_execute()``. Example:: - from nemo_flow import AnnotatedLLMRequest, LLMRequest, llm - from nemo_flow.codecs import LlmCodec, OpenAIChatCodec + from nemo_relay import AnnotatedLLMRequest, LLMRequest, llm + from nemo_relay.codecs import LlmCodec, OpenAIChatCodec class DemoCodec(LlmCodec): def decode(self, request: LLMRequest) -> AnnotatedLLMRequest: @@ -43,8 +43,8 @@ async def impl(request: LLMRequest): from typing import TYPE_CHECKING, Protocol, runtime_checkable -from nemo_flow import Json -from nemo_flow._native import ( +from nemo_relay import Json +from nemo_relay._native import ( AnnotatedLLMRequest, AnthropicMessagesCodec, LLMRequest, @@ -53,7 +53,7 @@ async def impl(request: LLMRequest): ) if TYPE_CHECKING: - from nemo_flow._native import AnnotatedLLMResponse + from nemo_relay._native import AnnotatedLLMResponse @runtime_checkable @@ -73,8 +73,8 @@ class LlmCodec(Protocol): Example:: - from nemo_flow import AnnotatedLLMRequest, LLMRequest - from nemo_flow.codecs import LlmCodec + from nemo_relay import AnnotatedLLMRequest, LLMRequest + from nemo_relay.codecs import LlmCodec class DemoCodec(LlmCodec): def decode(self, request: LLMRequest) -> AnnotatedLLMRequest: @@ -99,7 +99,7 @@ def decode(self, request: LLMRequest) -> AnnotatedLLMRequest: Args: request: The provider-specific request payload received by - ``nemo_flow.llm.execute()`` or ``nemo_flow.llm.stream_execute()``. + ``nemo_relay.llm.execute()`` or ``nemo_relay.llm.stream_execute()``. Returns: AnnotatedLLMRequest: The normalized request consumed by annotated @@ -134,13 +134,13 @@ class LlmResponseCodec(Protocol): Example:: - import nemo_flow + import nemo_relay - result = await nemo_flow.llm.execute( + result = await nemo_relay.llm.execute( "demo-provider", - nemo_flow.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), + nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), impl, - response_codec=nemo_flow.codecs.OpenAIChatCodec(), + response_codec=nemo_relay.codecs.OpenAIChatCodec(), ) """ diff --git a/python/nemo_flow/codecs.pyi b/python/nemo_relay/codecs.pyi similarity index 98% rename from python/nemo_flow/codecs.pyi rename to python/nemo_relay/codecs.pyi index b45f1f586..5bb540295 100644 --- a/python/nemo_flow/codecs.pyi +++ b/python/nemo_relay/codecs.pyi @@ -3,7 +3,7 @@ from typing import Protocol, runtime_checkable -from nemo_flow import AnnotatedLLMRequest, AnnotatedLLMResponse, Json, LLMRequest +from nemo_relay import AnnotatedLLMRequest, AnnotatedLLMResponse, Json, LLMRequest @runtime_checkable class LlmCodec(Protocol): diff --git a/python/nemo_flow/guardrails.py b/python/nemo_relay/guardrails.py similarity index 91% rename from python/nemo_flow/guardrails.py rename to python/nemo_relay/guardrails.py index e194c0678..478fcdde1 100644 --- a/python/nemo_flow/guardrails.py +++ b/python/nemo_relay/guardrails.py @@ -12,55 +12,55 @@ Example:: - import nemo_flow + import nemo_relay def redact(tool_name, args): return {**args, "api_key": "***"} - nemo_flow.guardrails.register_tool_sanitize_request("redact", 10, redact) + nemo_relay.guardrails.register_tool_sanitize_request("redact", 10, redact) """ -from nemo_flow import ( +from nemo_relay import ( LlmConditionalExecutionGuardrail, LlmSanitizeRequestGuardrail, LlmSanitizeResponseGuardrail, ToolConditionalExecutionGuardrail, ToolSanitizeGuardrail, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_conditional_execution_guardrail as _native_deregister_llm_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_sanitize_request_guardrail as _native_deregister_llm_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_sanitize_response_guardrail as _native_deregister_llm_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_tool_conditional_execution_guardrail as _native_deregister_tool_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_tool_sanitize_request_guardrail as _native_deregister_tool_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_tool_sanitize_response_guardrail as _native_deregister_tool_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_conditional_execution_guardrail as _native_register_llm_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_sanitize_request_guardrail as _native_register_llm_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_sanitize_response_guardrail as _native_register_llm_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_tool_conditional_execution_guardrail as _native_register_tool_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_tool_sanitize_request_guardrail as _native_register_tool_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_tool_sanitize_response_guardrail as _native_register_tool_sanitize_response, ) @@ -82,18 +82,18 @@ def register_tool_sanitize_request(name: str, priority: int, guardrail: ToolSani None: This function returns after the guardrail is registered. Notes: - In managed ``nemo_flow.tools.execute()`` flows, sanitize guardrails are + In managed ``nemo_relay.tools.execute()`` flows, sanitize guardrails are observability-only. They change the payload written to events, not the arguments passed to the tool callback. Example:: - import nemo_flow + import nemo_relay def redact(tool_name, args): return {**args, "api_key": "***"} - nemo_flow.guardrails.register_tool_sanitize_request("redact", 10, redact) + nemo_relay.guardrails.register_tool_sanitize_request("redact", 10, redact) """ return _native_register_tool_sanitize_request(name, priority, guardrail) @@ -205,19 +205,19 @@ def register_llm_sanitize_request(name: str, priority: int, guardrail: LlmSaniti None: This function returns after the guardrail is registered. Notes: - In managed ``nemo_flow.llm.execute()`` and - ``nemo_flow.llm.stream_execute()`` flows, this is observability-only + In managed ``nemo_relay.llm.execute()`` and + ``nemo_relay.llm.stream_execute()`` flows, this is observability-only and does not mutate the request forwarded to the provider callback. Example:: - import nemo_flow + import nemo_relay def strip_auth(request): headers = {k: v for k, v in request.headers.items() if k.lower() != "authorization"} - return nemo_flow.LLMRequest(headers, request.content) + return nemo_relay.LLMRequest(headers, request.content) - nemo_flow.guardrails.register_llm_sanitize_request("strip-auth", 10, strip_auth) + nemo_relay.guardrails.register_llm_sanitize_request("strip-auth", 10, strip_auth) """ return _native_register_llm_sanitize_request(name, priority, guardrail) diff --git a/python/nemo_flow/integrations/__init__.py b/python/nemo_relay/integrations/__init__.py similarity index 75% rename from python/nemo_flow/integrations/__init__.py rename to python/nemo_relay/integrations/__init__.py index 63e758869..c75525e45 100644 --- a/python/nemo_flow/integrations/__init__.py +++ b/python/nemo_relay/integrations/__init__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Optional integrations for NeMo Flow.""" +"""Optional integrations for NeMo Relay.""" diff --git a/python/nemo_flow/integrations/deepagents/__init__.py b/python/nemo_relay/integrations/deepagents/__init__.py similarity index 81% rename from python/nemo_flow/integrations/deepagents/__init__.py rename to python/nemo_relay/integrations/deepagents/__init__.py index 5be91048b..043187808 100644 --- a/python/nemo_flow/integrations/deepagents/__init__.py +++ b/python/nemo_relay/integrations/deepagents/__init__.py @@ -1,27 +1,27 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""NeMo Flow integrations for Deep Agents.""" +"""NeMo Relay integrations for Deep Agents.""" from __future__ import annotations from collections.abc import Mapping, Sequence from typing import Any -from nemo_flow.integrations.deepagents.callbacks import NemoFlowDeepAgentsCallbackHandler -from nemo_flow.integrations.deepagents.middleware import NemoFlowDeepAgentsMiddleware +from nemo_relay.integrations.deepagents.callbacks import NemoRelayDeepAgentsCallbackHandler +from nemo_relay.integrations.deepagents.middleware import NemoRelayDeepAgentsMiddleware -def add_nemo_flow_integration( +def add_nemo_relay_integration( kwargs: Mapping[str, Any] | None = None, *, instrument_subagents: bool = True, **overrides: Any, ) -> dict[str, Any]: """ - Receives the keyword arguments for ``create_deep_agent`` and returns them with NeMo Flow observability attached. + Receives the keyword arguments for ``create_deep_agent`` and returns them with NeMo Relay observability attached. - Use this helper as ``create_deep_agent(**add_nemo_flow_integration(...))``. + Use this helper as ``create_deep_agent(**add_nemo_relay_integration(...))``. It injects Deep Agents-aware middleware at the top level, adds the same middleware to dictionary-style custom subagents that do not inherit parent middleware, and leaves any provided backend unchanged. @@ -38,7 +38,7 @@ def add_nemo_flow_integration( middleware = list(observed.get("middleware") or ()) _append_middleware( middleware, - NemoFlowDeepAgentsMiddleware( + NemoRelayDeepAgentsMiddleware( agent_name=observed.get("name"), skills=skills, subagents=subagent_summaries, @@ -53,8 +53,8 @@ def add_nemo_flow_integration( return observed -def _append_middleware(middleware: list[Any], new_middleware: NemoFlowDeepAgentsMiddleware) -> None: - if any(isinstance(item, NemoFlowDeepAgentsMiddleware) for item in middleware): +def _append_middleware(middleware: list[Any], new_middleware: NemoRelayDeepAgentsMiddleware) -> None: + if any(isinstance(item, NemoRelayDeepAgentsMiddleware) for item in middleware): return middleware.append(new_middleware) @@ -67,7 +67,7 @@ def _instrument_subagent(subagent: Any) -> Any: middleware = list(observed.get("middleware") or ()) _append_middleware( middleware, - NemoFlowDeepAgentsMiddleware( + NemoRelayDeepAgentsMiddleware( agent_name=observed.get("name"), skills=_string_sequence(observed.get("skills")), subagents=None, @@ -107,7 +107,7 @@ def _string_sequence(value: Any) -> Sequence[str] | None: __all__ = [ - "NemoFlowDeepAgentsCallbackHandler", - "NemoFlowDeepAgentsMiddleware", - "add_nemo_flow_integration", + "NemoRelayDeepAgentsCallbackHandler", + "NemoRelayDeepAgentsMiddleware", + "add_nemo_relay_integration", ] diff --git a/python/nemo_flow/integrations/deepagents/_events.py b/python/nemo_relay/integrations/deepagents/_events.py similarity index 90% rename from python/nemo_flow/integrations/deepagents/_events.py rename to python/nemo_relay/integrations/deepagents/_events.py index 6be73fe83..b682e6ca5 100644 --- a/python/nemo_flow/integrations/deepagents/_events.py +++ b/python/nemo_relay/integrations/deepagents/_events.py @@ -9,7 +9,7 @@ from collections.abc import Mapping, Sequence from typing import Any -import nemo_flow +import nemo_relay _logger = logging.getLogger(__name__) @@ -22,7 +22,7 @@ def event_base_name(kind: str) -> str: }.get(kind, "DeepAgents") -def json_safe(value: Any) -> nemo_flow.Json: +def json_safe(value: Any) -> nemo_relay.Json: """Return a conservative JSON-compatible value.""" if value is None or isinstance(value, str | int | float | bool): return value @@ -53,10 +53,10 @@ def emit_mark( event_metadata.update(metadata) try: - nemo_flow.scope.event( + nemo_relay.scope.event( f"{base_name} {phase.title()}", data=json_safe(data), metadata=json_safe(event_metadata), ) except Exception: - _logger.debug("NeMo Flow: Deep Agents mark emission failed", exc_info=True) + _logger.debug("NeMo Relay: Deep Agents mark emission failed", exc_info=True) diff --git a/python/nemo_flow/integrations/deepagents/callbacks.py b/python/nemo_relay/integrations/deepagents/callbacks.py similarity index 73% rename from python/nemo_flow/integrations/deepagents/callbacks.py rename to python/nemo_relay/integrations/deepagents/callbacks.py index c03384ece..28ae7fa8a 100644 --- a/python/nemo_flow/integrations/deepagents/callbacks.py +++ b/python/nemo_relay/integrations/deepagents/callbacks.py @@ -1,21 +1,21 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Deep Agents callback handler for NeMo Flow observability.""" +"""Deep Agents callback handler for NeMo Relay observability.""" from __future__ import annotations from collections.abc import Mapping, Sequence from typing import Any -from nemo_flow.integrations.deepagents._events import emit_mark, event_base_name -from nemo_flow.integrations.langgraph.callbacks import NemoFlowCallbackHandler as LangGraphNemoFlowCallbackHandler +from nemo_relay.integrations.deepagents._events import emit_mark, event_base_name +from nemo_relay.integrations.langgraph.callbacks import NemoRelayCallbackHandler as LangGraphNemoRelayCallbackHandler _GraphEventKey = tuple[str | None, str | None, tuple[str, ...]] -class NemoFlowDeepAgentsCallbackHandler(LangGraphNemoFlowCallbackHandler): - """Bridge Deep Agents LangGraph lifecycle events to NeMo Flow marks.""" +class NemoRelayDeepAgentsCallbackHandler(LangGraphNemoRelayCallbackHandler): + """Bridge Deep Agents LangGraph lifecycle events to NeMo Relay marks.""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -46,8 +46,8 @@ def _emit_human_in_the_loop_mark(self, name: str, phase: str, data: dict[str, An @staticmethod def _graph_event_key(data: Mapping[str, Any]) -> _GraphEventKey: - run_id = NemoFlowDeepAgentsCallbackHandler._string_or_none(data.get("run_id")) - checkpoint_id = NemoFlowDeepAgentsCallbackHandler._string_or_none(data.get("checkpoint_id")) + run_id = NemoRelayDeepAgentsCallbackHandler._string_or_none(data.get("run_id")) + checkpoint_id = NemoRelayDeepAgentsCallbackHandler._string_or_none(data.get("checkpoint_id")) checkpoint_ns = data.get("checkpoint_ns") if not isinstance(checkpoint_ns, Sequence) or isinstance(checkpoint_ns, str | bytes | bytearray): return (run_id, checkpoint_id, ()) @@ -64,13 +64,13 @@ def _has_hitl_interrupt(data: Mapping[str, Any]) -> bool: interrupts = data.get("interrupts") if not isinstance(interrupts, Sequence) or isinstance(interrupts, str | bytes | bytearray): return False - return any(NemoFlowDeepAgentsCallbackHandler._is_hitl_interrupt_payload(interrupt) for interrupt in interrupts) + return any(NemoRelayDeepAgentsCallbackHandler._is_hitl_interrupt_payload(interrupt) for interrupt in interrupts) @staticmethod def _is_hitl_interrupt_payload(interrupt: Any) -> bool: if not isinstance(interrupt, Mapping): return False - return NemoFlowDeepAgentsCallbackHandler._is_hitl_request(interrupt.get("value")) + return NemoRelayDeepAgentsCallbackHandler._is_hitl_request(interrupt.get("value")) @staticmethod def _is_hitl_request(value: Any) -> bool: @@ -78,9 +78,9 @@ def _is_hitl_request(value: Any) -> bool: return False action_requests = value.get("action_requests") review_configs = value.get("review_configs") - return NemoFlowDeepAgentsCallbackHandler._is_mapping_sequence( + return NemoRelayDeepAgentsCallbackHandler._is_mapping_sequence( action_requests - ) and NemoFlowDeepAgentsCallbackHandler._is_mapping_sequence(review_configs) + ) and NemoRelayDeepAgentsCallbackHandler._is_mapping_sequence(review_configs) @staticmethod def _is_mapping_sequence(value: Any) -> bool: @@ -89,4 +89,4 @@ def _is_mapping_sequence(value: Any) -> bool: return all(isinstance(item, Mapping) for item in value) -__all__ = ["NemoFlowDeepAgentsCallbackHandler"] +__all__ = ["NemoRelayDeepAgentsCallbackHandler"] diff --git a/python/nemo_flow/integrations/deepagents/middleware.py b/python/nemo_relay/integrations/deepagents/middleware.py similarity index 79% rename from python/nemo_flow/integrations/deepagents/middleware.py rename to python/nemo_relay/integrations/deepagents/middleware.py index f87d8acd6..4c5905d6f 100644 --- a/python/nemo_flow/integrations/deepagents/middleware.py +++ b/python/nemo_relay/integrations/deepagents/middleware.py @@ -1,29 +1,29 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Deep Agents middleware for NeMo Flow observability.""" +"""Deep Agents middleware for NeMo Relay observability.""" from __future__ import annotations from collections.abc import Mapping, Sequence from typing import Any -from nemo_flow.integrations.deepagents._events import emit_mark, event_base_name -from nemo_flow.integrations.langchain.middleware import NemoFlowMiddleware +from nemo_relay.integrations.deepagents._events import emit_mark, event_base_name +from nemo_relay.integrations.langchain.middleware import NemoRelayMiddleware -class NemoFlowDeepAgentsMiddleware(NemoFlowMiddleware): - """Route Deep Agents model/tool calls through NeMo Flow and emit semantic events. +class NemoRelayDeepAgentsMiddleware(NemoRelayMiddleware): + """Route Deep Agents model/tool calls through NeMo Relay and emit semantic events. Deep Agents is built on LangChain ``AgentMiddleware`` and LangGraph. This - middleware keeps the existing NeMo Flow LangChain wrapping behavior, then + middleware keeps the existing NeMo Relay LangChain wrapping behavior, then emits Deep Agents configuration marks. """ def __init__( self, *, - name: str = "NemoFlowDeepAgentsMiddleware", + name: str = "NemoRelayDeepAgentsMiddleware", agent_name: str | None = None, skills: Sequence[str] | None = None, subagents: Sequence[Mapping[str, Any]] | None = None, diff --git a/python/nemo_relay/integrations/langchain/__init__.py b/python/nemo_relay/integrations/langchain/__init__.py new file mode 100644 index 000000000..dabc39cf6 --- /dev/null +++ b/python/nemo_relay/integrations/langchain/__init__.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""NeMo Relay integrations for LangChain.""" + +from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler +from nemo_relay.integrations.langchain.middleware import NemoRelayMiddleware + +__all__ = [ + "NemoRelayCallbackHandler", + "NemoRelayMiddleware", +] diff --git a/python/nemo_flow/integrations/langchain/_serialization.py b/python/nemo_relay/integrations/langchain/_serialization.py similarity index 92% rename from python/nemo_flow/integrations/langchain/_serialization.py rename to python/nemo_relay/integrations/langchain/_serialization.py index 0c13ec7d3..d5d95b0ed 100644 --- a/python/nemo_flow/integrations/langchain/_serialization.py +++ b/python/nemo_relay/integrations/langchain/_serialization.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""LangChain request/response conversion helpers for NeMo Flow middleware.""" +"""LangChain request/response conversion helpers for NeMo Relay middleware.""" from __future__ import annotations @@ -17,7 +17,7 @@ ) from langgraph.types import Command, Send -from nemo_flow.codecs import AnthropicMessagesCodec, LlmCodec, OpenAIChatCodec, OpenAIResponsesCodec +from nemo_relay.codecs import AnthropicMessagesCodec, LlmCodec, OpenAIChatCodec, OpenAIResponsesCodec if TYPE_CHECKING: from langchain.agents.middleware import ModelRequest @@ -49,7 +49,7 @@ except ImportError: pass -LANGCHAIN_MODEL_RESPONSE_KEY = "__nemo_flow_integrations_langchain_model_response" +LANGCHAIN_MODEL_RESPONSE_KEY = "__nemo_relay_integrations_langchain_model_response" def get_model_name(model: Any) -> str | None: @@ -62,7 +62,7 @@ def get_model_name(model: Any) -> str | None: def infer_codec_from_model(model: Any) -> LlmCodec | None: - """Infer a NeMo Flow codec name from a LangChain chat model.""" + """Infer a NeMo Relay codec name from a LangChain chat model.""" if _HAS_ANTHROPIC: if isinstance(model, ChatAnthropic): return AnthropicMessagesCodec() @@ -111,7 +111,7 @@ def payload_to_model_request( original: ModelRequest[Any], payload: dict[str, Any], ) -> ModelRequest[Any]: - """Apply supported NeMo Flow request-intercept edits back to ``ModelRequest``.""" + """Apply supported NeMo Relay request-intercept edits back to ``ModelRequest``.""" overrides: dict[str, Any] = {} raw_messages = payload.get("messages") @@ -175,11 +175,11 @@ def model_response_from_json(payload: Any, codec: Any) -> ModelResponse[Any]: decoded = codec.from_json(payload) if isinstance(decoded, ModelResponse): return decoded - raise TypeError(f"NeMo Flow model execution returned {type(decoded)!r}, expected ModelResponse") + raise TypeError(f"NeMo Relay model execution returned {type(decoded)!r}, expected ModelResponse") def _prepare_outputs(outputs: Any) -> Any: - """Prepare a NeMo Flow scope output dict for returning to LangChain.""" + """Prepare a NeMo Relay scope output dict for returning to LangChain.""" if isinstance(outputs, dict): prepared_outputs = {} for key, value in outputs.items(): diff --git a/python/nemo_flow/integrations/langchain/callbacks.py b/python/nemo_relay/integrations/langchain/callbacks.py similarity index 76% rename from python/nemo_flow/integrations/langchain/callbacks.py rename to python/nemo_relay/integrations/langchain/callbacks.py index bba0e36cd..d4780762c 100644 --- a/python/nemo_flow/integrations/langchain/callbacks.py +++ b/python/nemo_relay/integrations/langchain/callbacks.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""LangChain callback handler that maps run hierarchy to NeMo Flow scopes.""" +"""LangChain callback handler that maps run hierarchy to NeMo Relay scopes.""" from __future__ import annotations @@ -10,8 +10,8 @@ from langchain_core.callbacks.base import BaseCallbackHandler -import nemo_flow -from nemo_flow.integrations.langchain._serialization import _prepare_outputs +import nemo_relay +from nemo_relay.integrations.langchain._serialization import _prepare_outputs if typing.TYPE_CHECKING: from uuid import UUID @@ -19,8 +19,8 @@ _logger = logging.getLogger(__name__) -class NemoFlowCallbackHandler(BaseCallbackHandler): - """Bridge LangChain chain run IDs to NeMo Flow Agent scopes.""" +class NemoRelayCallbackHandler(BaseCallbackHandler): + """Bridge LangChain chain run IDs to NeMo Relay Agent scopes.""" # We need to run inline to ensure scopes are pushed and popped in the correct order. run_inline = True @@ -40,7 +40,7 @@ def on_chain_start( metadata: dict[str, typing.Any] | None = None, **kwargs: typing.Any, ) -> typing.Any: - """Push a NeMo Flow Agent scope for a LangChain chain run.""" + """Push a NeMo Relay Agent scope for a LangChain chain run.""" try: name = kwargs.get("name") @@ -58,16 +58,16 @@ def on_chain_start( scope_metadata = metadata.copy() if metadata else {} scope_metadata["langchain_run_id"] = str(run_id) - handle = nemo_flow.scope.push( + handle = nemo_relay.scope.push( name, - nemo_flow.ScopeType.Agent, + nemo_relay.ScopeType.Agent, handle=parent, input=inputs, metadata=scope_metadata, ) self._scope_handles[run_id] = handle except Exception: - _logger.debug("NeMo Flow: on_chain_start failed", exc_info=True) + _logger.debug("NeMo Relay: on_chain_start failed", exc_info=True) return None def on_chain_end( @@ -78,7 +78,7 @@ def on_chain_end( parent_run_id: UUID | None = None, **kwargs: typing.Any, ) -> typing.Any: - """Pop the NeMo Flow scope associated with a LangChain chain run.""" + """Pop the NeMo Relay scope associated with a LangChain chain run.""" self._pop_scope(run_id, output=outputs) return None @@ -90,7 +90,7 @@ def on_chain_error( parent_run_id: UUID | None = None, **kwargs: typing.Any, ) -> typing.Any: - """Pop the NeMo Flow scope associated with a failed LangChain chain run.""" + """Pop the NeMo Relay scope associated with a failed LangChain chain run.""" self._pop_scope(run_id, output={"error": repr(error)}) return None @@ -100,6 +100,6 @@ def _pop_scope(self, run_id: UUID, *, output: dict[str, typing.Any] | None = Non return try: prepared_outputs = _prepare_outputs(output) if output is not None else None - nemo_flow.scope.pop(handle, output=prepared_outputs) + nemo_relay.scope.pop(handle, output=prepared_outputs) except Exception: - _logger.warning("NeMo Flow: scope.pop failed", exc_info=True) + _logger.warning("NeMo Relay: scope.pop failed", exc_info=True) diff --git a/python/nemo_flow/integrations/langchain/middleware.py b/python/nemo_relay/integrations/langchain/middleware.py similarity index 79% rename from python/nemo_flow/integrations/langchain/middleware.py rename to python/nemo_relay/integrations/langchain/middleware.py index b00f096a2..5ff53eb8b 100644 --- a/python/nemo_flow/integrations/langchain/middleware.py +++ b/python/nemo_relay/integrations/langchain/middleware.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""LangChain AgentMiddleware implementation for NeMo Flow.""" +"""LangChain AgentMiddleware implementation for NeMo Relay.""" from __future__ import annotations @@ -10,8 +10,8 @@ from langchain.agents.middleware import AgentMiddleware -import nemo_flow -from nemo_flow.integrations.langchain._serialization import ( +import nemo_relay +from nemo_relay.integrations.langchain._serialization import ( get_model_name, infer_codec_from_model, model_request_to_payload, @@ -19,18 +19,18 @@ model_response_to_json, payload_to_model_request, ) -from nemo_flow.utils import run_sync +from nemo_relay.utils import run_sync if TYPE_CHECKING: from langchain.agents.middleware import ModelRequest, ModelResponse, ToolCallRequest from langchain_core.messages import ToolMessage from langgraph.types import Command - from nemo_flow.codecs import LlmCodec, LlmResponseCodec + from nemo_relay.codecs import LlmCodec, LlmResponseCodec -class NemoFlowMiddleware(AgentMiddleware): - """Route LangChain agent model and tool calls through NeMo Flow. +class NemoRelayMiddleware(AgentMiddleware): + """Route LangChain agent model and tool calls through NeMo Relay. This uses LangChain's public ``AgentMiddleware`` hooks. It applies to agents built with ``langchain.agents.create_agent(..., middleware=[...])``. @@ -39,7 +39,7 @@ class NemoFlowMiddleware(AgentMiddleware): def __init__( self, *, - name: str = "NemoFlowMiddleware", + name: str = "NemoRelayMiddleware", ) -> None: super().__init__() self._name = name @@ -52,13 +52,13 @@ def name(self) -> str: async def _llm_execute( self, model_name: str, - request: nemo_flow.LLMRequest, + request: nemo_relay.LLMRequest, codec: LlmCodec | None, response_codec: LlmResponseCodec | None, func: Callable[..., Any], ) -> Any: - """Execute a non-streaming LLM call through the NeMo Flow pipeline.""" - return await nemo_flow.llm.execute( + """Execute a non-streaming LLM call through the NeMo Relay pipeline.""" + return await nemo_relay.llm.execute( model_name, request, func, @@ -69,9 +69,9 @@ async def _llm_execute( def _prepare_model_call(self, request: ModelRequest[Any]) -> tuple: """Boilerplate code common to both wrap_model_call and awrap_model_call""" - object_codec = nemo_flow.typed.BestEffortAnyCodec() + object_codec = nemo_relay.typed.BestEffortAnyCodec() model_name = get_model_name(request.model) - llm_request = nemo_flow.LLMRequest({}, model_request_to_payload(model_name, request)) + llm_request = nemo_relay.LLMRequest({}, model_request_to_payload(model_name, request)) model_codec = infer_codec_from_model(request.model) return (object_codec, llm_request, model_name, model_codec) @@ -80,7 +80,7 @@ def wrap_model_call( request: ModelRequest[Any], handler: Callable[[ModelRequest[Any]], ModelResponse[Any]], ) -> ModelResponse[Any]: - """Wrap a sync LangChain agent model call in NeMo Flow LLM execution.""" + """Wrap a sync LangChain agent model call in NeMo Relay LLM execution.""" (object_codec, llm_request, model_name, model_codec) = self._prepare_model_call(request) async def _call(req: Any) -> Any: @@ -103,7 +103,7 @@ async def awrap_model_call( request: ModelRequest[Any], handler: Callable[[ModelRequest[Any]], Awaitable[ModelResponse[Any]]], ) -> ModelResponse[Any]: - """Wrap an async LangChain agent model call in NeMo Flow LLM execution.""" + """Wrap an async LangChain agent model call in NeMo Relay LLM execution.""" (object_codec, llm_request, model_name, model_codec) = self._prepare_model_call(request) async def _call(req: Any) -> Any: @@ -121,8 +121,8 @@ async def _call(req: Any) -> Any: def _prepare_tool_call(self, request: ToolCallRequest) -> tuple: """Boilerplate code common to both wrap_tool_call and awrap_tool_call""" - parent = nemo_flow.scope.get_handle() - codec = nemo_flow.typed.BestEffortAnyCodec() + parent = nemo_relay.scope.get_handle() + codec = nemo_relay.typed.BestEffortAnyCodec() tool_name = request.tool_call["name"] tool_args = request.tool_call.get("args") or {} return (parent, codec, tool_name, tool_args) @@ -132,7 +132,7 @@ def wrap_tool_call( request: ToolCallRequest, handler: Callable[[ToolCallRequest], ToolMessage | Command[Any]], ) -> ToolMessage | Command[Any]: - """Wrap a sync LangChain agent tool call in NeMo Flow tool execution.""" + """Wrap a sync LangChain agent tool call in NeMo Relay tool execution.""" (parent, codec, tool_name, tool_args) = self._prepare_tool_call(request) @@ -140,7 +140,7 @@ def _call(args: Any) -> ToolMessage | Command[Any]: return handler(request.override(tool_call={**request.tool_call, "args": args})) return run_sync( - nemo_flow.typed.tool_execute( + nemo_relay.typed.tool_execute( name=tool_name, args=tool_args, func=_call, args_codec=codec, result_codec=codec, handle=parent ) ) @@ -150,13 +150,13 @@ async def awrap_tool_call( request: ToolCallRequest, handler: Callable[[ToolCallRequest], Awaitable[ToolMessage | Command[Any]]], ) -> ToolMessage | Command[Any]: - """Wrap an async LangChain agent tool call in NeMo Flow tool execution.""" + """Wrap an async LangChain agent tool call in NeMo Relay tool execution.""" (parent, codec, tool_name, tool_args) = self._prepare_tool_call(request) async def _call(args: Any) -> ToolMessage | Command[Any]: return await handler(request.override(tool_call={**request.tool_call, "args": args})) - return await nemo_flow.typed.tool_execute( + return await nemo_relay.typed.tool_execute( name=tool_name, args=tool_args, func=_call, args_codec=codec, result_codec=codec, handle=parent ) diff --git a/python/nemo_relay/integrations/langgraph/__init__.py b/python/nemo_relay/integrations/langgraph/__init__.py new file mode 100644 index 000000000..79c021c4c --- /dev/null +++ b/python/nemo_relay/integrations/langgraph/__init__.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""NeMo Relay integrations for LangGraph.""" + +from nemo_relay.integrations.langchain import NemoRelayMiddleware +from nemo_relay.integrations.langgraph.callbacks import NemoRelayCallbackHandler + +__all__ = [ + "NemoRelayCallbackHandler", + "NemoRelayMiddleware", +] diff --git a/python/nemo_flow/integrations/langgraph/callbacks.py b/python/nemo_relay/integrations/langgraph/callbacks.py similarity index 72% rename from python/nemo_flow/integrations/langgraph/callbacks.py rename to python/nemo_relay/integrations/langgraph/callbacks.py index 6c069a19c..9429b8ab1 100644 --- a/python/nemo_flow/integrations/langgraph/callbacks.py +++ b/python/nemo_relay/integrations/langgraph/callbacks.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""LangGraph callback handler that reuses the LangChain NeMo Flow integration.""" +"""LangGraph callback handler that reuses the LangChain NeMo Relay integration.""" from __future__ import annotations @@ -10,14 +10,14 @@ from langgraph.callbacks import GraphCallbackHandler, GraphInterruptEvent, GraphResumeEvent -import nemo_flow -from nemo_flow.integrations.langchain._serialization import _prepare_outputs -from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler as LangChainNemoFlowCallbackHandler +import nemo_relay +from nemo_relay.integrations.langchain._serialization import _prepare_outputs +from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler as LangChainNemoRelayCallbackHandler _logger = logging.getLogger(__name__) -def _json_safe(value: Any) -> nemo_flow.Json: +def _json_safe(value: Any) -> nemo_relay.Json: """Return a conservative JSON-compatible representation for mark payloads.""" try: value = _prepare_outputs(value) @@ -33,16 +33,16 @@ def _json_safe(value: Any) -> nemo_flow.Json: return repr(value) -def _interrupt_to_payload(interrupt: Any) -> dict[str, nemo_flow.Json]: +def _interrupt_to_payload(interrupt: Any) -> dict[str, nemo_relay.Json]: return { "id": _json_safe(getattr(interrupt, "id", None)), "value": _json_safe(getattr(interrupt, "value", interrupt)), } -class NemoFlowCallbackHandler(LangChainNemoFlowCallbackHandler, GraphCallbackHandler): +class NemoRelayCallbackHandler(LangChainNemoRelayCallbackHandler, GraphCallbackHandler): """ - Bridge LangChain and LangGraph runs to NeMo Flow using public callback APIs. + Bridge LangChain and LangGraph runs to NeMo Relay using public callback APIs. This handler inherits the existing LangChain callback integration, so normal runnable scopes from LangGraph and LangChain are recorded by the same code @@ -51,7 +51,7 @@ class NemoFlowCallbackHandler(LangChainNemoFlowCallbackHandler, GraphCallbackHan """ def on_interrupt(self, event: GraphInterruptEvent) -> Any: - """Emit a NeMo Flow mark for a LangGraph interrupt lifecycle event.""" + """Emit a NeMo Relay mark for a LangGraph interrupt lifecycle event.""" self._emit_graph_mark( "Graph Interrupt", { @@ -65,7 +65,7 @@ def on_interrupt(self, event: GraphInterruptEvent) -> Any: return None def on_resume(self, event: GraphResumeEvent) -> Any: - """Emit a NeMo Flow mark for a LangGraph resume lifecycle event.""" + """Emit a NeMo Relay mark for a LangGraph resume lifecycle event.""" self._emit_graph_mark( "Graph Resume", { @@ -79,13 +79,13 @@ def on_resume(self, event: GraphResumeEvent) -> Any: def _emit_graph_mark(self, name: str, data: dict[str, Any]) -> None: try: - nemo_flow.scope.event( + nemo_relay.scope.event( name, data=_json_safe(data), metadata={"integration": "langgraph"}, ) except Exception: - _logger.debug("NeMo Flow: LangGraph mark emission failed", exc_info=True) + _logger.debug("NeMo Relay: LangGraph mark emission failed", exc_info=True) -__all__ = ["NemoFlowCallbackHandler"] +__all__ = ["NemoRelayCallbackHandler"] diff --git a/python/nemo_flow/intercepts.py b/python/nemo_relay/intercepts.py similarity index 94% rename from python/nemo_flow/intercepts.py rename to python/nemo_relay/intercepts.py index ad6d1772e..294ac7b38 100644 --- a/python/nemo_flow/intercepts.py +++ b/python/nemo_relay/intercepts.py @@ -8,50 +8,50 @@ Example:: - import nemo_flow + import nemo_relay def add_header(name, request, annotated): request.headers["X-Trace"] = "demo" return request, annotated - nemo_flow.intercepts.register_llm_request("trace-header", 10, False, add_header) + nemo_relay.intercepts.register_llm_request("trace-header", 10, False, add_header) """ -from nemo_flow import ( +from nemo_relay import ( LlmExecutionIntercept, LlmRequestIntercept, LlmStreamExecutionIntercept, ToolExecutionIntercept, ToolRequestIntercept, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_execution_intercept as _native_deregister_llm_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_request_intercept as _native_deregister_llm_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_llm_stream_execution_intercept as _native_deregister_llm_stream_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_tool_execution_intercept as _native_deregister_tool_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_tool_request_intercept as _native_deregister_tool_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_execution_intercept as _native_register_llm_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_request_intercept as _native_register_llm_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_llm_stream_execution_intercept as _native_register_llm_stream_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_tool_execution_intercept as _native_register_tool_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_tool_request_intercept as _native_register_tool_request, ) @@ -80,12 +80,12 @@ def register_tool_request(name: str, priority: int, break_chain: bool, fn: ToolR Example:: - import nemo_flow + import nemo_relay def add_trace_id(tool_name, args): return {**args, "trace_id": "req-123"} - nemo_flow.intercepts.register_tool_request( + nemo_relay.intercepts.register_tool_request( "trace-id", 10, False, @@ -175,13 +175,13 @@ def register_llm_request(name: str, priority: int, break_chain: bool, fn: LlmReq Example:: - import nemo_flow + import nemo_relay def add_header(name, request, annotated): request.headers["X-Trace"] = "req-123" return request, annotated - nemo_flow.intercepts.register_llm_request( + nemo_relay.intercepts.register_llm_request( "trace-header", 10, False, diff --git a/python/nemo_flow/llm.py b/python/nemo_relay/llm.py similarity index 91% rename from python/nemo_flow/llm.py rename to python/nemo_relay/llm.py index fba23bcb9..a99724593 100644 --- a/python/nemo_flow/llm.py +++ b/python/nemo_relay/llm.py @@ -3,15 +3,15 @@ """LLM lifecycle helpers for non-streaming and streaming calls. -This module is the LLM analogue of ``nemo_flow.tools``. It manages emitted +This module is the LLM analogue of ``nemo_relay.tools``. It manages emitted events, global middleware, optional request codecs for annotated intercepts, and optional response codecs for structured end-event annotations. Example:: - import nemo_flow + import nemo_relay - request = nemo_flow.LLMRequest( + request = nemo_relay.LLMRequest( {}, {"messages": [{"role": "user", "content": "hello"}], "model": "demo-model"}, ) @@ -19,11 +19,11 @@ async def impl(req): return {"id": "r1", "choices": [{"message": {"role": "assistant", "content": "hi"}}]} - result = await nemo_flow.llm.execute( + result = await nemo_relay.llm.execute( "demo-provider", request, impl, - response_codec=nemo_flow.codecs.OpenAIChatCodec(), + response_codec=nemo_relay.codecs.OpenAIChatCodec(), ) """ @@ -33,33 +33,33 @@ async def impl(req): from datetime import datetime from typing import TYPE_CHECKING -from nemo_flow._native import ( +from nemo_relay._native import ( LLMRequest, LlmStream, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_call as _native_llm_call, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_call_end as _native_llm_call_end, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_call_execute as _native_llm_call_execute, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_conditional_execution as _native_llm_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_request_intercepts as _native_llm_request_intercepts, ) -from nemo_flow._native import ( +from nemo_relay._native import ( llm_stream_call_execute as _native_llm_stream_call_execute, ) if TYPE_CHECKING: - from nemo_flow import Json - from nemo_flow._native import AnnotatedLLMResponse - from nemo_flow.codecs import LlmCodec, LlmResponseCodec + from nemo_relay import Json + from nemo_relay._native import AnnotatedLLMResponse + from nemo_relay.codecs import LlmCodec, LlmResponseCodec def call( @@ -100,10 +100,10 @@ def call( Example:: - import nemo_flow + import nemo_relay - request = nemo_flow.LLMRequest({}, {"messages": [], "model": "demo-model"}) - handle = nemo_flow.llm.call( + request = nemo_relay.LLMRequest({}, {"messages": [], "model": "demo-model"}) + handle = nemo_relay.llm.call( "demo-provider", request, handle=None, @@ -112,7 +112,7 @@ def call( metadata={"path": "manual"}, model_name="demo-model", ) - nemo_flow.llm.call_end( + nemo_relay.llm.call_end( handle, {"ok": True}, data={"cached": False}, @@ -233,9 +233,9 @@ def execute( Example:: - import nemo_flow + import nemo_relay - request = nemo_flow.LLMRequest( + request = nemo_relay.LLMRequest( {}, {"messages": [{"role": "user", "content": "hi"}], "model": "demo-model"}, ) @@ -243,7 +243,7 @@ def execute( async def impl(req): return {"id": "r1", "choices": [{"message": {"role": "assistant", "content": "hello"}}]} - result = await nemo_flow.llm.execute( + result = await nemo_relay.llm.execute( "demo-provider", request, impl, @@ -253,7 +253,7 @@ async def impl(req): metadata={"request_id": "req-1"}, model_name="demo-model", codec=None, - response_codec=nemo_flow.codecs.OpenAIChatCodec(), + response_codec=nemo_relay.codecs.OpenAIChatCodec(), ) """ return _native_llm_call_execute( @@ -318,9 +318,9 @@ def stream_execute( Example:: - import nemo_flow + import nemo_relay - request = nemo_flow.LLMRequest( + request = nemo_relay.LLMRequest( {}, {"messages": [{"role": "user", "content": "hi"}], "model": "demo-model"}, ) @@ -336,7 +336,7 @@ def collect(chunk): def finalize(): return {"text": "".join(chunk["token"] for chunk in collected)} - stream = await nemo_flow.llm.stream_execute( + stream = await nemo_relay.llm.stream_execute( "demo-provider", request, impl, diff --git a/python/nemo_flow/observability.py b/python/nemo_relay/observability.py similarity index 96% rename from python/nemo_flow/observability.py rename to python/nemo_relay/observability.py index 306667f59..2cf938c4a 100644 --- a/python/nemo_flow/observability.py +++ b/python/nemo_relay/observability.py @@ -8,7 +8,7 @@ from dataclasses import dataclass, field, fields, is_dataclass from typing import Literal, Protocol, cast -from nemo_flow import Json, JsonObject, UnsupportedBehavior +from nemo_relay import Json, JsonObject, UnsupportedBehavior class _SupportsToDict(Protocol): @@ -78,13 +78,13 @@ class AtifConfig: """Per-top-level-agent ATIF file export settings.""" enabled: bool = False - agent_name: str = "NeMo Flow" + agent_name: str = "NeMo Relay" agent_version: str | None = None model_name: str = "unknown" tool_definitions: list[JsonObject] | None = None extra: JsonObject | None = None output_directory: str | None = None - filename_template: str = "nemo-flow-atif-{session_id}.json" + filename_template: str = "nemo-relay-atif-{session_id}.json" def to_dict(self) -> JsonObject: """Serialize this ATIF config to the canonical JSON object shape.""" @@ -112,7 +112,7 @@ class OtlpConfig: endpoint: str | None = None headers: dict[str, str] = field(default_factory=dict) resource_attributes: dict[str, str] = field(default_factory=dict) - service_name: str = "nemo-flow" + service_name: str = "nemo-relay" service_namespace: str | None = None service_version: str | None = None instrumentation_scope: str | None = None diff --git a/python/nemo_flow/observability.pyi b/python/nemo_relay/observability.pyi similarity index 95% rename from python/nemo_flow/observability.pyi rename to python/nemo_relay/observability.pyi index 595a812ca..2c785f98f 100644 --- a/python/nemo_flow/observability.pyi +++ b/python/nemo_relay/observability.pyi @@ -1,14 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Type stubs for ``nemo_flow.observability``.""" +"""Type stubs for ``nemo_relay.observability``.""" from __future__ import annotations from dataclasses import dataclass, field from typing import Literal -from nemo_flow import JsonObject, UnsupportedBehavior +from nemo_relay import JsonObject, UnsupportedBehavior @dataclass(slots=True) class ConfigPolicy: diff --git a/python/nemo_flow/plugin.py b/python/nemo_relay/plugin.py similarity index 97% rename from python/nemo_flow/plugin.py rename to python/nemo_relay/plugin.py index d751c8213..8fb912a36 100644 --- a/python/nemo_flow/plugin.py +++ b/python/nemo_relay/plugin.py @@ -13,7 +13,7 @@ from dataclasses import dataclass, field, fields, is_dataclass from typing import TYPE_CHECKING, Callable, Literal, Protocol, TypedDict, cast -from nemo_flow import ( +from nemo_relay import ( Json, JsonObject, LlmConditionalExecutionGuardrail, @@ -28,30 +28,30 @@ ToolSanitizeGuardrail, UnsupportedBehavior, ) -from nemo_flow._native import ( +from nemo_relay._native import ( active_plugin_report as _active_plugin_report, ) -from nemo_flow._native import ( +from nemo_relay._native import ( clear_plugin_configuration as _clear_plugin_configuration, ) -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_plugin as _deregister_plugin, ) -from nemo_flow._native import ( +from nemo_relay._native import ( initialize_plugins as _initialize_plugins, ) -from nemo_flow._native import ( +from nemo_relay._native import ( list_plugin_kinds as _list_plugin_kinds, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_plugin as _register_plugin, ) -from nemo_flow._native import ( +from nemo_relay._native import ( validate_plugin_config as _validate_plugin_config, ) if TYPE_CHECKING: - from nemo_flow import Event + from nemo_relay import Event class _ConfigDiagnosticRequired(TypedDict): diff --git a/python/nemo_flow/plugin.pyi b/python/nemo_relay/plugin.pyi similarity index 99% rename from python/nemo_flow/plugin.pyi rename to python/nemo_relay/plugin.pyi index 8b58a50d6..529e30ddd 100644 --- a/python/nemo_flow/plugin.pyi +++ b/python/nemo_relay/plugin.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable from typing import Literal, Protocol, TypedDict -from nemo_flow import ( +from nemo_relay import ( Event, JsonObject, LlmConditionalExecutionGuardrail, diff --git a/python/nemo_flow/py.typed b/python/nemo_relay/py.typed similarity index 100% rename from python/nemo_flow/py.typed rename to python/nemo_relay/py.typed diff --git a/python/nemo_flow/scope.py b/python/nemo_relay/scope.py similarity index 89% rename from python/nemo_flow/scope.py rename to python/nemo_relay/scope.py index c1ca0629f..cc1cf2fdb 100644 --- a/python/nemo_flow/scope.py +++ b/python/nemo_relay/scope.py @@ -8,10 +8,10 @@ Example:: - import nemo_flow + import nemo_relay - with nemo_flow.scope.scope("demo-agent", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope.event("checkpoint", handle=handle, data={"step": 1}) + with nemo_relay.scope.scope("demo-agent", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope.event("checkpoint", handle=handle, data={"step": 1}) """ from __future__ import annotations @@ -20,22 +20,22 @@ from datetime import datetime from typing import Iterator -from nemo_flow import Json -from nemo_flow._native import ( +from nemo_relay import Json +from nemo_relay._native import ( ScopeAttributes, ScopeHandle, ScopeType, ) -from nemo_flow._native import ( +from nemo_relay._native import ( event as _native_event, ) -from nemo_flow._native import ( +from nemo_relay._native import ( get_handle as _native_get_handle, ) -from nemo_flow._native import ( +from nemo_relay._native import ( pop_scope as _native_pop_scope, ) -from nemo_flow._native import ( +from nemo_relay._native import ( push_scope as _native_push_scope, ) @@ -53,20 +53,20 @@ def _ensure_scope_stack() -> None: called ``set_thread_scope_stack``): keep the thread-local as-is. 3. **Neither is set**: create a new scope stack via ``get_scope_stack()``. """ - import nemo_flow + import nemo_relay # Case 1: ContextVar owns a stack — re-sync it to the Rust thread-local. - stack = nemo_flow._scope_stack_var.get(None) + stack = nemo_relay._scope_stack_var.get(None) if stack is not None: - nemo_flow._sync_thread_scope_stack(stack) + nemo_relay._sync_thread_scope_stack(stack) return # Case 2: Worker thread with explicit set_thread_scope_stack — don't clobber. - if nemo_flow._native_scope_stack_active(): + if nemo_relay._native_scope_stack_active(): return # Case 3: Fresh context — create and register a new stack. - nemo_flow.get_scope_stack() + nemo_relay.get_scope_stack() def get_handle() -> ScopeHandle: @@ -121,18 +121,18 @@ def push( Example:: - import nemo_flow + import nemo_relay - with nemo_flow.scope.scope("parent", nemo_flow.ScopeType.Agent) as parent: - handle = nemo_flow.scope.push( + with nemo_relay.scope.scope("parent", nemo_relay.ScopeType.Agent) as parent: + handle = nemo_relay.scope.push( "worker", - nemo_flow.ScopeType.Function, + nemo_relay.ScopeType.Function, handle=parent, attributes=None, data={"step": 1}, metadata={"source": "scope.push"}, ) - nemo_flow.scope.pop(handle) + nemo_relay.scope.pop(handle) """ _ensure_scope_stack() return _native_push_scope( @@ -242,17 +242,17 @@ def scope( Example:: - import nemo_flow + import nemo_relay - with nemo_flow.scope.scope( + with nemo_relay.scope.scope( "demo", - nemo_flow.ScopeType.Agent, + nemo_relay.ScopeType.Agent, handle=None, attributes=None, data={"stage": "start"}, metadata={"owner": "docs"}, ) as handle: - nemo_flow.scope.event("inside", handle=handle, data={"ok": True}, metadata={"step": 1}) + nemo_relay.scope.event("inside", handle=handle, data={"ok": True}, metadata={"step": 1}) """ _ensure_scope_stack() pushed_handle = None diff --git a/python/nemo_flow/scope_local.py b/python/nemo_relay/scope_local.py similarity index 94% rename from python/nemo_flow/scope_local.py rename to python/nemo_relay/scope_local.py index 2ab0a2108..909a5bccf 100644 --- a/python/nemo_flow/scope_local.py +++ b/python/nemo_relay/scope_local.py @@ -10,85 +10,85 @@ Example:: - import nemo_flow + import nemo_relay def redact(tool_name, args): return {**args, "api_key": "***"} - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope_local.register_tool_sanitize_request(handle, "redact", 10, redact) + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope_local.register_tool_sanitize_request(handle, "redact", 10, redact) """ -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_conditional_execution_guardrail as _deregister_llm_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_execution_intercept as _deregister_llm_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_request_intercept as _deregister_llm_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_sanitize_request_guardrail as _deregister_llm_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_sanitize_response_guardrail as _deregister_llm_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_llm_stream_execution_intercept as _deregister_llm_stream_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_subscriber as _deregister_subscriber, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_tool_conditional_execution_guardrail as _deregister_tool_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_tool_execution_intercept as _deregister_tool_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_tool_request_intercept as _deregister_tool_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_tool_sanitize_request_guardrail as _deregister_tool_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_deregister_tool_sanitize_response_guardrail as _deregister_tool_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_conditional_execution_guardrail as _register_llm_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_execution_intercept as _register_llm_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_request_intercept as _register_llm_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_sanitize_request_guardrail as _register_llm_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_sanitize_response_guardrail as _register_llm_sanitize_response, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_llm_stream_execution_intercept as _register_llm_stream_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_subscriber as _register_subscriber, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_tool_conditional_execution_guardrail as _register_tool_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_tool_execution_intercept as _register_tool_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_tool_request_intercept as _register_tool_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_tool_sanitize_request_guardrail as _register_tool_sanitize_request, ) -from nemo_flow._native import ( +from nemo_relay._native import ( scope_register_tool_sanitize_response_guardrail as _register_tool_sanitize_response, ) @@ -577,13 +577,13 @@ def register_subscriber(scope_handle, name, callback): Example:: - import nemo_flow + import nemo_relay def log_event(event): print(event.kind, event.name) - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent) as handle: - nemo_flow.scope_local.register_subscriber(handle, "logger", log_event) + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent) as handle: + nemo_relay.scope_local.register_subscriber(handle, "logger", log_event) """ return _register_subscriber(scope_handle.uuid, name, callback) diff --git a/python/nemo_flow/subscribers.py b/python/nemo_relay/subscribers.py similarity index 73% rename from python/nemo_flow/subscribers.py rename to python/nemo_relay/subscribers.py index 2e83746c9..33b96668b 100644 --- a/python/nemo_flow/subscribers.py +++ b/python/nemo_relay/subscribers.py @@ -9,31 +9,31 @@ Example:: - import nemo_flow + import nemo_relay def log_event(event): print(f"{event.kind}: {event.name}") - nemo_flow.subscribers.register("logger", log_event) + nemo_relay.subscribers.register("logger", log_event) try: - with nemo_flow.scope.scope("demo", nemo_flow.ScopeType.Agent): - nemo_flow.scope.event("started") + with nemo_relay.scope.scope("demo", nemo_relay.ScopeType.Agent): + nemo_relay.scope.event("started") finally: - nemo_flow.subscribers.deregister("logger") + nemo_relay.subscribers.deregister("logger") """ from collections.abc import Callable from typing import TYPE_CHECKING -from nemo_flow._native import ( +from nemo_relay._native import ( deregister_subscriber as _native_deregister, ) -from nemo_flow._native import ( +from nemo_relay._native import ( register_subscriber as _native_register, ) if TYPE_CHECKING: - from nemo_flow import Event + from nemo_relay import Event def register(name: str, callback: "Callable[[Event], None]") -> None: @@ -52,9 +52,9 @@ def register(name: str, callback: "Callable[[Event], None]") -> None: Example:: - import nemo_flow + import nemo_relay - nemo_flow.subscribers.register("printer", lambda event: print(event.kind)) + nemo_relay.subscribers.register("printer", lambda event: print(event.kind)) """ return _native_register(name, callback) @@ -74,10 +74,10 @@ def deregister(name: str) -> bool: Example:: - import nemo_flow + import nemo_relay - nemo_flow.subscribers.register("printer", lambda event: None) - removed = nemo_flow.subscribers.deregister("printer") + nemo_relay.subscribers.register("printer", lambda event: None) + removed = nemo_relay.subscribers.deregister("printer") assert removed is True """ return _native_deregister(name) diff --git a/python/nemo_flow/tools.py b/python/nemo_relay/tools.py similarity index 92% rename from python/nemo_flow/tools.py rename to python/nemo_relay/tools.py index 36f2230a1..a9a6adf80 100644 --- a/python/nemo_flow/tools.py +++ b/python/nemo_relay/tools.py @@ -3,7 +3,7 @@ """Tool lifecycle helpers. -Use this module when you want NeMo Flow to emit tool start and end events around a +Use this module when you want NeMo Relay to emit tool start and end events around a piece of application logic. ``execute()`` is the usual entry point and runs the full middleware pipeline. @@ -11,30 +11,30 @@ Example:: - import nemo_flow + import nemo_relay async def search(args): return {"result": args["query"].upper()} - result = await nemo_flow.tools.execute("search", {"query": "hello"}, search) + result = await nemo_relay.tools.execute("search", {"query": "hello"}, search) assert result == {"result": "HELLO"} """ from datetime import datetime -from nemo_flow._native import ( +from nemo_relay._native import ( tool_call as _native_tool_call, ) -from nemo_flow._native import ( +from nemo_relay._native import ( tool_call_end as _native_tool_call_end, ) -from nemo_flow._native import ( +from nemo_relay._native import ( tool_call_execute as _native_tool_call_execute, ) -from nemo_flow._native import ( +from nemo_relay._native import ( tool_conditional_execution as _native_tool_conditional_execution, ) -from nemo_flow._native import ( +from nemo_relay._native import ( tool_request_intercepts as _native_tool_request_intercepts, ) @@ -77,9 +77,9 @@ def call( Example:: - import nemo_flow + import nemo_relay - handle = nemo_flow.tools.call( + handle = nemo_relay.tools.call( "search", {"query": "hello"}, handle=None, @@ -88,7 +88,7 @@ def call( metadata={"path": "manual"}, tool_call_id="tool-call-1", ) - nemo_flow.tools.call_end( + nemo_relay.tools.call_end( handle, {"result": "ok"}, data={"cached": False}, @@ -163,12 +163,12 @@ def execute(name, args, func, *, handle=None, attributes=None, data=None, metada Example:: - import nemo_flow + import nemo_relay async def local_tool(args): return {"count": len(args["items"])} - result = await nemo_flow.tools.execute( + result = await nemo_relay.tools.execute( "count", {"items": [1, 2, 3]}, local_tool, diff --git a/python/nemo_flow/typed.py b/python/nemo_relay/typed.py similarity index 95% rename from python/nemo_flow/typed.py rename to python/nemo_relay/typed.py index cf1b112d8..eed665c95 100644 --- a/python/nemo_flow/typed.py +++ b/python/nemo_relay/typed.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Typed wrappers around the JSON-based NeMo Flow execution APIs. +"""Typed wrappers around the JSON-based NeMo Relay execution APIs. The core runtime operates on JSON-like values. This module adds a codec layer so callers can work with typed Python objects at the boundaries while the @@ -11,7 +11,7 @@ from dataclasses import dataclass - import nemo_flow.typed as typed + import nemo_relay.typed as typed @dataclass class SearchArgs: @@ -45,9 +45,9 @@ async def tool_impl(args: SearchArgs) -> SearchResult: import weakref from typing import AsyncIterator, Awaitable, Callable, Generic, Protocol, TypeVar, cast, overload -from nemo_flow import Json, llm, tools -from nemo_flow._native import LLMRequest, LlmStream, ScopeHandle -from nemo_flow.codecs import LlmCodec, LlmResponseCodec +from nemo_relay import Json, llm, tools +from nemo_relay._native import LLMRequest, LlmStream, ScopeHandle +from nemo_relay.codecs import LlmCodec, LlmResponseCodec T = TypeVar("T") TArgs = TypeVar("TArgs") @@ -144,7 +144,7 @@ class Codec(Generic[T]): """Bidirectional conversion protocol between a Python type and JSON. Implementations convert between ergonomic Python objects and the - JSON-compatible values used by the underlying NeMo Flow runtime. + JSON-compatible values used by the underlying NeMo Relay runtime. """ def to_json(self, value: T) -> Json: @@ -483,7 +483,7 @@ async def tool_execute( data: Json | None = None, metadata: Json | None = None, ) -> TResult: - """Run ``nemo_flow.tools.execute`` with typed arguments and results. + """Run ``nemo_relay.tools.execute`` with typed arguments and results. Args: name: Tool name recorded on emitted lifecycle events. @@ -505,7 +505,7 @@ async def tool_execute( from dataclasses import dataclass - from nemo_flow.typed import DataclassCodec, tool_execute + from nemo_relay.typed import DataclassCodec, tool_execute @dataclass class SearchArgs: @@ -599,7 +599,7 @@ async def llm_execute( codec: LlmCodec | None = None, response_codec: LlmResponseCodec | None = None, ) -> TResponse: - """Run ``nemo_flow.llm.execute`` and decode the returned response type. + """Run ``nemo_relay.llm.execute`` and decode the returned response type. Args: name: Provider or logical call name recorded on emitted events. @@ -625,20 +625,20 @@ async def llm_execute( Example:: - import nemo_flow + import nemo_relay from dataclasses import dataclass - from nemo_flow.typed import DataclassCodec, llm_execute + from nemo_relay.typed import DataclassCodec, llm_execute @dataclass class MyResponse: text: str - async def llm_impl(request: nemo_flow.LLMRequest): + async def llm_impl(request: nemo_relay.LLMRequest): return {"text": "hello"} typed_response = await llm_execute( "demo-provider", - nemo_flow.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), + nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), llm_impl, response_json_codec=DataclassCodec(MyResponse), handle=None, @@ -690,7 +690,7 @@ async def llm_stream_execute( codec: LlmCodec | None = None, response_codec: LlmResponseCodec | None = None, ) -> LlmStream: # SONAR_IGNORE_STOP - """Run ``nemo_flow.llm.stream_execute`` with typed chunks and final output. + """Run ``nemo_relay.llm.stream_execute`` with typed chunks and final output. Args: name: Provider or logical call name recorded on emitted events. @@ -725,9 +725,9 @@ async def llm_stream_execute( Example:: - import nemo_flow + import nemo_relay from dataclasses import dataclass - from nemo_flow.typed import DataclassCodec, llm_stream_execute + from nemo_relay.typed import DataclassCodec, llm_stream_execute @dataclass class MyChunk: @@ -739,7 +739,7 @@ class MyResponse: collected = [] - async def stream_impl(request: nemo_flow.LLMRequest): + async def stream_impl(request: nemo_relay.LLMRequest): yield MyChunk(token="hel") yield MyChunk(token="lo") @@ -751,7 +751,7 @@ def finish_response() -> MyResponse: stream = await llm_stream_execute( "demo-provider", - nemo_flow.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), + nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}), stream_impl, collector=collect_chunk, finalizer=finish_response, diff --git a/python/nemo_flow/utils.py b/python/nemo_relay/utils.py similarity index 88% rename from python/nemo_flow/utils.py rename to python/nemo_relay/utils.py index 3df7017e2..3942c03ca 100644 --- a/python/nemo_flow/utils.py +++ b/python/nemo_relay/utils.py @@ -6,7 +6,7 @@ from concurrent.futures import ThreadPoolExecutor from typing import Any -import nemo_flow +import nemo_relay # Since this is created on import, this module is intentionally not imported in __init__.py _RUN_SYNC_EXECUTOR = ThreadPoolExecutor() @@ -21,7 +21,7 @@ def run_sync(coro: Any) -> Any: When offloading to a ThreadPoolExecutor worker, this helper propagates both Python contextvars and the Rust thread-local scope stack so that - NeMo Flow telemetry is preserved on the worker thread. + NeMo Relay telemetry is preserved on the worker thread. """ try: asyncio.get_running_loop() @@ -33,10 +33,10 @@ def run_sync(coro: Any) -> Any: # Propagate contextvars and scope stack to the worker thread. ctx = contextvars.copy_context() - scope_stack = nemo_flow.get_scope_stack() + scope_stack = nemo_relay.get_scope_stack() def _run_with_scope_stack() -> Any: - nemo_flow.set_thread_scope_stack(scope_stack) + nemo_relay.set_thread_scope_stack(scope_stack) return asyncio.run(coro) return _RUN_SYNC_EXECUTOR.submit(ctx.run, _run_with_scope_stack).result() diff --git a/python/tests/conftest.py b/python/tests/conftest.py index cc4b97944..5958c3597 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -12,19 +12,19 @@ import pytest if typing.TYPE_CHECKING: - import nemo_flow + import nemo_relay @pytest.fixture(name="subscribed_events") -def subscribed_events_fixture() -> Iterator[list[nemo_flow.Event]]: - import nemo_flow +def subscribed_events_fixture() -> Iterator[list[nemo_relay.Event]]: + import nemo_relay - events: list[nemo_flow.Event] = [] + events: list[nemo_relay.Event] = [] - def event_recorder(event: nemo_flow.Event) -> None: + def event_recorder(event: nemo_relay.Event) -> None: events.append(event) subscriber_name = f"test-{uuid4()}" - nemo_flow.subscribers.register(subscriber_name, event_recorder) + nemo_relay.subscribers.register(subscriber_name, event_recorder) yield events - nemo_flow.subscribers.deregister(subscriber_name) + nemo_relay.subscribers.deregister(subscriber_name) diff --git a/python/tests/integrations/deepagents_tests/test_deepagents_integration.py b/python/tests/integrations/deepagents_tests/test_deepagents_integration.py index ac34267f0..35cad43a1 100644 --- a/python/tests/integrations/deepagents_tests/test_deepagents_integration.py +++ b/python/tests/integrations/deepagents_tests/test_deepagents_integration.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for the Deep Agents NeMo Flow integration.""" +"""Tests for the Deep Agents NeMo Relay integration.""" from __future__ import annotations @@ -13,17 +13,17 @@ import pytest -import nemo_flow +import nemo_relay if TYPE_CHECKING: from langchain_core.language_models.fake_chat_models import FakeMessagesListChatModel - import nemo_flow.integrations.deepagents as deepagents_integration + import nemo_relay.integrations.deepagents as deepagents_integration @pytest.fixture(name="deepagents_integration_module", scope="session") def deepagents_integration_module_fixture() -> types.ModuleType: - import nemo_flow.integrations.deepagents as deepagents_integration + import nemo_relay.integrations.deepagents as deepagents_integration return deepagents_integration @@ -31,8 +31,8 @@ def deepagents_integration_module_fixture() -> types.ModuleType: @pytest.fixture(name="callback_handler") def callback_handler_fixture( deepagents_integration_module: types.ModuleType, -) -> deepagents_integration.NemoFlowDeepAgentsCallbackHandler: - return deepagents_integration_module.NemoFlowDeepAgentsCallbackHandler() +) -> deepagents_integration.NemoRelayDeepAgentsCallbackHandler: + return deepagents_integration_module.NemoRelayDeepAgentsCallbackHandler() def _mock_deepagents_chat_model(responses: list[Any]) -> FakeMessagesListChatModel: @@ -47,32 +47,32 @@ def bind_tools(self, _tools: Any, *_args: Any, **_kwargs: Any) -> _MockDeepAgent return _MockDeepAgentsChatModel(responses=responses) -def _filter_mark_events(events: list[nemo_flow.Event]) -> list[nemo_flow.MarkEvent]: - return [event for event in events if isinstance(event, nemo_flow.MarkEvent)] +def _filter_mark_events(events: list[nemo_relay.Event]) -> list[nemo_relay.MarkEvent]: + return [event for event in events if isinstance(event, nemo_relay.MarkEvent)] -def _mark_data(mark: nemo_flow.MarkEvent) -> dict[str, Any]: +def _mark_data(mark: nemo_relay.MarkEvent) -> dict[str, Any]: assert isinstance(mark.data, dict) return cast(dict[str, Any], mark.data) -def _mark_metadata(mark: nemo_flow.MarkEvent) -> dict[str, Any]: +def _mark_metadata(mark: nemo_relay.MarkEvent) -> dict[str, Any]: assert isinstance(mark.metadata, dict) return cast(dict[str, Any], mark.metadata) def test_before_agent_emits_configuration_mark( - subscribed_events: list[nemo_flow.Event], + subscribed_events: list[nemo_relay.Event], deepagents_integration_module: types.ModuleType, ): - middleware = deepagents_integration_module.NemoFlowDeepAgentsMiddleware( + middleware = deepagents_integration_module.NemoRelayDeepAgentsMiddleware( agent_name="main-agent", skills=["/skills/research/"], subagents=[{"name": "researcher"}], backend_name="StateBackend", ) - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): middleware.before_agent(MagicMock(name="mock_state"), MagicMock(name="mock_runtime")) marks = _filter_mark_events(subscribed_events) @@ -84,8 +84,8 @@ def test_before_agent_emits_configuration_mark( def test_callback_handler_emits_human_in_the_loop_marks( - subscribed_events: list[nemo_flow.Event], - callback_handler: deepagents_integration.NemoFlowDeepAgentsCallbackHandler, + subscribed_events: list[nemo_relay.Event], + callback_handler: deepagents_integration.NemoRelayDeepAgentsCallbackHandler, ): from langgraph.callbacks import GraphInterruptEvent, GraphResumeEvent from langgraph.types import Interrupt @@ -102,7 +102,7 @@ def test_callback_handler_emits_human_in_the_loop_marks( "review_configs": [{"action_name": "edit_file", "allowed_decisions": ["approve", "reject"]}], } - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): callback_handler.on_interrupt( GraphInterruptEvent( run_id=run_id, @@ -132,15 +132,15 @@ def test_callback_handler_emits_human_in_the_loop_marks( def test_callback_handler_falls_back_for_non_hitl_interrupt( - subscribed_events: list[nemo_flow.Event], - callback_handler: deepagents_integration.NemoFlowDeepAgentsCallbackHandler, + subscribed_events: list[nemo_relay.Event], + callback_handler: deepagents_integration.NemoRelayDeepAgentsCallbackHandler, ): from langgraph.callbacks import GraphInterruptEvent, GraphResumeEvent from langgraph.types import Interrupt run_id = uuid4() - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): callback_handler.on_interrupt( GraphInterruptEvent( run_id=run_id, @@ -165,10 +165,10 @@ def test_callback_handler_falls_back_for_non_hitl_interrupt( assert "deepagents_kind" not in _mark_metadata(marks[0]) -def test_add_nemo_flow_integration_preserves_backend(deepagents_integration_module: types.ModuleType): +def test_add_nemo_relay_integration_preserves_backend(deepagents_integration_module: types.ModuleType): mock_backend = MagicMock(name="mock_backend") mock_compiled_subagent = MagicMock(name="mock_compiled_subagent") - kwargs = deepagents_integration_module.add_nemo_flow_integration( + kwargs = deepagents_integration_module.add_nemo_relay_integration( model="mock-model", name="main-agent", skills=["/skills/main/"], @@ -182,10 +182,10 @@ def test_add_nemo_flow_integration_preserves_backend(deepagents_integration_modu assert kwargs["backend"] is mock_backend assert any( - isinstance(item, deepagents_integration_module.NemoFlowDeepAgentsMiddleware) for item in kwargs["middleware"] + isinstance(item, deepagents_integration_module.NemoRelayDeepAgentsMiddleware) for item in kwargs["middleware"] ) assert any( - isinstance(item, deepagents_integration_module.NemoFlowDeepAgentsMiddleware) + isinstance(item, deepagents_integration_module.NemoRelayDeepAgentsMiddleware) for item in kwargs["subagents"][0]["middleware"] ) assert kwargs["subagents"][1] is mock_compiled_subagent @@ -193,7 +193,7 @@ def test_add_nemo_flow_integration_preserves_backend(deepagents_integration_modu def test_e2e_agent( tmp_path: Path, - subscribed_events: list[nemo_flow.Event], + subscribed_events: list[nemo_relay.Event], deepagents_integration_module: types.ModuleType, ): from deepagents import create_deep_agent @@ -234,7 +234,7 @@ def test_e2e_agent( AIMessage(content="created turtle after reviewer verified turtle"), ] ) - kwargs = deepagents_integration_module.add_nemo_flow_integration( + kwargs = deepagents_integration_module.add_nemo_relay_integration( model=model, tools=[], name="main-agent", @@ -251,7 +251,7 @@ def test_e2e_agent( ) agent = create_deep_agent(**kwargs) - with nemo_flow.scope.scope("deepagents-request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("deepagents-request", nemo_relay.ScopeType.Agent): result = agent.invoke({"messages": [{"role": "user", "content": "Create a file named turtle."}]}) assert (tmp_path / "turtle").read_text() == "shell" diff --git a/python/tests/integrations/langchain_tests/test_callbacks.py b/python/tests/integrations/langchain_tests/test_callbacks.py index 31fb4d232..bc72fe29b 100644 --- a/python/tests/integrations/langchain_tests/test_callbacks.py +++ b/python/tests/integrations/langchain_tests/test_callbacks.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for the LangChain NeMo Flow callback handler.""" +"""Tests for the LangChain NeMo Relay callback handler.""" from __future__ import annotations @@ -13,13 +13,13 @@ import pytest if typing.TYPE_CHECKING: - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler -def _make_mock_nemo_flow() -> MagicMock: - """Build a minimal mock of the ``nemo_flow`` module.""" - mock_nemo_flow = MagicMock(name="nemo_flow") - mock_nemo_flow.ScopeType = types.SimpleNamespace(Agent="Agent") +def _make_mock_nemo_relay() -> MagicMock: + """Build a minimal mock of the ``nemo_relay`` module.""" + mock_nemo_relay = MagicMock(name="nemo_relay") + mock_nemo_relay.ScopeType = types.SimpleNamespace(Agent="Agent") scope = types.SimpleNamespace() scope.push = MagicMock( @@ -31,39 +31,39 @@ def _make_mock_nemo_flow() -> MagicMock: ) ) scope.pop = MagicMock() - mock_nemo_flow.scope = scope - return mock_nemo_flow + mock_nemo_relay.scope = scope + return mock_nemo_relay @pytest.fixture(name="callbacks_module", scope="session") def callbacks_module_fixture() -> types.ModuleType: """Fixture to provide the callbacks module.""" - import nemo_flow.integrations.langchain.callbacks as callbacks_module + import nemo_relay.integrations.langchain.callbacks as callbacks_module return callbacks_module @pytest.fixture() -def mock_nemo_flow(monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType) -> MagicMock: - mock_nemo_flow = _make_mock_nemo_flow() - monkeypatch.setattr(callbacks_module, "nemo_flow", mock_nemo_flow) - return mock_nemo_flow +def mock_nemo_relay(monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType) -> MagicMock: + mock_nemo_relay = _make_mock_nemo_relay() + monkeypatch.setattr(callbacks_module, "nemo_relay", mock_nemo_relay) + return mock_nemo_relay @pytest.fixture() -def handler(mock_nemo_flow: MagicMock) -> NemoFlowCallbackHandler: - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler +def handler(mock_nemo_relay: MagicMock) -> NemoRelayCallbackHandler: + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler - return NemoFlowCallbackHandler() + return NemoRelayCallbackHandler() class TestScopeLifecycle: """Verify that chain start/end/error map to scope push/pop.""" - def test_handler_runs_inline_for_async_callback_managers(self, handler: NemoFlowCallbackHandler): + def test_handler_runs_inline_for_async_callback_managers(self, handler: NemoRelayCallbackHandler): assert handler.run_inline is True - def test_on_chain_start_pushes_scope(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_on_chain_start_pushes_scope(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start( @@ -73,9 +73,9 @@ def test_on_chain_start_pushes_scope(self, handler: NemoFlowCallbackHandler, moc metadata={"source": "unit-test"}, ) - mock_nemo_flow.scope.push.assert_called_once() - args, kwargs = mock_nemo_flow.scope.push.call_args - assert args == ("MyChain", mock_nemo_flow.ScopeType.Agent) + mock_nemo_relay.scope.push.assert_called_once() + args, kwargs = mock_nemo_relay.scope.push.call_args + assert args == ("MyChain", mock_nemo_relay.ScopeType.Agent) assert kwargs["input"] == {"input": "test"} assert kwargs["metadata"] == { "langchain_run_id": str(run_id), @@ -83,7 +83,7 @@ def test_on_chain_start_pushes_scope(self, handler: NemoFlowCallbackHandler, moc } assert run_id in handler._scope_handles - def test_on_chain_start_uses_callback_name(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_on_chain_start_uses_callback_name(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start( @@ -93,9 +93,9 @@ def test_on_chain_start_uses_callback_name(self, handler: NemoFlowCallbackHandle name="LangGraph", ) - assert mock_nemo_flow.scope.push.call_args.args[0] == "LangGraph" + assert mock_nemo_relay.scope.push.call_args.args[0] == "LangGraph" - def test_on_chain_end_pops_scope(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_on_chain_end_pops_scope(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start( {"name": "MyChain"}, @@ -109,10 +109,10 @@ def test_on_chain_end_pops_scope(self, handler: NemoFlowCallbackHandler, mock_ne run_id=run_id, ) - mock_nemo_flow.scope.pop.assert_called_once_with(handle, output={"output": "result"}) + mock_nemo_relay.scope.pop.assert_called_once_with(handle, output={"output": "result"}) assert run_id not in handler._scope_handles - def test_on_chain_error_pops_scope(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_on_chain_error_pops_scope(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start( {"name": "MyChain"}, @@ -126,10 +126,10 @@ def test_on_chain_error_pops_scope(self, handler: NemoFlowCallbackHandler, mock_ run_id=run_id, ) - mock_nemo_flow.scope.pop.assert_called_once_with(handle, output={"error": "RuntimeError('boom')"}) + mock_nemo_relay.scope.pop.assert_called_once_with(handle, output={"error": "RuntimeError('boom')"}) assert run_id not in handler._scope_handles - def test_on_chain_end_prepares_command_outputs(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_on_chain_end_prepares_command_outputs(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): from langchain_core.messages import ToolMessage from langgraph.types import Command @@ -158,7 +158,7 @@ def test_on_chain_end_prepares_command_outputs(self, handler: NemoFlowCallbackHa run_id=run_id, ) - mock_nemo_flow.scope.pop.assert_called_once_with( + mock_nemo_relay.scope.pop.assert_called_once_with( handle, output={ "result": { @@ -185,7 +185,7 @@ def test_on_chain_end_prepares_command_outputs(self, handler: NemoFlowCallbackHa }, ) - def test_parent_scope_passed_to_push(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_parent_scope_passed_to_push(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): parent_id = uuid4() child_id = uuid4() handler.on_chain_start( @@ -202,18 +202,18 @@ def test_parent_scope_passed_to_push(self, handler: NemoFlowCallbackHandler, moc parent_run_id=parent_id, ) - child_call = mock_nemo_flow.scope.push.call_args_list[1] + child_call = mock_nemo_relay.scope.push.call_args_list[1] assert child_call.kwargs["handle"] is parent_handle - def test_chain_end_without_start_is_noop(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_chain_end_without_start_is_noop(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): handler.on_chain_end( {"output": "result"}, run_id=uuid4(), ) - mock_nemo_flow.scope.pop.assert_not_called() + mock_nemo_relay.scope.pop.assert_not_called() - def test_name_fallback_to_id(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_name_fallback_to_id(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start( @@ -222,48 +222,48 @@ def test_name_fallback_to_id(self, handler: NemoFlowCallbackHandler, mock_nemo_f run_id=run_id, ) - assert mock_nemo_flow.scope.push.call_args.args[0] == "RunnableSequence" + assert mock_nemo_relay.scope.push.call_args.args[0] == "RunnableSequence" class TestGracefulNoOp: """Verify callbacks are silent if the module-level runtime is unavailable.""" - def test_no_nemo_flow_on_chain_start(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): - monkeypatch.setattr(callbacks_module, "nemo_flow", None) - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler + def test_no_nemo_relay_on_chain_start(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): + monkeypatch.setattr(callbacks_module, "nemo_relay", None) + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler - handler = NemoFlowCallbackHandler() + handler = NemoRelayCallbackHandler() handler.on_chain_start({"name": "x"}, {}, run_id=uuid4()) - def test_no_nemo_flow_on_chain_end(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): - monkeypatch.setattr(callbacks_module, "nemo_flow", None) - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler + def test_no_nemo_relay_on_chain_end(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): + monkeypatch.setattr(callbacks_module, "nemo_relay", None) + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler - handler = NemoFlowCallbackHandler() + handler = NemoRelayCallbackHandler() handler.on_chain_end({}, run_id=uuid4()) - def test_no_nemo_flow_on_chain_error(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): - monkeypatch.setattr(callbacks_module, "nemo_flow", None) - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler + def test_no_nemo_relay_on_chain_error(self, monkeypatch: pytest.MonkeyPatch, callbacks_module: types.ModuleType): + monkeypatch.setattr(callbacks_module, "nemo_relay", None) + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler - handler = NemoFlowCallbackHandler() + handler = NemoRelayCallbackHandler() handler.on_chain_error(RuntimeError("e"), run_id=uuid4()) class TestErrorSwallowing: - """Ensure NeMo Flow errors never propagate.""" + """Ensure NeMo Relay errors never propagate.""" - def test_scope_push_error_swallowed(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): - mock_nemo_flow.scope.push.side_effect = RuntimeError("nemo flow failure") + def test_scope_push_error_swallowed(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): + mock_nemo_relay.scope.push.side_effect = RuntimeError("nemo relay failure") handler.on_chain_start({"name": "x"}, {}, run_id=uuid4()) - def test_scope_pop_error_swallowed(self, handler: NemoFlowCallbackHandler, mock_nemo_flow: MagicMock): + def test_scope_pop_error_swallowed(self, handler: NemoRelayCallbackHandler, mock_nemo_relay: MagicMock): run_id = uuid4() handler.on_chain_start({"name": "x"}, {}, run_id=run_id) - mock_nemo_flow.scope.pop.side_effect = RuntimeError("nemo flow failure") + mock_nemo_relay.scope.pop.side_effect = RuntimeError("nemo relay failure") handler.on_chain_end({}, run_id=run_id) diff --git a/python/tests/integrations/langchain_tests/test_middleware.py b/python/tests/integrations/langchain_tests/test_middleware.py index 72fe9642b..fe1773043 100644 --- a/python/tests/integrations/langchain_tests/test_middleware.py +++ b/python/tests/integrations/langchain_tests/test_middleware.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for the LangChain NeMo Flow middleware.""" +"""Tests for the LangChain NeMo Relay middleware.""" from __future__ import annotations @@ -13,16 +13,16 @@ import pytest -import nemo_flow -from nemo_flow.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec +import nemo_relay +from nemo_relay.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec if TYPE_CHECKING: from langchain.agents.middleware import ModelRequest, ModelResponse, ToolCallRequest from langchain_core.messages import AIMessage, ToolMessage - from nemo_flow.integrations.langchain.middleware import NemoFlowMiddleware + from nemo_relay.integrations.langchain.middleware import NemoRelayMiddleware -_DEFAULT_MOCK_RESPONSE_MSG = "nemo_flow unittest result" +_DEFAULT_MOCK_RESPONSE_MSG = "nemo_relay unittest result" @pytest.fixture(name="model_request_handler") @@ -109,11 +109,11 @@ def _mk_mock_model(returned_message: str | list[AIMessage] = _DEFAULT_MOCK_RESPO return mock_model -@pytest.fixture(name="nemo_flow_middleware") -def nemo_flow_middleware_fixture() -> NemoFlowMiddleware: - from nemo_flow.integrations.langchain.middleware import NemoFlowMiddleware +@pytest.fixture(name="nemo_relay_middleware") +def nemo_relay_middleware_fixture() -> NemoRelayMiddleware: + from nemo_relay.integrations.langchain.middleware import NemoRelayMiddleware - return NemoFlowMiddleware() + return NemoRelayMiddleware() class RecordingMiddleware(Protocol): @@ -124,9 +124,9 @@ class RecordingMiddleware(Protocol): @pytest.fixture(name="recording_middleware") def recording_middleware_fixture() -> RecordingMiddleware: - from nemo_flow.integrations.langchain.middleware import NemoFlowMiddleware + from nemo_relay.integrations.langchain.middleware import NemoRelayMiddleware - class _RecordingMiddleware(NemoFlowMiddleware, RecordingMiddleware): + class _RecordingMiddleware(NemoRelayMiddleware, RecordingMiddleware): def __init__(self): super().__init__() self.calls: list[dict[str, Any]] = [] @@ -134,7 +134,7 @@ def __init__(self): async def _llm_execute( self, model_name: str, - request: nemo_flow.LLMRequest, + request: nemo_relay.LLMRequest, codec: Any, response_codec: Any, func: Any, @@ -147,7 +147,7 @@ async def _llm_execute( "response_codec": response_codec, } ) - intercepted = nemo_flow.LLMRequest( + intercepted = nemo_relay.LLMRequest( request.headers, { **request.content, @@ -223,7 +223,7 @@ def test_awrap_model_call_routes_through_llm_execute( def test_wrap_tool_call_routes_through_tool_execute( monkeypatch: pytest.MonkeyPatch, - nemo_flow_middleware: NemoFlowMiddleware, + nemo_relay_middleware: NemoRelayMiddleware, mock_tool_execute: AsyncMock, tool_call_request: ToolCallRequest, tool_request_handler: tuple[Callable[[ToolCallRequest], ToolMessage], dict[str, ToolCallRequest]], @@ -231,10 +231,10 @@ def test_wrap_tool_call_routes_through_tool_execute( (handler, seen_request) = tool_request_handler parent_handle = MagicMock() - monkeypatch.setattr(nemo_flow.scope, "get_handle", lambda: parent_handle) - monkeypatch.setattr(nemo_flow.typed, "tool_execute", mock_tool_execute) + monkeypatch.setattr(nemo_relay.scope, "get_handle", lambda: parent_handle) + monkeypatch.setattr(nemo_relay.typed, "tool_execute", mock_tool_execute) - response = nemo_flow_middleware.wrap_tool_call(tool_call_request, handler) + response = nemo_relay_middleware.wrap_tool_call(tool_call_request, handler) assert response.content == "done" assert seen_request["request"].tool_call["args"] == {"query": "intercepted"} @@ -244,13 +244,13 @@ def test_wrap_tool_call_routes_through_tool_execute( assert kwargs["name"] == "lookup" assert kwargs["args"] == {"query": "original"} assert kwargs["handle"] is parent_handle - assert isinstance(kwargs["args_codec"], nemo_flow.typed.BestEffortAnyCodec) - assert isinstance(kwargs["result_codec"], nemo_flow.typed.BestEffortAnyCodec) + assert isinstance(kwargs["args_codec"], nemo_relay.typed.BestEffortAnyCodec) + assert isinstance(kwargs["result_codec"], nemo_relay.typed.BestEffortAnyCodec) def test_awrap_tool_call_routes_through_tool_execute( monkeypatch: pytest.MonkeyPatch, - nemo_flow_middleware: NemoFlowMiddleware, + nemo_relay_middleware: NemoRelayMiddleware, mock_tool_execute: AsyncMock, tool_call_request: ToolCallRequest, async_tool_request_handler: tuple[Callable[[ToolCallRequest], Awaitable[ToolMessage]], dict[str, ToolCallRequest]], @@ -258,10 +258,10 @@ def test_awrap_tool_call_routes_through_tool_execute( parent_handle = MagicMock() (handler, seen_request) = async_tool_request_handler - monkeypatch.setattr(nemo_flow.scope, "get_handle", lambda: parent_handle) - monkeypatch.setattr(nemo_flow.typed, "tool_execute", mock_tool_execute) + monkeypatch.setattr(nemo_relay.scope, "get_handle", lambda: parent_handle) + monkeypatch.setattr(nemo_relay.typed, "tool_execute", mock_tool_execute) - response = asyncio.run(nemo_flow_middleware.awrap_tool_call(tool_call_request, handler)) + response = asyncio.run(nemo_relay_middleware.awrap_tool_call(tool_call_request, handler)) assert response.content == "done" assert seen_request["request"].tool_call["args"] == {"query": "intercepted"} @@ -271,12 +271,12 @@ def test_awrap_tool_call_routes_through_tool_execute( assert kwargs["name"] == "lookup" assert kwargs["args"] == {"query": "original"} assert kwargs["handle"] is parent_handle - assert isinstance(kwargs["args_codec"], nemo_flow.typed.BestEffortAnyCodec) - assert isinstance(kwargs["result_codec"], nemo_flow.typed.BestEffortAnyCodec) + assert isinstance(kwargs["args_codec"], nemo_relay.typed.BestEffortAnyCodec) + assert isinstance(kwargs["result_codec"], nemo_relay.typed.BestEffortAnyCodec) def test_infer_codec_from_supported_model_classes(monkeypatch: pytest.MonkeyPatch): - from nemo_flow.integrations.langchain import _serialization + from nemo_relay.integrations.langchain import _serialization MockChatAnthropic = MagicMock(spec=type("MockChatAnthropic", (), {})) MockChatOpenAI = MagicMock(spec=type("MockChatOpenAI", (), {})) @@ -302,7 +302,7 @@ def test_infer_codec_from_supported_model_classes(monkeypatch: pytest.MonkeyPatc @pytest.mark.parametrize("use_async", [False, True]) -def test_agent_integration(use_async: bool, nemo_flow_middleware: NemoFlowMiddleware): +def test_agent_integration(use_async: bool, nemo_relay_middleware: NemoRelayMiddleware): """An integration test to verify that the middleware correctly wraps a model call end-to-end.""" from langchain.agents import create_agent from langchain_core.messages import AIMessage @@ -329,7 +329,7 @@ def get_weather(location: str) -> str: """Get the current weather for a location.""" return f"The weather in {location} is sunny and 72 degrees." - agent = create_agent(model=mock_model, tools=[get_weather], middleware=[nemo_flow_middleware]) + agent = create_agent(model=mock_model, tools=[get_weather], middleware=[nemo_relay_middleware]) input_payload = { "messages": [ @@ -355,16 +355,16 @@ def get_weather(location: str) -> str: def event_recorder(event): events.append(f"{event.kind}.{event.scope_category}.{event.name}") - nemo_flow.subscribers.register("event_recorder", event_recorder) + nemo_relay.subscribers.register("event_recorder", event_recorder) try: - with nemo_flow.scope.scope("langchain-request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("langchain-request", nemo_relay.ScopeType.Agent): if use_async: result = asyncio.run(agent.ainvoke(input_payload)) else: result = agent.invoke(input_payload) finally: - nemo_flow.subscribers.deregister("event_recorder") + nemo_relay.subscribers.deregister("event_recorder") assert any( message.content == "The weather in San Francisco is sunny and 72 degrees." for message in result["messages"] diff --git a/python/tests/integrations/langgraph_tests/test_langgraph_integration.py b/python/tests/integrations/langgraph_tests/test_langgraph_integration.py index 5b09bb6ba..337532bf7 100644 --- a/python/tests/integrations/langgraph_tests/test_langgraph_integration.py +++ b/python/tests/integrations/langgraph_tests/test_langgraph_integration.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for the LangGraph NeMo Flow callback integration.""" +"""Tests for the LangGraph NeMo Relay callback integration.""" from __future__ import annotations @@ -12,12 +12,12 @@ import pytest from typing_extensions import TypedDict -import nemo_flow +import nemo_relay if TYPE_CHECKING: from langgraph.graph import CompiledStateGraph - from nemo_flow.integrations.langgraph import NemoFlowCallbackHandler + from nemo_relay.integrations.langgraph import NemoRelayCallbackHandler class State(TypedDict): @@ -58,17 +58,17 @@ def async_graph_fixture() -> CompiledStateGraph: @pytest.fixture(name="callback_handler") -def callback_handler_fixture() -> NemoFlowCallbackHandler: - from nemo_flow.integrations.langgraph import NemoFlowCallbackHandler +def callback_handler_fixture() -> NemoRelayCallbackHandler: + from nemo_relay.integrations.langgraph import NemoRelayCallbackHandler - return NemoFlowCallbackHandler() + return NemoRelayCallbackHandler() -def _events_to_strings(events: list[nemo_flow.Event]) -> list[str]: +def _events_to_strings(events: list[nemo_relay.Event]) -> list[str]: event_strings: list[str] = [] for event in events: - if isinstance(event, nemo_flow.ScopeEvent): + if isinstance(event, nemo_relay.ScopeEvent): event_strings.append(f"{event.kind}.{event.scope_category}.{event.name}") else: event_strings.append(f"{event.kind}.{event.name}") @@ -76,10 +76,10 @@ def _events_to_strings(events: list[nemo_flow.Event]) -> list[str]: return event_strings -def test_handler_type(callback_handler: NemoFlowCallbackHandler): +def test_handler_type(callback_handler: NemoRelayCallbackHandler): from langgraph.callbacks import GraphCallbackHandler - from nemo_flow.integrations.langchain.callbacks import NemoFlowCallbackHandler as LangChainCallbackHandler + from nemo_relay.integrations.langchain.callbacks import NemoRelayCallbackHandler as LangChainCallbackHandler assert isinstance(callback_handler, LangChainCallbackHandler) assert isinstance(callback_handler, GraphCallbackHandler) @@ -98,10 +98,10 @@ class TestGraphCallbacks: def test_sync( self, sync_graph: CompiledStateGraph, - subscribed_events: list[nemo_flow.Event], - callback_handler: NemoFlowCallbackHandler, + subscribed_events: list[nemo_relay.Event], + callback_handler: NemoRelayCallbackHandler, ): - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): result = sync_graph.invoke({"value": 1}, config={"callbacks": [callback_handler]}) assert result == {"value": 2} @@ -110,10 +110,10 @@ def test_sync( async def test_async( self, async_graph: CompiledStateGraph, - subscribed_events: list[nemo_flow.Event], - callback_handler: NemoFlowCallbackHandler, + subscribed_events: list[nemo_relay.Event], + callback_handler: NemoRelayCallbackHandler, ): - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): result = await async_graph.ainvoke({"value": 1}, config={"callbacks": [callback_handler]}) assert result == {"value": 2} @@ -121,8 +121,8 @@ async def test_async( def test_graph_lifecycle_callbacks_emit_marks( - subscribed_events: list[nemo_flow.Event], - callback_handler: NemoFlowCallbackHandler, + subscribed_events: list[nemo_relay.Event], + callback_handler: NemoRelayCallbackHandler, ): from langgraph.callbacks import GraphInterruptEvent, GraphResumeEvent from langgraph.types import Interrupt @@ -136,7 +136,7 @@ def test_graph_lifecycle_callbacks_emit_marks( "scope.end.request", ] - with nemo_flow.scope.scope("request", nemo_flow.ScopeType.Agent): + with nemo_relay.scope.scope("request", nemo_relay.ScopeType.Agent): callback_handler.on_interrupt( GraphInterruptEvent( run_id=run_id, @@ -159,12 +159,12 @@ def test_graph_lifecycle_callbacks_emit_marks( assert _events_to_strings(subscribed_events) == expected_event_strings interrupt_event = subscribed_events[1] - assert isinstance(interrupt_event, nemo_flow.MarkEvent) + assert isinstance(interrupt_event, nemo_relay.MarkEvent) interrupt_data = cast(dict[str, Any], interrupt_event.data) assert interrupt_data["interrupts"] == [{"id": "interrupt-1", "value": "needs approval"}] resume_event = subscribed_events[2] - assert isinstance(resume_event, nemo_flow.MarkEvent) + assert isinstance(resume_event, nemo_relay.MarkEvent) resume_data = cast(dict[str, Any], resume_event.data) assert resume_data["checkpoint_ns"] == ["parent", "child"] assert resume_event.metadata == {"integration": "langgraph"} diff --git a/python/tests/test_adaptive.py b/python/tests/test_adaptive.py index 509ff3161..f3fb92547 100644 --- a/python/tests/test_adaptive.py +++ b/python/tests/test_adaptive.py @@ -9,9 +9,9 @@ import pytest -from nemo_flow import AnnotatedLLMRequest, JsonObject, LLMRequest, ScopeType, llm, plugin, scope, tools -from nemo_flow import adaptive as adaptive_module -from nemo_flow.adaptive import ( +from nemo_relay import AnnotatedLLMRequest, JsonObject, LLMRequest, ScopeType, llm, plugin, scope, tools +from nemo_relay import adaptive as adaptive_module +from nemo_relay.adaptive import ( ADAPTIVE_PLUGIN_KIND, AcgConfig, AcgStabilityThresholds, @@ -37,7 +37,7 @@ def test_backend_helpers(self): assert BackendSpec.in_memory().to_dict() == {"kind": "in_memory", "config": {}} assert BackendSpec.redis("redis://127.0.0.1:6379").to_dict() == { "kind": "redis", - "config": {"url": "redis://127.0.0.1:6379", "key_prefix": "nemo_flow:"}, + "config": {"url": "redis://127.0.0.1:6379", "key_prefix": "nemo_relay:"}, } def test_backend_helper_normalizes_nested_dataclass_config(self): diff --git a/python/tests/test_adaptive_config.py b/python/tests/test_adaptive_config.py index 232cd553c..eec629c4f 100644 --- a/python/tests/test_adaptive_config.py +++ b/python/tests/test_adaptive_config.py @@ -6,9 +6,9 @@ from pathlib import Path from typing import Literal, cast -from nemo_flow import adaptive as adaptive_module -from nemo_flow import plugin -from nemo_flow.adaptive import ( +from nemo_relay import adaptive as adaptive_module +from nemo_relay import plugin +from nemo_relay.adaptive import ( AcgConfig, AcgStabilityThresholds, AdaptiveConfig, diff --git a/python/tests/test_builtin_codecs.py b/python/tests/test_builtin_codecs.py index 6af579ff0..2e98b8bdb 100644 --- a/python/tests/test_builtin_codecs.py +++ b/python/tests/test_builtin_codecs.py @@ -14,8 +14,8 @@ import pytest -import nemo_flow -from nemo_flow import ( +import nemo_relay +from nemo_relay import ( AnnotatedLLMRequest, AnnotatedLLMResponse, JsonObject, @@ -24,7 +24,7 @@ llm, subscribers, ) -from nemo_flow.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec +from nemo_relay.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec # --------------------------------------------------------------------------- # 1. Built-in codec construction @@ -169,13 +169,13 @@ def test_anthropic_messages_decode_response(self): class TestLlmResponseCodecProtocol: def test_protocol_importable(self): """LlmResponseCodec protocol is importable from codecs module.""" - from nemo_flow.codecs import LlmResponseCodec + from nemo_relay.codecs import LlmResponseCodec assert LlmResponseCodec.__name__ == "LlmResponseCodec" def test_builtin_codecs_satisfy_protocol(self): """Built-in codecs satisfy LlmResponseCodec protocol.""" - from nemo_flow.codecs import LlmResponseCodec + from nemo_relay.codecs import LlmResponseCodec assert isinstance(OpenAIChatCodec(), LlmResponseCodec) assert isinstance(OpenAIResponsesCodec(), LlmResponseCodec) @@ -433,7 +433,7 @@ async def mock_llm(req): class TestBuiltinCodecsTupleRemoved: def test_no_builtin_codecs_tuple(self): """BUILTIN_CODECS tuple is no longer in codecs module.""" - from nemo_flow import codecs as codecs_mod + from nemo_relay import codecs as codecs_mod assert not hasattr(codecs_mod, "BUILTIN_CODECS") @@ -445,15 +445,15 @@ def test_no_builtin_codecs_tuple(self): class TestBuiltinCodecImports: def test_importable_from_codecs_module(self): - """Built-in codecs are importable from nemo_flow.codecs.""" - from nemo_flow.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec + """Built-in codecs are importable from nemo_relay.codecs.""" + from nemo_relay.codecs import AnthropicMessagesCodec, OpenAIChatCodec, OpenAIResponsesCodec assert OpenAIChatCodec is not None assert OpenAIResponsesCodec is not None assert AnthropicMessagesCodec is not None def test_not_reexported_from_top_level(self): - """Built-in codecs are not re-exported from nemo_flow.""" - assert not hasattr(nemo_flow, "OpenAIChatCodec") - assert not hasattr(nemo_flow, "OpenAIResponsesCodec") - assert not hasattr(nemo_flow, "AnthropicMessagesCodec") + """Built-in codecs are not re-exported from nemo_relay.""" + assert not hasattr(nemo_relay, "OpenAIChatCodec") + assert not hasattr(nemo_relay, "OpenAIResponsesCodec") + assert not hasattr(nemo_relay, "AnthropicMessagesCodec") diff --git a/python/tests/test_codecs.py b/python/tests/test_codecs.py index 98b92512f..d49c70513 100644 --- a/python/tests/test_codecs.py +++ b/python/tests/test_codecs.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow LLM Codec system. +"""Tests for NeMo Relay LLM Codec system. Covers: - AnnotatedLLMRequest construction, field access, setters, helpers @@ -12,14 +12,14 @@ from typing import cast -from nemo_flow import ( +from nemo_relay import ( AnnotatedLLMRequest, JsonObject, LLMRequest, intercepts, llm, ) -from nemo_flow.codecs import ( +from nemo_relay.codecs import ( LlmCodec, ) @@ -347,15 +347,15 @@ def func(request): class TestCodecsModuleImport: def test_codecs_module_import(self): """Verify module import structure works correctly.""" - from nemo_flow import codecs as codecs_mod + from nemo_relay import codecs as codecs_mod # LlmCodec is accessible from the module assert hasattr(codecs_mod, "LlmCodec") assert codecs_mod.LlmCodec is LlmCodec # AnnotatedLLMRequest at top level matches _native - from nemo_flow import AnnotatedLLMRequest as top_level_alr - from nemo_flow._native import AnnotatedLLMRequest as native_alr + from nemo_relay import AnnotatedLLMRequest as top_level_alr + from nemo_relay._native import AnnotatedLLMRequest as native_alr assert top_level_alr is native_alr diff --git a/python/tests/test_context_isolation.py b/python/tests/test_context_isolation.py index d4f0323c2..5851a120b 100644 --- a/python/tests/test_context_isolation.py +++ b/python/tests/test_context_isolation.py @@ -5,20 +5,20 @@ import asyncio -import nemo_flow +import nemo_relay def test_create_scope_stack_returns_scope_stack(): """create_scope_stack returns a ScopeStack instance.""" - stack = nemo_flow.create_scope_stack() - assert isinstance(stack, nemo_flow.ScopeStack) + stack = nemo_relay.create_scope_stack() + assert isinstance(stack, nemo_relay.ScopeStack) assert repr(stack) == "" def test_get_scope_stack_returns_same_in_same_context(): """get_scope_stack returns the same instance within the same context.""" - s1 = nemo_flow.get_scope_stack() - s2 = nemo_flow.get_scope_stack() + s1 = nemo_relay.get_scope_stack() + s2 = nemo_relay.get_scope_stack() assert s1 is s2 @@ -31,8 +31,8 @@ async def task(name): # But since the ContextVar hasn't been set yet at fork time, # each task creates its own when get_scope_stack is first called. # We need to reset the ContextVar in each task to test isolation. - nemo_flow._scope_stack_var.set(nemo_flow.create_scope_stack()) - stack = nemo_flow.get_scope_stack() + nemo_relay._scope_stack_var.set(nemo_relay.create_scope_stack()) + stack = nemo_relay.get_scope_stack() results[name] = id(stack) async def main(): @@ -47,7 +47,7 @@ async def main(): def test_scope_stack_repr(): """ScopeStack has a meaningful repr.""" - stack = nemo_flow.create_scope_stack() + stack = nemo_relay.create_scope_stack() assert "" in repr(stack) @@ -59,7 +59,7 @@ def test_scope_stack_active_false_by_default(): def worker(): # Fresh thread, no ContextVar set - result["active"] = nemo_flow.scope_stack_active() + result["active"] = nemo_relay.scope_stack_active() t = threading.Thread(target=worker) t.start() @@ -74,8 +74,8 @@ def test_scope_stack_active_true_after_get_scope_stack(): result = {} def worker(): - nemo_flow.get_scope_stack() - result["active"] = nemo_flow.scope_stack_active() + nemo_relay.get_scope_stack() + result["active"] = nemo_relay.scope_stack_active() t = threading.Thread(target=worker) t.start() @@ -88,11 +88,11 @@ def test_scope_stack_active_true_after_set_thread(): import threading result = {} - stack = nemo_flow.create_scope_stack() + stack = nemo_relay.create_scope_stack() def worker(): - nemo_flow.set_thread_scope_stack(stack) - result["active"] = nemo_flow.scope_stack_active() + nemo_relay.set_thread_scope_stack(stack) + result["active"] = nemo_relay.scope_stack_active() t = threading.Thread(target=worker) t.start() @@ -108,7 +108,7 @@ def test_propagate_scope_to_thread_fails_when_inactive(): def worker(): try: - nemo_flow.propagate_scope_to_thread() + nemo_relay.propagate_scope_to_thread() result["raised"] = False except RuntimeError: result["raised"] = True @@ -121,9 +121,9 @@ def worker(): def test_propagate_scope_to_thread_returns_scope_stack(): """propagate_scope_to_thread returns the current ScopeStack.""" - nemo_flow.get_scope_stack() - stack = nemo_flow.propagate_scope_to_thread() - assert isinstance(stack, nemo_flow.ScopeStack) + nemo_relay.get_scope_stack() + stack = nemo_relay.propagate_scope_to_thread() + assert isinstance(stack, nemo_relay.ScopeStack) def test_propagate_scope_to_thread_cross_thread(): @@ -131,15 +131,15 @@ def test_propagate_scope_to_thread_cross_thread(): import threading # Initialize scope stack and push a scope - nemo_flow.get_scope_stack() - handle = nemo_flow.scope.push("parent_scope", nemo_flow.ScopeType.Agent) + nemo_relay.get_scope_stack() + handle = nemo_relay.scope.push("parent_scope", nemo_relay.ScopeType.Agent) - propagated = nemo_flow.propagate_scope_to_thread() + propagated = nemo_relay.propagate_scope_to_thread() result = {} def worker(): - nemo_flow.set_thread_scope_stack(propagated) - h = nemo_flow.scope.get_handle() + nemo_relay.set_thread_scope_stack(propagated) + h = nemo_relay.scope.get_handle() result["name"] = h.name t = threading.Thread(target=worker) @@ -147,7 +147,7 @@ def worker(): t.join() assert result["name"] == "parent_scope" - nemo_flow.scope.pop(handle) + nemo_relay.scope.pop(handle) def test_propagate_scope_to_thread_uses_native_active_stack_without_contextvar(): @@ -160,12 +160,12 @@ def test_propagate_scope_to_thread_uses_native_active_stack_without_contextvar() import threading result = {} - stack = nemo_flow.create_scope_stack() + stack = nemo_relay.create_scope_stack() def worker(): - nemo_flow.set_thread_scope_stack(stack) - propagated = nemo_flow.propagate_scope_to_thread() - result["active"] = nemo_flow.scope_stack_active() + nemo_relay.set_thread_scope_stack(stack) + propagated = nemo_relay.propagate_scope_to_thread() + result["active"] = nemo_relay.scope_stack_active() result["repr"] = repr(propagated) t = threading.Thread(target=worker) diff --git a/python/tests/test_event_json.py b/python/tests/test_event_json.py index 9136226b6..a5a34f9cf 100644 --- a/python/tests/test_event_json.py +++ b/python/tests/test_event_json.py @@ -8,7 +8,7 @@ import json from uuid import uuid4 -from nemo_flow import MarkEvent, ScopeEvent, ScopeType, scope, subscribers +from nemo_relay import MarkEvent, ScopeEvent, ScopeType, scope, subscribers def _subscriber_name(prefix: str) -> str: diff --git a/python/tests/test_integration_codecs.py b/python/tests/test_integration_codecs.py index 8452e3211..a98b72d04 100644 --- a/python/tests/test_integration_codecs.py +++ b/python/tests/test_integration_codecs.py @@ -13,8 +13,8 @@ from typing import cast -from nemo_flow import AnnotatedLLMRequest, JsonObject, LLMRequest, ScopeType, llm, scope -from nemo_flow.codecs import ( +from nemo_relay import AnnotatedLLMRequest, JsonObject, LLMRequest, ScopeType, llm, scope +from nemo_relay.codecs import ( LlmCodec, ) @@ -442,7 +442,7 @@ async def test_explicit_codec_delegates_to_provider(self): intercept_data = {} - from nemo_flow import intercepts + from nemo_relay import intercepts def annotated_intercept(name, request, annotated): if annotated is not None: diff --git a/python/tests/test_llm.py b/python/tests/test_llm.py index 1f9c98697..e56f25b47 100644 --- a/python/tests/test_llm.py +++ b/python/tests/test_llm.py @@ -1,13 +1,13 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow LLM lifecycle, guardrails, intercepts, and streaming.""" +"""Tests for NeMo Relay LLM lifecycle, guardrails, intercepts, and streaming.""" from typing import NoReturn, cast import pytest -from nemo_flow import ( +from nemo_relay import ( LLMAttributes, LLMHandle, LLMRequest, diff --git a/python/tests/test_nemoguardrails_example_plugin.py b/python/tests/test_nemoguardrails_example_plugin.py index 546bb9766..dd6e9850b 100644 --- a/python/tests/test_nemoguardrails_example_plugin.py +++ b/python/tests/test_nemoguardrails_example_plugin.py @@ -20,7 +20,7 @@ import pytest -from nemo_flow import JsonObject, LLMRequest, llm, plugin, tools +from nemo_relay import JsonObject, LLMRequest, llm, plugin, tools def _load_example_plugin() -> Any: diff --git a/python/tests/test_observability_plugin.py b/python/tests/test_observability_plugin.py index e3f00323d..b578a1493 100644 --- a/python/tests/test_observability_plugin.py +++ b/python/tests/test_observability_plugin.py @@ -7,8 +7,8 @@ import json -from nemo_flow import ScopeType, plugin, scope -from nemo_flow.observability import ( +from nemo_relay import ScopeType, plugin, scope +from nemo_relay.observability import ( OBSERVABILITY_PLUGIN_KIND, AtifConfig, AtofConfig, @@ -23,16 +23,16 @@ def test_defaults_and_component_wrapper(self): assert AtofConfig().to_dict() == {"enabled": False, "mode": "append"} assert AtifConfig().to_dict() == { "enabled": False, - "agent_name": "NeMo Flow", + "agent_name": "NeMo Relay", "model_name": "unknown", - "filename_template": "nemo-flow-atif-{session_id}.json", + "filename_template": "nemo-relay-atif-{session_id}.json", } assert OtlpConfig().to_dict() == { "enabled": False, "transport": "http_binary", "headers": {}, "resource_attributes": {}, - "service_name": "nemo-flow", + "service_name": "nemo-relay", "timeout_millis": 3000, } @@ -113,7 +113,7 @@ async def test_atif_flushes_open_agent_on_clear(self, tmp_path): handle = scope.push("python-open-agent", ScopeType.Agent) try: plugin.clear() - assert (tmp_path / f"nemo-flow-atif-{handle.uuid}.json").exists() + assert (tmp_path / f"nemo-relay-atif-{handle.uuid}.json").exists() finally: scope.pop(handle) diff --git a/python/tests/test_runtime.py b/python/tests/test_runtime.py index eee4793df..e36553640 100644 --- a/python/tests/test_runtime.py +++ b/python/tests/test_runtime.py @@ -3,14 +3,14 @@ """Tests for runtime public-surface behavior.""" -import nemo_flow +import nemo_relay class TestRuntime: def test_runtime_control_module_is_not_exported(self): - assert not hasattr(nemo_flow, "runtime") + assert not hasattr(nemo_relay, "runtime") def test_scope_stack_helpers_remain_available(self): - stack = nemo_flow.create_scope_stack() + stack = nemo_relay.create_scope_stack() assert stack is not None diff --git a/python/tests/test_scope.py b/python/tests/test_scope.py index ed24b2d76..8e9580d51 100644 --- a/python/tests/test_scope.py +++ b/python/tests/test_scope.py @@ -1,11 +1,11 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow scope operations.""" +"""Tests for NeMo Relay scope operations.""" import pytest -from nemo_flow import ( +from nemo_relay import ( ScopeAttributes, ScopeHandle, ScopeType, @@ -73,12 +73,12 @@ def test_event_with_handle(self): def test_get_handle_preserves_explicit_worker_thread_scope_stack(self): import threading - import nemo_flow + import nemo_relay result = {} def worker(): - nemo_flow.set_thread_scope_stack(nemo_flow.create_scope_stack()) + nemo_relay.set_thread_scope_stack(nemo_relay.create_scope_stack()) result["name"] = scope.get_handle().name t = threading.Thread(target=worker) diff --git a/python/tests/test_scope_local.py b/python/tests/test_scope_local.py index 53291e660..ef5de9f0c 100644 --- a/python/tests/test_scope_local.py +++ b/python/tests/test_scope_local.py @@ -1,11 +1,11 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow scope-local middleware registry. +"""Tests for NeMo Relay scope-local middleware registry. Scope-local registrations are tied to a scope handle and are automatically cleaned up when the scope is popped. These tests verify that guardrails, -intercepts, and subscribers registered via ``nemo_flow.scope_local`` only +intercepts, and subscribers registered via ``nemo_relay.scope_local`` only take effect within their owning scope and do not leak to other scopes. """ @@ -13,7 +13,7 @@ import pytest -from nemo_flow import ( +from nemo_relay import ( JsonObject, LLMRequest, MarkEvent, diff --git a/python/tests/test_subscribers.py b/python/tests/test_subscribers.py index b779a67ce..02954cbdd 100644 --- a/python/tests/test_subscribers.py +++ b/python/tests/test_subscribers.py @@ -1,14 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow subscriber and event handling.""" +"""Tests for NeMo Relay subscriber and event handling.""" from datetime import datetime, timezone from typing import Any, cast import pytest -from nemo_flow import ( +from nemo_relay import ( LLMRequest, MarkEvent, ScopeEvent, diff --git a/python/tests/test_tools.py b/python/tests/test_tools.py index fe692076e..219c65e09 100644 --- a/python/tests/test_tools.py +++ b/python/tests/test_tools.py @@ -1,13 +1,13 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow tool lifecycle, guardrails, and intercepts.""" +"""Tests for NeMo Relay tool lifecycle, guardrails, and intercepts.""" from typing import cast import pytest -from nemo_flow import ( +from nemo_relay import ( ScopeEvent, ScopeType, ToolAttributes, diff --git a/python/tests/test_typed.py b/python/tests/test_typed.py index 15c545162..2601fd2dc 100644 --- a/python/tests/test_typed.py +++ b/python/tests/test_typed.py @@ -1,15 +1,15 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow typed wrappers with explicit Codec protocol.""" +"""Tests for NeMo Relay typed wrappers with explicit Codec protocol.""" import dataclasses from typing import cast import pytest -from nemo_flow import JsonObject, LLMRequest, intercepts, typed -from nemo_flow.typed import BestEffortAnyCodec, Codec, DataclassCodec, JsonPassthrough +from nemo_relay import JsonObject, LLMRequest, intercepts, typed +from nemo_relay.typed import BestEffortAnyCodec, Codec, DataclassCodec, JsonPassthrough # --------------------------------------------------------------------------- # Test models diff --git a/python/tests/test_typed_codec_name.py b/python/tests/test_typed_codec_name.py index 6f874cf86..f2fa6c1c4 100644 --- a/python/tests/test_typed_codec_name.py +++ b/python/tests/test_typed_codec_name.py @@ -9,9 +9,9 @@ from unittest.mock import AsyncMock, patch -from nemo_flow import AnnotatedLLMRequest, LLMRequest -from nemo_flow.codecs import LlmCodec -from nemo_flow.typed import JsonPassthrough, llm_execute, llm_stream_execute +from nemo_relay import AnnotatedLLMRequest, LLMRequest +from nemo_relay.codecs import LlmCodec +from nemo_relay.typed import JsonPassthrough, llm_execute, llm_stream_execute class SimpleCodec(LlmCodec): @@ -71,7 +71,7 @@ def func(req): codec_instance = SimpleCodec() # Patch llm.execute to capture the codec argument - with patch("nemo_flow.typed.llm.execute", new_callable=AsyncMock) as mock_execute: + with patch("nemo_relay.typed.llm.execute", new_callable=AsyncMock) as mock_execute: mock_execute.return_value = {"ok": True} await llm_execute( "test-model", @@ -127,7 +127,7 @@ def finalizer(): codec_instance = SimpleCodec() - with patch("nemo_flow.typed.llm.stream_execute", new_callable=AsyncMock) as mock_stream: + with patch("nemo_relay.typed.llm.stream_execute", new_callable=AsyncMock) as mock_stream: mock_stream.return_value = AsyncMock() await llm_stream_execute( "test-model", diff --git a/python/tests/test_types.py b/python/tests/test_types.py index e50752963..a2343cb3b 100644 --- a/python/tests/test_types.py +++ b/python/tests/test_types.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Tests for NeMo Flow Python type bindings.""" +"""Tests for NeMo Relay Python type bindings.""" import http.server import json @@ -11,7 +11,7 @@ import pytest -from nemo_flow import ( +from nemo_relay import ( AtifExporter, AtofExporter, AtofExporterConfig, @@ -449,7 +449,7 @@ def test_config_defaults_mutation_and_repr(self, tmp_path): config = AtofExporterConfig() assert config.mode == AtofExporterMode.Append - assert config.filename.startswith("nemo-flow-events-") + assert config.filename.startswith("nemo-relay-events-") assert config.filename.endswith(".jsonl") assert "AtofExporterConfig" in repr(config) @@ -518,8 +518,8 @@ def test_config_defaults_mutation_and_repr(self): assert config.transport == "http_binary" assert config.endpoint is None - assert config.service_name == "nemo-flow" - assert config.instrumentation_scope == "nemo-flow-otel" + assert config.service_name == "nemo-relay" + assert config.instrumentation_scope == "nemo-relay-otel" assert config.timeout_millis == 3000 assert config.headers == {} assert config.resource_attributes == {} @@ -607,8 +607,8 @@ def test_config_defaults_mutation_and_repr(self): assert config.transport == "http_binary" assert config.endpoint is None - assert config.service_name == "nemo-flow" - assert config.instrumentation_scope == "nemo-flow-openinference" + assert config.service_name == "nemo-relay" + assert config.instrumentation_scope == "nemo-relay-openinference" assert config.timeout_millis == 3000 assert config.headers == {} assert config.resource_attributes == {} diff --git a/python/tests/test_utils.py b/python/tests/test_utils.py index 4b100303f..f1c13623d 100644 --- a/python/tests/test_utils.py +++ b/python/tests/test_utils.py @@ -7,21 +7,21 @@ import pytest -import nemo_flow -from nemo_flow.utils import run_sync +import nemo_relay +from nemo_relay.utils import run_sync @pytest.mark.parametrize("from_async", [False, True]) def test_run_sync(from_async: bool): """ - Test that run_sync correctly propagates the NeMo Flow scope stack to the worker thread, + Test that run_sync correctly propagates the NeMo Relay scope stack to the worker thread, and that it can be called from inside a running loop and outside a running loop. """ - scope_stack = nemo_flow.get_scope_stack() + scope_stack = nemo_relay.get_scope_stack() assert scope_stack is not None async def coro_fn() -> int: - thread_scope_stack = nemo_flow.get_scope_stack() + thread_scope_stack = nemo_relay.get_scope_stack() assert thread_scope_stack is scope_stack return 1 diff --git a/scripts/docs/build_node_docs_artifacts.mjs b/scripts/docs/build_node_docs_artifacts.mjs index c08340ab9..2de019cd2 100644 --- a/scripts/docs/build_node_docs_artifacts.mjs +++ b/scripts/docs/build_node_docs_artifacts.mjs @@ -14,9 +14,9 @@ const SPDX_HEADER = [ ]; const REQUIRED_SPHINX_ENV = [ - 'NEMO_FLOW_SPHINX_JS_MAIN_TS', - 'NEMO_FLOW_SPHINX_JS_IMPORT_HOOK', - 'NEMO_FLOW_SPHINX_JS_TSX_TSCONFIG', + 'NEMO_RELAY_SPHINX_JS_MAIN_TS', + 'NEMO_RELAY_SPHINX_JS_IMPORT_HOOK', + 'NEMO_RELAY_SPHINX_JS_TSX_TSCONFIG', ]; const MODULES = [ @@ -99,7 +99,8 @@ const DECLARATION_REWRITES = new Map([ replacement: 'type Json = import("./index").Json;', }, { - original: "import type { ConfigPolicy, ConfigDiagnostic, ConfigReport } from './plugin';\n\nexport { ConfigPolicy, ConfigDiagnostic, ConfigReport };", + original: + "import type { ConfigPolicy, ConfigDiagnostic, ConfigReport } from './plugin';\n\nexport { ConfigPolicy, ConfigDiagnostic, ConfigReport };", replacement: [ 'export type ConfigPolicy = import("./plugin").ConfigPolicy;', 'export type ConfigDiagnostic = import("./plugin").ConfigDiagnostic;', @@ -124,7 +125,8 @@ const DECLARATION_REWRITES = new Map([ replacement: 'type Json = import("./index").Json;', }, { - original: "import type { ConfigPolicy, ConfigDiagnostic, ConfigReport } from './plugin';\n\nexport { ConfigPolicy, ConfigDiagnostic, ConfigReport };", + original: + "import type { ConfigPolicy, ConfigDiagnostic, ConfigReport } from './plugin';\n\nexport { ConfigPolicy, ConfigDiagnostic, ConfigReport };", replacement: [ 'export type ConfigPolicy = import("./plugin").ConfigPolicy;', 'export type ConfigDiagnostic = import("./plugin").ConfigDiagnostic;', @@ -145,11 +147,13 @@ const DECLARATION_REWRITES = new Map([ const PUBLIC_NAME_REWRITES = new Map([['ComponentSpecShape', 'ComponentSpec']]); -const repoRoot = process.env.NEMO_FLOW_DOCS_REPO_ROOT - ? path.resolve(process.env.NEMO_FLOW_DOCS_REPO_ROOT) +const repoRoot = process.env.NEMO_RELAY_DOCS_REPO_ROOT + ? path.resolve(process.env.NEMO_RELAY_DOCS_REPO_ROOT) : path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); const nodePackageDir = path.join(repoRoot, 'crates', 'node'); -const docsDir = process.env.NEMO_FLOW_DOCS_DIR ? path.resolve(process.env.NEMO_FLOW_DOCS_DIR) : path.join(repoRoot, 'docs'); +const docsDir = process.env.NEMO_RELAY_DOCS_DIR + ? path.resolve(process.env.NEMO_RELAY_DOCS_DIR) + : path.join(repoRoot, 'docs'); const nodeDocsGeneratedDir = path.join(docsDir, 'reference', 'api', 'nodejs', '_generated'); const nodeDocsSourceDir = path.join(nodeDocsGeneratedDir, 'source'); const nodeDocsDeclDir = path.join(nodeDocsSourceDir, 'declarations'); @@ -263,7 +267,7 @@ function writeModuleEntrypoints(modules) { function writeDocsPackageManifest() { writeUtf8( path.join(nodeDocsSourceDir, 'package.json'), - `${JSON.stringify({ name: 'nemo-flow-node-api-docs', private: true }, null, 2)}\n`, + `${JSON.stringify({ name: 'nemo-relay-node-api-docs', private: true }, null, 2)}\n`, ); } @@ -396,7 +400,9 @@ function publicName(name) { } function renderType(items) { - const value = renderInline(items).trim().replaceAll(/\bComponentSpecShape\b/g, 'ComponentSpec'); + const value = renderInline(items) + .trim() + .replaceAll(/\bComponentSpecShape\b/g, 'ComponentSpec'); return value ? `\`${value}\`` : '`unknown`'; } diff --git a/scripts/licensing/attributions_lockfile_md.py b/scripts/licensing/attributions_lockfile_md.py index 8210f6f7e..068d52162 100755 --- a/scripts/licensing/attributions_lockfile_md.py +++ b/scripts/licensing/attributions_lockfile_md.py @@ -865,7 +865,7 @@ def _lockfile_python_packages( def _python_attribution_packages() -> list[RenderedPythonPackage]: """Return Python attribution packages directly from uv.lock artifacts.""" lockfile_pkgs = _lockfile_registry_packages() - own_name = "nemo-flow" + own_name = "nemo-relay" packages = _lockfile_python_packages(lockfile_pkgs, own_name=own_name) packages.sort(key=lambda r: (str(r["name"]).lower(), str(r["version"]))) return packages @@ -874,7 +874,7 @@ def _python_attribution_packages() -> list[RenderedPythonPackage]: def _python_license_inventory() -> list[LicenseInventoryEntry]: """Return minimal Python dependency license rows directly from uv.lock artifacts.""" lockfile_pkgs = _lockfile_registry_packages() - own_name = "nemo-flow" + own_name = "nemo-relay" return [ _rendered_python_package_inventory(pkg) for pkg in _lockfile_python_packages(lockfile_pkgs, own_name=own_name) ] diff --git a/scripts/licensing/license_diff.py b/scripts/licensing/license_diff.py index 00fd47ca9..d099cf0ae 100755 --- a/scripts/licensing/license_diff.py +++ b/scripts/licensing/license_diff.py @@ -227,7 +227,7 @@ def _filter_inventory(inventory: Inventory, languages: list[str]) -> Inventory: def _worktree_inventory(root: Path, ref: str, languages: list[str]) -> Inventory: """Generate inventory for a git ref in a temporary detached worktree.""" - tmp_parent = Path(tempfile.mkdtemp(prefix="nemo-flow-license-base-")) + tmp_parent = Path(tempfile.mkdtemp(prefix="nemo-relay-license-base-")) worktree = tmp_parent / "repo" try: _status(f"checking out base ref {ref} into a temporary worktree") diff --git a/scripts/lint/check_copyright.py b/scripts/lint/check_copyright.py index 27d53f382..28050235d 100755 --- a/scripts/lint/check_copyright.py +++ b/scripts/lint/check_copyright.py @@ -47,7 +47,7 @@ "LICENSE", "index.js", "index.d.ts", - "nemo_flow.h", + "nemo_relay.h", } ) diff --git a/scripts/third-party/apply-patches.sh b/scripts/third-party/apply-patches.sh index 089cfa96b..7f3d929ee 100755 --- a/scripts/third-party/apply-patches.sh +++ b/scripts/third-party/apply-patches.sh @@ -2,7 +2,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -# Apply NeMo Flow integration patches to local third-party checkouts. +# Apply NeMo Relay integration patches to local third-party checkouts. # # Usage: # ./scripts/third-party/apply-patches.sh # apply all patches diff --git a/scripts/third-party/generate-patches.sh b/scripts/third-party/generate-patches.sh index 0ab666b8c..ec29f44d6 100755 --- a/scripts/third-party/generate-patches.sh +++ b/scripts/third-party/generate-patches.sh @@ -50,7 +50,7 @@ generate_patches() { fi mkdir -p "$patch_dir" - local patch_file="$patch_dir/0001-add-nemo-flow-integration.patch" + local patch_file="$patch_dir/0001-add-nemo-relay-integration.patch" # Combine tracked diffs and new file diffs { diff --git a/skills/README.md b/skills/README.md index dc49769f5..fef645f55 100644 --- a/skills/README.md +++ b/skills/README.md @@ -5,10 +5,10 @@ SPDX-License-Identifier: Apache-2.0 # Consumer Skills -This directory contains consumer-facing NeMo Flow skills for application +This directory contains consumer-facing NeMo Relay skills for application developers, integrators, and end users. -Public skill directories use a `nemo-flow-` prefix so they remain recognizable +Public skill directories use a `nemo-relay-` prefix so they remain recognizable and collision-resistant when exported outside this repository. Skills in this directory are self-contained. A skill can point to another skill @@ -24,10 +24,10 @@ Use these skills for tasks such as: - Tuning performance with adaptive features - Building reusable plugin behavior - Setting up observability and trace export -- Debugging application-side NeMo Flow integrations +- Debugging application-side NeMo Relay integrations When a skill mentions Go, WebAssembly, or raw FFI, treat those as source-first -advanced surfaces. Their APIs are tracked in `go/nemo_flow`, `crates/wasm`, and +advanced surfaces. Their APIs are tracked in `go/nemo_relay`, `crates/wasm`, and `crates/ffi`, but the primary end-user docs and quick starts focus on Rust, Python, and Node.js. diff --git a/skills/nemo-flow-build-plugin/SKILL.md b/skills/nemo-relay-build-plugin/SKILL.md similarity index 88% rename from skills/nemo-flow-build-plugin/SKILL.md rename to skills/nemo-relay-build-plugin/SKILL.md index 04e8006b9..536289224 100644 --- a/skills/nemo-flow-build-plugin/SKILL.md +++ b/skills/nemo-relay-build-plugin/SKILL.md @@ -1,13 +1,13 @@ --- -name: nemo-flow-build-plugin -description: Build and package reusable NeMo Flow runtime behavior as a config-activated plugin with validation and rollback-safe registration +name: nemo-relay-build-plugin +description: Build and package reusable NeMo Relay runtime behavior as a config-activated plugin with validation and rollback-safe registration author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- # Build a Plugin -Use this skill when a user wants to package reusable NeMo Flow runtime behavior +Use this skill when a user wants to package reusable NeMo Relay runtime behavior behind plugin configuration. ## Use This When @@ -26,13 +26,13 @@ Common cases: ## Do Not Use This When -Do not build a plugin when a narrower NeMo Flow surface is enough: +Do not build a plugin when a narrower NeMo Relay surface is enough: - One request or tenant needs temporary behavior -> use scope-local middleware. - The user only needs first-time scopes, tool calls, or LLM calls -> - `nemo-flow-instrument-calls`. + `nemo-relay-instrument-calls`. - The user only needs to choose an exporter path -> - `nemo-flow-setup-observability`. + `nemo-relay-setup-observability`. - The behavior depends on live callables, provider clients, file handles, credentials, or framework objects inside config. @@ -104,9 +104,9 @@ endpoints rather than embedding sensitive values. ## Binding Pointers -- Python: `nemo_flow.plugin` -- Node.js: `nemo-flow-node/plugin` -- Rust: `nemo_flow::plugin` +- Python: `nemo_relay.plugin` +- Node.js: `nemo-relay-node/plugin` +- Rust: `nemo_relay::plugin` - Go, WebAssembly, and raw FFI are source-first or advanced surfaces. Use the same canonical `snake_case` config keys across bindings and files. Node @@ -143,14 +143,14 @@ helper functions can be `camelCase`, but plugin config objects remain ## Use Another Skill When - You only need to wrap direct tool or LLM calls -> - `nemo-flow-instrument-calls` + `nemo-relay-instrument-calls` - You need to set up traces or exporters without packaging a plugin -> - `nemo-flow-setup-observability` + `nemo-relay-setup-observability` - You need to debug plugin activation, missing events, or load failures -> - `nemo-flow-debug-runtime-integration` + `nemo-relay-debug-runtime-integration` ## Related Skills -- `nemo-flow-instrument-calls` -- `nemo-flow-setup-observability` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-instrument-calls` +- `nemo-relay-setup-observability` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-debug-runtime-integration/SKILL.md b/skills/nemo-relay-debug-runtime-integration/SKILL.md similarity index 89% rename from skills/nemo-flow-debug-runtime-integration/SKILL.md rename to skills/nemo-relay-debug-runtime-integration/SKILL.md index 565d9f601..1b34f9903 100644 --- a/skills/nemo-flow-debug-runtime-integration/SKILL.md +++ b/skills/nemo-relay-debug-runtime-integration/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-debug-runtime-integration -description: Debug application-side NeMo Flow integration issues such as load failures, inactive scopes, missing events, or adaptive/plugin wiring problems +name: nemo-relay-debug-runtime-integration +description: Debug application-side NeMo Relay integration issues such as load failures, inactive scopes, missing events, or adaptive/plugin wiring problems author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -8,7 +8,7 @@ license: Apache-2.0 # Debug Runtime Integration -Use this skill when NeMo Flow is present in the application but something is not +Use this skill when NeMo Relay is present in the application but something is not working. ## First Checks @@ -75,7 +75,7 @@ working. ## Related Skills -- `nemo-flow-start` -- `nemo-flow-use-context-isolation` -- `nemo-flow-tune-adaptive-config` -- `nemo-flow-build-plugin` +- `nemo-relay-start` +- `nemo-relay-use-context-isolation` +- `nemo-relay-tune-adaptive-config` +- `nemo-relay-build-plugin` diff --git a/skills/nemo-flow-export-atif-trajectories/SKILL.md b/skills/nemo-relay-export-atif-trajectories/SKILL.md similarity index 88% rename from skills/nemo-flow-export-atif-trajectories/SKILL.md rename to skills/nemo-relay-export-atif-trajectories/SKILL.md index f20f539c6..2acf186d7 100644 --- a/skills/nemo-flow-export-atif-trajectories/SKILL.md +++ b/skills/nemo-relay-export-atif-trajectories/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-export-atif-trajectories -description: Export NeMo Flow activity as ATIF trajectories for replay, analysis, or interchange +name: nemo-relay-export-atif-trajectories +description: Export NeMo Relay activity as ATIF trajectories for replay, analysis, or interchange author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -21,7 +21,7 @@ live OTLP spans. ## Embedded ATIF Semantics -- ATIF export translates NeMo Flow events into ATIF v1.6 trajectory data. +- ATIF export translates NeMo Relay events into ATIF v1.6 trajectory data. - LLM start events become `user` steps; message content is extracted from the `LLMRequest.content` payload when possible. - LLM end events become `agent` steps with response content, model metadata, @@ -63,6 +63,6 @@ live OTLP spans. ## Related Skills -- `nemo-flow-setup-observability` -- `nemo-flow-instrument-calls` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-setup-observability` +- `nemo-relay-instrument-calls` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-export-openinference/SKILL.md b/skills/nemo-relay-export-openinference/SKILL.md similarity index 88% rename from skills/nemo-flow-export-openinference/SKILL.md rename to skills/nemo-relay-export-openinference/SKILL.md index 94f18f041..d7e12db48 100644 --- a/skills/nemo-flow-export-openinference/SKILL.md +++ b/skills/nemo-relay-export-openinference/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-export-openinference -description: Configure and use NeMo Flow OpenInference export for OTLP backends that understand OpenInference semantics +name: nemo-relay-export-openinference +description: Configure and use NeMo Relay OpenInference export for OTLP backends that understand OpenInference semantics author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -52,6 +52,6 @@ for example Arize Phoenix or another OpenInference-aware OTLP backend. ## Related Skills -- `nemo-flow-setup-observability` -- `nemo-flow-export-otel` -- `nemo-flow-typed-wrappers-codecs` +- `nemo-relay-setup-observability` +- `nemo-relay-export-otel` +- `nemo-relay-typed-wrappers-codecs` diff --git a/skills/nemo-flow-export-otel/SKILL.md b/skills/nemo-relay-export-otel/SKILL.md similarity index 86% rename from skills/nemo-flow-export-otel/SKILL.md rename to skills/nemo-relay-export-otel/SKILL.md index 78a32d520..d07c9d258 100644 --- a/skills/nemo-flow-export-otel/SKILL.md +++ b/skills/nemo-relay-export-otel/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-export-otel -description: Configure and use NeMo Flow OpenTelemetry export for OTLP-compatible tracing backends +name: nemo-relay-export-otel +description: Configure and use NeMo Relay OpenTelemetry export for OTLP-compatible tracing backends author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -21,7 +21,7 @@ OpenTelemetry Collector, Jaeger, Tempo, or Honeycomb. ## Embedded OpenTelemetry Semantics -- OpenTelemetry export maps NeMo Flow runtime events into OTLP traces for +- OpenTelemetry export maps NeMo Relay runtime events into OTLP traces for tracing backends and collectors. - Configure `transport`, `endpoint`, `service_name`, optional namespace and version, instrumentation scope, headers, resource attributes, and timeout. @@ -56,6 +56,6 @@ OpenTelemetry Collector, Jaeger, Tempo, or Honeycomb. ## Related Skills -- `nemo-flow-setup-observability` -- `nemo-flow-export-openinference` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-setup-observability` +- `nemo-relay-export-openinference` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-instrument-calls/SKILL.md b/skills/nemo-relay-instrument-calls/SKILL.md similarity index 88% rename from skills/nemo-flow-instrument-calls/SKILL.md rename to skills/nemo-relay-instrument-calls/SKILL.md index aed16e862..a2240b07d 100644 --- a/skills/nemo-flow-instrument-calls/SKILL.md +++ b/skills/nemo-relay-instrument-calls/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-instrument-calls -description: Wrap application tool calls and LLM/provider calls with NeMo Flow scopes and managed execution APIs +name: nemo-relay-instrument-calls +description: Wrap application tool calls and LLM/provider calls with NeMo Relay scopes and managed execution APIs author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -9,7 +9,7 @@ license: Apache-2.0 # Instrument Tool And LLM Calls Use this skill when an app already has tool functions or model/provider calls and -needs to run them through NeMo Flow correctly. +needs to run them through NeMo Relay correctly. ## Default Guidance @@ -41,7 +41,7 @@ needs to run them through NeMo Flow correctly. - If execution fails after the start event has been emitted, the runtime still emits an end event without a semantic output payload. - Tool calls are named operations with JSON-compatible arguments and results. - Keep the original tool callable responsible for business logic; let NeMo Flow + Keep the original tool callable responsible for business logic; let NeMo Relay own lifecycle events, middleware, and metadata. - LLM calls use an `LLMRequest` made of metadata plus content. Pass model names and stable call identifiers when they matter for trace export or diagnostics. @@ -65,17 +65,17 @@ needs to run them through NeMo Flow correctly. ## Use Another Skill When -- You need traces, ATIF, or export setup -> `nemo-flow-setup-observability` +- You need traces, ATIF, or export setup -> `nemo-relay-setup-observability` - You are debugging missing events or load failures -> - `nemo-flow-debug-runtime-integration` + `nemo-relay-debug-runtime-integration` - You need per-request isolation or worker-pool advice -> - `nemo-flow-use-context-isolation` + `nemo-relay-use-context-isolation` - You need reusable config-activated runtime behavior -> - `nemo-flow-build-plugin` + `nemo-relay-build-plugin` ## Related Skills -- `nemo-flow-start` -- `nemo-flow-typed-wrappers-codecs` -- `nemo-flow-setup-observability` -- `nemo-flow-build-plugin` +- `nemo-relay-start` +- `nemo-relay-typed-wrappers-codecs` +- `nemo-relay-setup-observability` +- `nemo-relay-build-plugin` diff --git a/skills/nemo-flow-setup-observability/SKILL.md b/skills/nemo-relay-setup-observability/SKILL.md similarity index 72% rename from skills/nemo-flow-setup-observability/SKILL.md rename to skills/nemo-relay-setup-observability/SKILL.md index 72de32679..b45581d0f 100644 --- a/skills/nemo-flow-setup-observability/SKILL.md +++ b/skills/nemo-relay-setup-observability/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-setup-observability -description: Choose and set up the right NeMo Flow observability path for an application +name: nemo-relay-setup-observability +description: Choose and set up the right NeMo Relay observability path for an application author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -8,7 +8,7 @@ license: Apache-2.0 # Set Up Observability -Use this skill when an application developer wants visibility into NeMo Flow +Use this skill when an application developer wants visibility into NeMo Relay activity but has not yet decided which output they need. ## Choose The Output @@ -24,7 +24,7 @@ activity but has not yet decided which output they need. ## Embedded Event And Subscriber Model -- NeMo Flow emits one canonical event stream from scopes, marks, managed tool +- NeMo Relay emits one canonical event stream from scopes, marks, managed tool calls, managed LLM calls, middleware, and manual lifecycle APIs. - Subscribers consume events without defining the event model. Multiple subscribers can observe the same stream for logging, export, analytics, or @@ -46,32 +46,32 @@ activity but has not yet decided which output they need. 1. Create the exporter or subscriber. 2. Register it with a unique name before the relevant scoped work. -3. Run NeMo Flow-instrumented work inside scopes. +3. Run NeMo Relay-instrumented work inside scopes. 4. Deregister it. 5. Flush or shut down if the binding supports it and deterministic delivery is needed. ## Binding Names -- Python: `nemo_flow.subscribers.register(...)`, +- Python: `nemo_relay.subscribers.register(...)`, `AtifExporter`, `OpenTelemetrySubscriber`, and `OpenInferenceSubscriber` - Node.js: root exports `registerSubscriber(...)`, `AtifExporter`, `OpenTelemetrySubscriber`, and `OpenInferenceSubscriber` -- Rust: `nemo_flow::api::subscriber` and `nemo_flow::observability::*` +- Rust: `nemo_relay::api::subscriber` and `nemo_relay::observability::*` - Go and WebAssembly: source-first wrappers expose equivalent register, exporter, and subscriber lifecycle methods ## Use Another Skill When -- You already know you need ATIF -> `nemo-flow-export-atif-trajectories` -- You already know you need OTEL -> `nemo-flow-export-otel` -- You already know you need OpenInference -> `nemo-flow-export-openinference` +- You already know you need ATIF -> `nemo-relay-export-atif-trajectories` +- You already know you need OTEL -> `nemo-relay-export-otel` +- You already know you need OpenInference -> `nemo-relay-export-openinference` - You need to package subscriber-based export behavior as a reusable plugin -> - `nemo-flow-build-plugin` -- You are debugging missing telemetry -> `nemo-flow-debug-runtime-integration` + `nemo-relay-build-plugin` +- You are debugging missing telemetry -> `nemo-relay-debug-runtime-integration` ## Related Skills -- `nemo-flow-export-atif-trajectories` -- `nemo-flow-export-otel` -- `nemo-flow-export-openinference` -- `nemo-flow-build-plugin` +- `nemo-relay-export-atif-trajectories` +- `nemo-relay-export-otel` +- `nemo-relay-export-openinference` +- `nemo-relay-build-plugin` diff --git a/skills/nemo-flow-start/SKILL.md b/skills/nemo-relay-start/SKILL.md similarity index 72% rename from skills/nemo-flow-start/SKILL.md rename to skills/nemo-relay-start/SKILL.md index f4d9ac266..43a3fa394 100644 --- a/skills/nemo-flow-start/SKILL.md +++ b/skills/nemo-relay-start/SKILL.md @@ -1,12 +1,12 @@ --- -name: nemo-flow-start -description: Help application developers pick a NeMo Flow binding and get to a first working scope, tool call, and LLM call +name: nemo-relay-start +description: Help application developers pick a NeMo Relay binding and get to a first working scope, tool call, and LLM call author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- -# Get Started With NeMo Flow +# Get Started With NeMo Relay Use this skill for first-time users who want the shortest path to a working example. Rust, Python, and Node.js are the primary quick-start and hosted-docs @@ -22,11 +22,11 @@ paths. Go, WebAssembly, and the raw FFI surface are source-first advanced paths. ## Guidance -- **Rust**: use `nemo_flow::api::scope::{push_scope, pop_scope, event}` with - builder params, then `nemo_flow::api::tool::tool_call_execute(...)` and - `nemo_flow::api::llm::llm_call_execute(...)` -- **Python**: `uv sync`, then use `nemo_flow.scope.scope(...)`, - `nemo_flow.tools.execute(...)`, and `nemo_flow.llm.execute(...)` +- **Rust**: use `nemo_relay::api::scope::{push_scope, pop_scope, event}` with + builder params, then `nemo_relay::api::tool::tool_call_execute(...)` and + `nemo_relay::api::llm::llm_call_execute(...)` +- **Python**: `uv sync`, then use `nemo_relay.scope.scope(...)`, + `nemo_relay.tools.execute(...)`, and `nemo_relay.llm.execute(...)` - **Node.js**: build the addon, then use `withScope(...)`, `toolCallExecute(...)`, and `llmCallExecute(...)` - **Go**: use source-first wrappers such as `scope.Push(...)`, @@ -35,8 +35,8 @@ paths. Go, WebAssembly, and the raw FFI surface are source-first advanced paths. - **WebAssembly**: use the generated JS-facing API such as `withScope(...)`, `toolCallExecute(...)`, `llmCallExecute(...)`, and `createScopeStack()` - **FFI**: recommend only for binding or embedding work; verify C names such as - `nemo_flow_push_scope`, `nemo_flow_tool_call_execute`, and - `nemo_flow_llm_call_execute` in the current header + `nemo_relay_push_scope`, `nemo_relay_tool_call_execute`, and + `nemo_relay_llm_call_execute` in the current header ## Common Pitfalls @@ -49,17 +49,17 @@ paths. Go, WebAssembly, and the raw FFI surface are source-first advanced paths. ## Embedded Quick-Start Notes - Install from packages when building a consumer app: Rust uses `cargo add - nemo-flow`, Python uses `uv add nemo-flow`, and Node.js uses `npm install - nemo-flow-node`. + nemo-relay`, Python uses `uv add nemo-relay`, and Node.js uses `npm install + nemo-relay-node`. - Use repository setup commands when working from a checkout: Rust builds the workspace, Python rebuilds the virtual environment and native extension with `uv sync`, and Node.js installs and builds the native addon before tests or examples run. - A first example should register a short-lived subscriber, open an agent scope, emit one mark event, run one managed tool call, run one managed LLM call, then - deregister the subscriber. In Python use `nemo_flow.subscribers`; in Node.js + deregister the subscriber. In Python use `nemo_relay.subscribers`; in Node.js use root exports such as `registerSubscriber`; in Rust use - `nemo_flow::api::subscriber`. + `nemo_relay::api::subscriber`. - Success means the app emits scope start/end events plus tool and LLM lifecycle events, and the application result remains the provider or tool result. - Scope handles are explicit in Rust and optional in higher-level Python and @@ -68,6 +68,6 @@ paths. Go, WebAssembly, and the raw FFI surface are source-first advanced paths. ## Related Skills -- `nemo-flow-instrument-calls` -- `nemo-flow-setup-observability` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-instrument-calls` +- `nemo-relay-setup-observability` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-tune-adaptive-config/SKILL.md b/skills/nemo-relay-tune-adaptive-config/SKILL.md similarity index 74% rename from skills/nemo-flow-tune-adaptive-config/SKILL.md rename to skills/nemo-relay-tune-adaptive-config/SKILL.md index 2d61163cf..2dc189c4d 100644 --- a/skills/nemo-flow-tune-adaptive-config/SKILL.md +++ b/skills/nemo-relay-tune-adaptive-config/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-tune-adaptive-config -description: Configure the NeMo Flow adaptive plugin component through the shared plugin system; use this skill for state, telemetry, adaptive_hints, tool_parallelism, ACG, or policy settings with validation and measured rollout +name: nemo-relay-tune-adaptive-config +description: Configure the NeMo Relay adaptive plugin component through the shared plugin system; use this skill for state, telemetry, adaptive_hints, tool_parallelism, ACG, or policy settings with validation and measured rollout author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -10,7 +10,7 @@ license: Apache-2.0 ## Use This When -Use this skill when an application already intends to use NeMo Flow adaptive +Use this skill when an application already intends to use NeMo Relay adaptive features and needs the correct plugin configuration shape. ## Do Not Use This When @@ -26,14 +26,14 @@ request-specific middleware, or production trace debugging. - Wrap the adaptive object in an adaptive `ComponentSpec`, insert it into the shared plugin config `components` list, validate the plugin config, then initialize the plugin system. -- Python uses `nemo_flow.adaptive.AdaptiveConfig(...)`, - `nemo_flow.adaptive.ComponentSpec(...)`, and - `nemo_flow.plugin.PluginConfig(...)`. -- Node.js uses `require("nemo-flow-node/adaptive")` helpers such as +- Python uses `nemo_relay.adaptive.AdaptiveConfig(...)`, + `nemo_relay.adaptive.ComponentSpec(...)`, and + `nemo_relay.plugin.PluginConfig(...)`. +- Node.js uses `require("nemo-relay-node/adaptive")` helpers such as `defaultConfig()`, `inMemoryBackend()`, `toolParallelismConfig(...)`, and - `ComponentSpec(...)`, then activates through `nemo-flow-node/plugin`. -- Rust uses `nemo_flow_adaptive::{AdaptiveConfig, ComponentSpec, ...}` and - `nemo_flow::plugin::{validate_plugin_config, initialize_plugins}`. + `ComponentSpec(...)`, then activates through `nemo-relay-node/plugin`. +- Rust uses `nemo_relay_adaptive::{AdaptiveConfig, ComponentSpec, ...}` and + `nemo_relay::plugin::{validate_plugin_config, initialize_plugins}`. - Go, WebAssembly, and raw FFI are source-first or advanced surfaces. - Plugins install runtime behavior such as subscribers, guardrails, intercepts, and related helpers. Adaptive is a built-in plugin component, not a separate @@ -82,7 +82,7 @@ request-specific middleware, or production trace debugging. ## Related Skills -- `nemo-flow-tune-performance` -- `nemo-flow-tune-adaptive-hints` -- `nemo-flow-debug-runtime-integration` -- `nemo-flow-build-plugin` +- `nemo-relay-tune-performance` +- `nemo-relay-tune-adaptive-hints` +- `nemo-relay-debug-runtime-integration` +- `nemo-relay-build-plugin` diff --git a/skills/nemo-flow-tune-adaptive-hints/SKILL.md b/skills/nemo-relay-tune-adaptive-hints/SKILL.md similarity index 79% rename from skills/nemo-flow-tune-adaptive-hints/SKILL.md rename to skills/nemo-relay-tune-adaptive-hints/SKILL.md index ab16c5637..36a4f1df2 100644 --- a/skills/nemo-flow-tune-adaptive-hints/SKILL.md +++ b/skills/nemo-relay-tune-adaptive-hints/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-tune-adaptive-hints -description: Consume NeMo Flow adaptive hints, predictions, latency sensitivity, ACG diagnostics, or tool-parallelism guidance safely in application logic after the adaptive plugin is already configured +name: nemo-relay-tune-adaptive-hints +description: Consume NeMo Relay adaptive hints, predictions, latency sensitivity, ACG diagnostics, or tool-parallelism guidance safely in application logic after the adaptive plugin is already configured author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -17,8 +17,8 @@ parallelism guidance, or ACG diagnostics. ## Do Not Use This When Do not use this skill to design the first adaptive rollout or to configure the -plugin from scratch. Use `nemo-flow-tune-performance` or -`nemo-flow-tune-adaptive-config` first. +plugin from scratch. Use `nemo-relay-tune-performance` or +`nemo-relay-tune-adaptive-config` first. ## Focus Areas @@ -42,8 +42,8 @@ plugin from scratch. Use `nemo-flow-tune-performance` or - `set_latency_sensitivity(...)` is a request-local execution hint, not persistent adaptive configuration. - Normal adaptive runtime behavior should come from explicit config objects, not - environment variables. `NEMO_FLOW_ACG_DEBUG` is for cache-governor diagnostics - and `NEMO_FLOW_RUN_REDIS_TESTS` is for Redis-backed tests. + environment variables. `NEMO_RELAY_ACG_DEBUG` is for cache-governor diagnostics + and `NEMO_RELAY_RUN_REDIS_TESTS` is for Redis-backed tests. ## Default Path @@ -64,6 +64,6 @@ plugin from scratch. Use `nemo-flow-tune-performance` or ## Related Skills -- `nemo-flow-tune-performance` -- `nemo-flow-tune-adaptive-config` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-tune-performance` +- `nemo-relay-tune-adaptive-config` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-tune-performance/SKILL.md b/skills/nemo-relay-tune-performance/SKILL.md similarity index 71% rename from skills/nemo-flow-tune-performance/SKILL.md rename to skills/nemo-relay-tune-performance/SKILL.md index 3f8b71c70..1ef8e6122 100644 --- a/skills/nemo-flow-tune-performance/SKILL.md +++ b/skills/nemo-relay-tune-performance/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-tune-performance -description: Plan a measured NeMo Flow adaptive tuning rollout after baseline scopes, tool calls, LLM calls, and observability are working; use this skill to improve latency, tool parallelism, prompt-cache behavior, or model-request behavior from runtime signals +name: nemo-relay-tune-performance +description: Plan a measured NeMo Relay adaptive tuning rollout after baseline scopes, tool calls, LLM calls, and observability are working; use this skill to improve latency, tool parallelism, prompt-cache behavior, or model-request behavior from runtime signals author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -10,14 +10,14 @@ license: Apache-2.0 ## Use This When -Use this skill when a user has baseline NeMo Flow instrumentation and wants to +Use this skill when a user has baseline NeMo Relay instrumentation and wants to improve latency, parallelism, prompt-cache behavior, or model-request behavior from runtime signals. ## Do Not Use This When Do not use this skill when the application is not instrumented yet. Start with -`nemo-flow-instrument-calls` or `nemo-flow-start` first. +`nemo-relay-instrument-calls` or `nemo-relay-start` first. ## Default Guidance @@ -35,7 +35,7 @@ Do not use this skill when the application is not instrumented yet. Start with - Adaptive behavior is configured through the first-party plugin component with kind `adaptive`. -- Adaptive requires existing NeMo Flow scopes, managed tool or LLM calls, and +- Adaptive requires existing NeMo Relay scopes, managed tool or LLM calls, and lifecycle events because it learns from runtime signals. - Main configuration areas are state, telemetry, adaptive hints, tool parallelism, Adaptive Cache Governor (ACG), and rollout policy. @@ -43,8 +43,8 @@ Do not use this skill when the application is not instrumented yet. Start with - Tool-parallelism modes are `observe_only`, `inject_hints`, and `schedule`. - Adaptive Cache Governor providers are `passthrough`, `anthropic`, and `openai`; omit ACG until prompt-cache planning is needed. -- Helper APIs exist in Rust `nemo_flow_adaptive`, Python `nemo_flow.adaptive`, - and Node.js `nemo-flow-node/adaptive`. Go, WebAssembly, and raw FFI are +- Helper APIs exist in Rust `nemo_relay_adaptive`, Python `nemo_relay.adaptive`, + and Node.js `nemo-relay-node/adaptive`. Go, WebAssembly, and raw FFI are source-first or advanced surfaces. ## Default Path @@ -68,17 +68,17 @@ Do not use this skill when the application is not instrumented yet. Start with ## Use Another Skill When -- You need the exact adaptive config shape -> `nemo-flow-tune-adaptive-config` +- You need the exact adaptive config shape -> `nemo-relay-tune-adaptive-config` - You need to consume adaptive hints or scheduling guidance in app logic -> - `nemo-flow-tune-adaptive-hints` + `nemo-relay-tune-adaptive-hints` - You need to build reusable plugin behavior instead of configuring the built-in - adaptive component -> `nemo-flow-build-plugin` + adaptive component -> `nemo-relay-build-plugin` ## Related Skills -- `nemo-flow-start` -- `nemo-flow-instrument-calls` -- `nemo-flow-setup-observability` -- `nemo-flow-tune-adaptive-config` -- `nemo-flow-tune-adaptive-hints` -- `nemo-flow-build-plugin` +- `nemo-relay-start` +- `nemo-relay-instrument-calls` +- `nemo-relay-setup-observability` +- `nemo-relay-tune-adaptive-config` +- `nemo-relay-tune-adaptive-hints` +- `nemo-relay-build-plugin` diff --git a/skills/nemo-flow-typed-wrappers-codecs/SKILL.md b/skills/nemo-relay-typed-wrappers-codecs/SKILL.md similarity index 90% rename from skills/nemo-flow-typed-wrappers-codecs/SKILL.md rename to skills/nemo-relay-typed-wrappers-codecs/SKILL.md index a61eac2ab..0e2c76bf5 100644 --- a/skills/nemo-flow-typed-wrappers-codecs/SKILL.md +++ b/skills/nemo-relay-typed-wrappers-codecs/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-typed-wrappers-codecs -description: Use NeMo Flow typed wrappers and codecs without losing middleware behavior +name: nemo-relay-typed-wrappers-codecs +description: Use NeMo Relay typed wrappers and codecs without losing middleware behavior author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -20,7 +20,7 @@ tool or LLM integration. ## Embedded Codec Model - A typed value codec is a pure boundary translator. It converts - application-facing values to JSON before NeMo Flow emits events or runs + application-facing values to JSON before NeMo Relay emits events or runs middleware, then converts JSON back into the framework callback or caller type. - Python exposes `JsonPassthrough`, `DataclassCodec`, `PydanticCodec`, and `BestEffortAnyCodec`. Node.js exposes `JsonPassthrough` plus custom @@ -72,6 +72,6 @@ tool or LLM integration. ## Related Skills -- `nemo-flow-instrument-calls` -- `nemo-flow-export-openinference` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-instrument-calls` +- `nemo-relay-export-openinference` +- `nemo-relay-debug-runtime-integration` diff --git a/skills/nemo-flow-use-context-isolation/SKILL.md b/skills/nemo-relay-use-context-isolation/SKILL.md similarity index 87% rename from skills/nemo-flow-use-context-isolation/SKILL.md rename to skills/nemo-relay-use-context-isolation/SKILL.md index 8b510a706..248933cf8 100644 --- a/skills/nemo-flow-use-context-isolation/SKILL.md +++ b/skills/nemo-relay-use-context-isolation/SKILL.md @@ -1,6 +1,6 @@ --- -name: nemo-flow-use-context-isolation -description: Set up and reason about NeMo Flow scope-stack isolation for concurrent application work +name: nemo-relay-use-context-isolation +description: Set up and reason about NeMo Relay scope-stack isolation for concurrent application work author: NVIDIA Corporation and Affiliates license: Apache-2.0 --- @@ -54,12 +54,12 @@ ancestry and shared scope-local middleware. - Events from different requests appear under one root UUID - Scope-local middleware leaks across requests - Worker-thread work runs without the expected active scope -- Integrations activate NeMo Flow without an explicitly initialized stack +- Integrations activate NeMo Relay without an explicitly initialized stack - Relying on a thread-local stack after crossing async tasks, goroutines, or JS worker boundaries ## Related Skills -- `nemo-flow-instrument-calls` -- `nemo-flow-setup-observability` -- `nemo-flow-debug-runtime-integration` +- `nemo-relay-instrument-calls` +- `nemo-relay-setup-observability` +- `nemo-relay-debug-runtime-integration` diff --git a/third_party/README-hermes-agent.md b/third_party/README-hermes-agent.md index 4cf0b7057..5b7c1d35b 100644 --- a/third_party/README-hermes-agent.md +++ b/third_party/README-hermes-agent.md @@ -5,22 +5,22 @@ SPDX-License-Identifier: Apache-2.0 # Hermes Agent Patch Setup -This directory contains the maintained NeMo Flow integration patch for +This directory contains the maintained NeMo Relay integration patch for `third_party/hermes-agent`. Use [patches/hermes-agent/notes.md](../patches/hermes-agent/notes.md) as the detailed operator runbook. It covers the pinned checkout, editable install with -the `nemo-flow` extra, environment variables, ATIF output, OpenInference export, +the `nemo-relay` extra, environment variables, ATIF output, OpenInference export, and smoke validation. ## Quick Path -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/hermes-agent apply ../../patches/hermes-agent/0001-add-nemo-flow-integration.patch +git -C third_party/hermes-agent apply ../../patches/hermes-agent/0001-add-nemo-relay-integration.patch ``` Then follow [patches/hermes-agent/notes.md](../patches/hermes-agent/notes.md) @@ -31,9 +31,9 @@ for the Hermes-specific virtual environment and runtime configuration. Enable the integration in `${HERMES_HOME:-$HOME/.hermes}/.env`: ```bash -HERMES_NEMO_FLOW_ENABLED=1 -HERMES_NEMO_FLOW_ACG_ENABLED=1 -HERMES_NEMO_FLOW_ATIF_DIR=${HERMES_HOME:-$HOME/.hermes}/atif +HERMES_NEMO_RELAY_ENABLED=1 +HERMES_NEMO_RELAY_ACG_ENABLED=1 +HERMES_NEMO_RELAY_ATIF_DIR=${HERMES_HOME:-$HOME/.hermes}/atif ``` Then start Hermes from the patched checkout: diff --git a/third_party/README-langchain-nvidia.md b/third_party/README-langchain-nvidia.md index 1b44fad37..6ab9841f0 100644 --- a/third_party/README-langchain-nvidia.md +++ b/third_party/README-langchain-nvidia.md @@ -5,25 +5,25 @@ SPDX-License-Identifier: Apache-2.0 # LangChain NVIDIA Patch Setup -This directory contains the NeMo Flow integration patch for +This directory contains the NeMo Relay integration patch for `third_party/langchain-nvidia`, specifically the `libs/ai-endpoints` `langchain_nvidia_ai_endpoints` package. -The patch adds optional NeMo Flow LLM execution wrappers for ChatNVIDIA. The -integration stays inactive unless `nemo_flow` is importable and a NeMo Flow +The patch adds optional NeMo Relay LLM execution wrappers for ChatNVIDIA. The +integration stays inactive unless `nemo_relay` is importable and a NeMo Relay scope stack is already active. ## Setup -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/langchain-nvidia apply ../../patches/langchain-nvidia/0001-add-nemo-flow-integration.patch +git -C third_party/langchain-nvidia apply ../../patches/langchain-nvidia/0001-add-nemo-relay-integration.patch ``` -For local runtime validation, install the NeMo Flow Python package and the +For local runtime validation, install the NeMo Relay Python package and the patched LangChain NVIDIA package into the same environment: ```bash @@ -35,18 +35,18 @@ uv pip install -e third_party/langchain-nvidia/libs/ai-endpoints ## Usage Example -Use ChatNVIDIA inside an active NeMo Flow scope. The patched package detects -the active scope stack and routes the request through `nemo_flow.llm.execute` -or `nemo_flow.llm.stream_execute`; otherwise it falls back to the vanilla +Use ChatNVIDIA inside an active NeMo Relay scope. The patched package detects +the active scope stack and routes the request through `nemo_relay.llm.execute` +or `nemo_relay.llm.stream_execute`; otherwise it falls back to the vanilla ChatNVIDIA path. ```python -import nemo_flow +import nemo_relay from langchain_nvidia_ai_endpoints import ChatNVIDIA -with nemo_flow.scope.scope("langchain-nvidia-request", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("langchain-nvidia-request", nemo_relay.ScopeType.Agent): model = ChatNVIDIA(model="meta/llama-3.1-70b-instruct") - response = model.invoke("Summarize NeMo Flow in one sentence.") + response = model.invoke("Summarize NeMo Relay in one sentence.") print(response.content) ``` @@ -60,7 +60,7 @@ Run a structural syntax check for the patched files: ```bash uv run python -m py_compile \ - third_party/langchain-nvidia/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_flow.py \ + third_party/langchain-nvidia/libs/ai-endpoints/langchain_nvidia_ai_endpoints/_nemo_relay.py \ third_party/langchain-nvidia/libs/ai-endpoints/langchain_nvidia_ai_endpoints/chat_models.py ``` diff --git a/third_party/README-langchain.md b/third_party/README-langchain.md index 2c0491add..f79d3b0a9 100644 --- a/third_party/README-langchain.md +++ b/third_party/README-langchain.md @@ -5,26 +5,26 @@ SPDX-License-Identifier: Apache-2.0 # LangChain Patch Setup -This directory contains the NeMo Flow integration patch for +This directory contains the NeMo Relay integration patch for `third_party/langchain`. The patch touches LangChain Core callbacks/tools plus the OpenAI and Anthropic -partner packages. It adds optional NeMo Flow request, streaming, and callback -bridges that no-op when `nemo_flow` is unavailable or no scope stack is active. +partner packages. It adds optional NeMo Relay request, streaming, and callback +bridges that no-op when `nemo_relay` is unavailable or no scope stack is active. -For an alternate approach refer to [the public API-based integration in `python/nemo_flow/integrations/langchain`](../python/nemo_flow/integrations/langchain/README.md). +For an alternate approach refer to [the public API-based integration in `python/nemo_relay/integrations/langchain`](../python/nemo_relay/integrations/langchain/README.md). ## Setup -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/langchain apply ../../patches/langchain/0001-add-nemo-flow-integration.patch +git -C third_party/langchain apply ../../patches/langchain/0001-add-nemo-relay-integration.patch ``` -For local runtime validation, install NeMo Flow and the relevant editable +For local runtime validation, install NeMo Relay and the relevant editable LangChain packages into the same Python environment: ```bash @@ -39,20 +39,20 @@ uv pip install -e third_party/langchain/libs/partners/anthropic ## Usage Example Use the callback handler for LangChain run scopes and run provider calls inside -an active NeMo Flow scope. The OpenAI and Anthropic partner patches wrap LLM -execution with provider-specific codecs when a NeMo Flow scope stack is active. +an active NeMo Relay scope. The OpenAI and Anthropic partner patches wrap LLM +execution with provider-specific codecs when a NeMo Relay scope stack is active. ```python -import nemo_flow -from langchain_core.callbacks import NemoFlowCallbackHandler +import nemo_relay +from langchain_core.callbacks import NemoRelayCallbackHandler from langchain_openai import ChatOpenAI -handler = NemoFlowCallbackHandler() +handler = NemoRelayCallbackHandler() -with nemo_flow.scope.scope("langchain-request", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("langchain-request", nemo_relay.ScopeType.Agent): model = ChatOpenAI(model="gpt-5.4") response = model.invoke( - "Summarize NeMo Flow in one sentence.", + "Summarize NeMo Relay in one sentence.", config={"callbacks": [handler]}, ) print(response.content) @@ -64,24 +64,24 @@ The patch chooses `AnthropicMessagesCodec` for Anthropic requests and ## Validation -Run the NeMo Flow callback test from the LangChain Core package: +Run the NeMo Relay callback test from the LangChain Core package: ```bash cd third_party/langchain/libs/core -uv run --group test pytest tests/unit_tests/callbacks/test_nemo_flow_handler.py -q +uv run --group test pytest tests/unit_tests/callbacks/test_nemo_relay_handler.py -q ``` -Run a syntax check for the patched Python files from the NeMo Flow repository +Run a syntax check for the patched Python files from the NeMo Relay repository root: ```bash uv run python -m py_compile \ - third_party/langchain/libs/core/langchain_core/callbacks/nemo_flow_handler.py \ + third_party/langchain/libs/core/langchain_core/callbacks/nemo_relay_handler.py \ third_party/langchain/libs/core/langchain_core/tools/base.py \ - third_party/langchain/libs/core/langchain_core/utils/_nemo_flow.py \ - third_party/langchain/libs/partners/anthropic/langchain_anthropic/_nemo_flow.py \ + third_party/langchain/libs/core/langchain_core/utils/_nemo_relay.py \ + third_party/langchain/libs/partners/anthropic/langchain_anthropic/_nemo_relay.py \ third_party/langchain/libs/partners/anthropic/langchain_anthropic/chat_models.py \ - third_party/langchain/libs/partners/openai/langchain_openai/chat_models/_nemo_flow.py \ + third_party/langchain/libs/partners/openai/langchain_openai/chat_models/_nemo_relay.py \ third_party/langchain/libs/partners/openai/langchain_openai/chat_models/base.py ``` diff --git a/third_party/README-langgraph.md b/third_party/README-langgraph.md index 806a0c39c..0263a917d 100644 --- a/third_party/README-langgraph.md +++ b/third_party/README-langgraph.md @@ -5,21 +5,21 @@ SPDX-License-Identifier: Apache-2.0 # LangGraph Patch Setup -This directory contains the NeMo Flow integration patch for +This directory contains the NeMo Relay integration patch for `third_party/langgraph`. The patch adds LangGraph lifecycle, checkpoint, interrupt, retry, superstep, -and edge event emission through `langgraph._nemo_flow`. Tests for this patch +and edge event emission through `langgraph._nemo_relay`. Tests for this patch live in the first-party `third_party/langgraph_tests` directory. ## Setup -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/langgraph apply ../../patches/langgraph/0001-add-nemo-flow-integration.patch +git -C third_party/langgraph apply ../../patches/langgraph/0001-add-nemo-relay-integration.patch ``` For local runtime validation, expose the patched LangGraph package on @@ -31,14 +31,14 @@ PYTHONPATH=third_party/langgraph/libs/langgraph uv run pytest third_party/langgr ## Usage Example -Run a LangGraph graph inside an active NeMo Flow scope. The patch emits graph +Run a LangGraph graph inside an active NeMo Relay scope. The patch emits graph lifecycle, superstep, edge, retry, interrupt, checkpoint save, and checkpoint -restore events through `langgraph._nemo_flow`. +restore events through `langgraph._nemo_relay`. ```python from typing import TypedDict -import nemo_flow +import nemo_relay from langgraph.graph import END, StateGraph @@ -56,12 +56,12 @@ builder.set_entry_point("increment") builder.add_edge("increment", END) graph = builder.compile() -with nemo_flow.scope.scope("langgraph-run", nemo_flow.ScopeType.Agent): +with nemo_relay.scope.scope("langgraph-run", nemo_relay.ScopeType.Agent): result = graph.invoke({"value": 0}) print(result) ``` -Register a NeMo Flow subscriber or ATIF exporter before invoking the graph if +Register a NeMo Relay subscriber or ATIF exporter before invoking the graph if you want to inspect the emitted events. ## Validation @@ -70,7 +70,7 @@ Run a syntax check for the patched LangGraph files: ```bash uv run python -m py_compile \ - third_party/langgraph/libs/langgraph/langgraph/_nemo_flow.py \ + third_party/langgraph/libs/langgraph/langgraph/_nemo_relay.py \ third_party/langgraph/libs/langgraph/langgraph/pregel/_loop.py \ third_party/langgraph/libs/langgraph/langgraph/pregel/_retry.py \ third_party/langgraph/libs/langgraph/langgraph/pregel/_write.py \ diff --git a/third_party/README-openclaw.md b/third_party/README-openclaw.md index bf4465970..a585c11cb 100644 --- a/third_party/README-openclaw.md +++ b/third_party/README-openclaw.md @@ -5,22 +5,22 @@ SPDX-License-Identifier: Apache-2.0 # OpenClaw Patch Setup -This directory contains the NeMo Flow integration patch for +This directory contains the NeMo Relay integration patch for `third_party/openclaw`. -The patch adds an OpenClaw NeMo Flow extension plus agent runtime middleware -registration points. It depends on the local NeMo Flow Node binding through a +The patch adds an OpenClaw NeMo Relay extension plus agent runtime middleware +registration points. It depends on the local NeMo Relay Node binding through a `file:` dependency that resolves from `third_party/openclaw` back to `crates/node`. ## Setup -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/openclaw apply ../../patches/openclaw/0001-add-nemo-flow-integration.patch +git -C third_party/openclaw apply ../../patches/openclaw/0001-add-nemo-relay-integration.patch ``` Install OpenClaw dependencies using its pinned package manager. `pnpm` is not @@ -32,8 +32,8 @@ cd third_party/openclaw npx -y pnpm@10.32.1 install --frozen-lockfile --ignore-scripts ``` -For runtime smoke tests that load `nemo-flow-node`, build the Node binding from -the NeMo Flow repository root first: +For runtime smoke tests that load `nemo-relay-node`, build the Node binding from +the NeMo Relay repository root first: ```bash cd ../../crates/node @@ -44,13 +44,13 @@ npm run build ## Usage Example Install or enable the local extension from the patched OpenClaw checkout, then -configure the NeMo Flow plugin host directly under the OpenClaw plugin config: +configure the NeMo Relay plugin host directly under the OpenClaw plugin config: ```json { "plugins": { "entries": { - "nemo-flow": { + "nemo-relay": { "enabled": true, "config": { "version": 1, @@ -63,7 +63,7 @@ configure the NeMo Flow plugin host directly under the OpenClaw plugin config: "atif": { "enabled": true, "agent_name": "openclaw", - "output_directory": "./nemo-flow-atif" + "output_directory": "./nemo-relay-atif" } } } @@ -80,30 +80,30 @@ configure the NeMo Flow plugin host directly under the OpenClaw plugin config: } ``` -With that config, the patched plugin initializes the NeMo Flow plugin host and +With that config, the patched plugin initializes the NeMo Relay plugin host and activates the `observability` component. Wrapping is implicit when the plugin is enabled and initialized: the extension registers PI runtime streaming LLM and tool-call middleware with OpenClaw. -The patched plugin config is the canonical NeMo Flow plugin-host document. Old +The patched plugin config is the canonical NeMo Relay plugin-host document. Old wrapper keys are rejected, including `enabled`, `backend`, `capture`, -`correlation`, `plugins`, `nemoFlow`, `atif`, and `telemetry`. Configure +`correlation`, `plugins`, `nemoRelay`, `atif`, and `telemetry`. Configure observability through component-local keys such as `atof`, `atif`, `opentelemetry`, and `openinference`. ## Validation -Run the focused OpenClaw NeMo Flow tests: +Run the focused OpenClaw NeMo Relay tests: ```bash cd third_party/openclaw npx -y pnpm@10.32.1 exec node scripts/run-vitest.mjs run \ --config vitest.config.ts \ - extensions/nemo-flow/src/runtime.test.ts \ + extensions/nemo-relay/src/runtime.test.ts \ src/plugins/agent-runtime-middleware.test.ts ``` -Also rerun the patch applicability check from the NeMo Flow repository root: +Also rerun the patch applicability check from the NeMo Relay repository root: ```bash ./scripts/apply-patches.sh --check diff --git a/third_party/README-opencode.md b/third_party/README-opencode.md index 407a50d42..d324bf2e6 100644 --- a/third_party/README-opencode.md +++ b/third_party/README-opencode.md @@ -5,23 +5,23 @@ SPDX-License-Identifier: Apache-2.0 # opencode Patch Setup -This directory contains the NeMo Flow integration patch for +This directory contains the NeMo Relay integration patch for `third_party/opencode`. -The patch adds optional NeMo Flow tracing, LLM stream wrapping, tool execution +The patch adds optional NeMo Relay tracing, LLM stream wrapping, tool execution wrapping, raw ATOF JSONL export, and optional direct ATIF export support to the -opencode package. The patch also wires opencode to the local NeMo Flow Node +opencode package. The patch also wires opencode to the local NeMo Relay Node package with an optional `file:` dependency so the patched workspace can load -`nemo-flow-node` when NeMo Flow tracing is enabled. +`nemo-relay-node` when NeMo Relay tracing is enabled. ## Setup -From the NeMo Flow repository root: +From the NeMo Relay repository root: ```bash ./scripts/bootstrap-third-party.sh ./scripts/apply-patches.sh --check -git -C third_party/opencode apply ../../patches/opencode/0001-add-nemo-flow-integration.patch +git -C third_party/opencode apply ../../patches/opencode/0001-add-nemo-relay-integration.patch ``` Install opencode dependencies with Bun: @@ -31,8 +31,8 @@ cd third_party/opencode bun install --frozen-lockfile ``` -For runtime smoke tests that load `nemo-flow-node`, build the Node binding from -the NeMo Flow repository root first: +For runtime smoke tests that load `nemo-relay-node`, build the Node binding from +the NeMo Relay repository root first: ```bash cd ../../crates/node @@ -40,17 +40,17 @@ npm install npm run build ``` -Enable the integration at runtime with either `NEMO_FLOW_ENABLED=1` or the -opencode experimental `nemo_flow` config flag. If the native addon is missing, +Enable the integration at runtime with either `NEMO_RELAY_ENABLED=1` or the +opencode experimental `nemo_relay` config flag. If the native addon is missing, the integration logs a warning and disables itself. ## Usage Example -Run opencode with the NeMo Flow integration enabled by environment variable: +Run opencode with the NeMo Relay integration enabled by environment variable: ```bash cd third_party/opencode -NEMO_FLOW_ENABLED=1 bun --cwd packages/opencode run dev +NEMO_RELAY_ENABLED=1 bun --cwd packages/opencode run dev ``` Alternatively, enable the patched experimental config flag: @@ -58,23 +58,23 @@ Alternatively, enable the patched experimental config flag: ```json { "experimental": { - "nemo_flow": true + "nemo_relay": true } } ``` -When enabled, opencode creates NeMo Flow scopes for agents and batched tool +When enabled, opencode creates NeMo Relay scopes for agents and batched tool execution, wraps LLM streams and tool calls, and registers a raw ATOF JSONL -subscriber. Set `NEMO_FLOW_ATOF_DIR` to control where `events.jsonl` is written; +subscriber. Set `NEMO_RELAY_ATOF_DIR` to control where `events.jsonl` is written; otherwise it defaults to the opencode data directory's `atof` subdirectory. -Direct ATIF export is optional comparison output. Set `NEMO_FLOW_ATIF_DIR` to +Direct ATIF export is optional comparison output. Set `NEMO_RELAY_ATIF_DIR` to control where exported ATIF JSON files are written when a session becomes idle; otherwise it defaults to the opencode data directory's `atif` subdirectory. The tool wrapper keeps opencode's execution on original JavaScript values while -passing JSON-safe snapshots to the NeMo Flow native observer. This avoids -`structuredClone()` failures in opencode while still preserving NeMo Flow tool +passing JSON-safe snapshots to the NeMo Relay native observer. This avoids +`structuredClone()` failures in opencode while still preserving NeMo Relay tool events. ## Validation @@ -86,12 +86,12 @@ cd third_party/opencode/packages/opencode bun run typecheck ``` -Also rerun the patch applicability check from the NeMo Flow repository root: +Also rerun the patch applicability check from the NeMo Relay repository root: ```bash ./scripts/apply-patches.sh --check ``` -For an end-to-end smoke, run an opencode task with `NEMO_FLOW_ENABLED=1` and -verify that the configured `NEMO_FLOW_ATOF_DIR` contains an `events.jsonl` file +For an end-to-end smoke, run an opencode task with `NEMO_RELAY_ENABLED=1` and +verify that the configured `NEMO_RELAY_ATOF_DIR` contains an `events.jsonl` file with scope and tool/LLM events. diff --git a/third_party/README.md b/third_party/README.md index 104d8e645..c2d96d386 100644 --- a/third_party/README.md +++ b/third_party/README.md @@ -5,12 +5,12 @@ SPDX-License-Identifier: Apache-2.0 # Third-Party Integrations -NeMo Flow maintains some third-party integrations as patch sets applied to local +NeMo Relay maintains some third-party integrations as patch sets applied to local upstream checkouts under `third_party/`. The public wrapper commands stay at the `scripts/` root, while their implementations live under `scripts/third-party/`. -The tracked upstream sources live in [sources.lock](sources.lock). The NeMo Flow +The tracked upstream sources live in [sources.lock](sources.lock). The NeMo Relay patches live under [`../patches/`](../patches/). Integration-specific setup, usage, and validation notes live next to this file: @@ -30,7 +30,7 @@ Bootstrap the tracked upstream checkouts from the manifest: ./scripts/bootstrap-third-party.sh ``` -Apply the NeMo Flow integration patches: +Apply the NeMo Relay integration patches: ```bash ./scripts/apply-patches.sh @@ -77,7 +77,7 @@ Example for `langgraph`: ```bash git clone https://github.com/langchain-ai/langgraph.git third_party/langgraph git -C third_party/langgraph checkout --detach 5c9c1d598d65411317e0957a42cc3af681d395f8 -git -C third_party/langgraph apply ../patches/langgraph/0001-add-nemo-flow-integration.patch +git -C third_party/langgraph apply ../patches/langgraph/0001-add-nemo-relay-integration.patch ``` ## Updating Patch Sets diff --git a/third_party/langgraph_tests/conftest.py b/third_party/langgraph_tests/conftest.py index 47fe1de07..6496e0e59 100644 --- a/third_party/langgraph_tests/conftest.py +++ b/third_party/langgraph_tests/conftest.py @@ -4,8 +4,8 @@ """Shared import guards for LangGraph integration tests. All tests in this directory require: -1. ``nemo_flow`` to be installed (the NeMo Flow Python bindings) -2. ``langgraph`` to be installed with the NeMo Flow integration patch applied +1. ``nemo_relay`` to be installed (the NeMo Relay Python bindings) +2. ``langgraph`` to be installed with the NeMo Relay integration patch applied Tests are automatically skipped when either dependency is unavailable. """ @@ -16,9 +16,9 @@ def _langgraph_patched() -> bool: - """Return True if langgraph is installed with the NeMo Flow integration patch.""" + """Return True if langgraph is installed with the NeMo Relay integration patch.""" try: - from langgraph import _nemo_flow # noqa: F401 + from langgraph import _nemo_relay # noqa: F401 return True except ImportError: @@ -31,5 +31,5 @@ def _langgraph_patched() -> bool: pytestmark = pytest.mark.skipif( not _langgraph_patched(), - reason="langgraph not installed or NeMo Flow integration patch not applied", + reason="langgraph not installed or NeMo Relay integration patch not applied", ) diff --git a/third_party/langgraph_tests/test_langgraph_edge_events.py b/third_party/langgraph_tests/test_langgraph_edge_events.py index 10570e213..3cd53eb41 100644 --- a/third_party/langgraph_tests/test_langgraph_edge_events.py +++ b/third_party/langgraph_tests/test_langgraph_edge_events.py @@ -3,7 +3,7 @@ """Unit tests for LangGraph edge traversal event emission. -Validates that emit_edge_write in _nemo_flow.py emits correct NeMo Flow Mark events +Validates that emit_edge_write in _nemo_relay.py emits correct NeMo Relay Mark events with the expected name, data fields, and source_node extraction behavior. """ @@ -13,7 +13,7 @@ from typing import Any import pytest -from langgraph._nemo_flow import ( # type: ignore[import-untyped] +from langgraph._nemo_relay import ( # type: ignore[import-untyped] available, emit_edge_write, pop_graph_scope, @@ -22,8 +22,8 @@ push_node_scope, ) -import nemo_flow -from nemo_flow import create_scope_stack, set_thread_scope_stack +import nemo_relay +from nemo_relay import create_scope_stack, set_thread_scope_stack def _is_mark_event(event: Any, name: str) -> bool: @@ -44,9 +44,9 @@ def scope_stack(self): def events(self): """Register an event subscriber and collect events.""" collected: list[Any] = [] - nemo_flow.subscribers.register("test-edge-collector", lambda e: collected.append(e)) + nemo_relay.subscribers.register("test-edge-collector", lambda e: collected.append(e)) yield collected - nemo_flow.subscribers.deregister("test-edge-collector") + nemo_relay.subscribers.deregister("test-edge-collector") def test_edge_write_emits_event(self, scope_stack: Any, events: list[Any]) -> None: """emit_edge_write emits a Mark event with correct name and data fields.""" diff --git a/third_party/langgraph_tests/test_langgraph_lifecycle.py b/third_party/langgraph_tests/test_langgraph_lifecycle.py index a034df079..8b6c5ed24 100644 --- a/third_party/langgraph_tests/test_langgraph_lifecycle.py +++ b/third_party/langgraph_tests/test_langgraph_lifecycle.py @@ -3,8 +3,8 @@ """Integration tests for LangGraph lifecycle event emission. -Validates that the four lifecycle event helper functions in ``_nemo_flow.py`` -emit correct NeMo Flow Mark events with the expected names, event types, and data +Validates that the four lifecycle event helper functions in ``_nemo_relay.py`` +emit correct NeMo Relay Mark events with the expected names, event types, and data fields, and that guard behavior prevents spurious events when no scope stack is active. @@ -18,7 +18,7 @@ from typing import Any import pytest -from langgraph._nemo_flow import ( # type: ignore[import-untyped] +from langgraph._nemo_relay import ( # type: ignore[import-untyped] available, emit_checkpoint_restore, emit_checkpoint_save, @@ -28,8 +28,8 @@ push_graph_scope, ) -import nemo_flow -from nemo_flow import create_scope_stack, set_thread_scope_stack +import nemo_relay +from nemo_relay import create_scope_stack, set_thread_scope_stack def _is_mark_event(event: Any, name: str) -> bool: @@ -50,9 +50,9 @@ def scope_stack(self): def events(self): """Register an event subscriber and collect events.""" collected: list[Any] = [] - nemo_flow.subscribers.register("test-lifecycle-collector", lambda e: collected.append(e)) + nemo_relay.subscribers.register("test-lifecycle-collector", lambda e: collected.append(e)) yield collected - nemo_flow.subscribers.deregister("test-lifecycle-collector") + nemo_relay.subscribers.deregister("test-lifecycle-collector") # ------------------------------------------------------------------- # Checkpoint Save events @@ -147,9 +147,9 @@ def scope_stack(self): def events(self): """Register an event subscriber and collect events.""" collected: list[Any] = [] - nemo_flow.subscribers.register("test-interrupt-collector", lambda e: collected.append(e)) + nemo_relay.subscribers.register("test-interrupt-collector", lambda e: collected.append(e)) yield collected - nemo_flow.subscribers.deregister("test-interrupt-collector") + nemo_relay.subscribers.deregister("test-interrupt-collector") # ------------------------------------------------------------------- # Graph Interrupt events diff --git a/third_party/langgraph_tests/test_langgraph_scope.py b/third_party/langgraph_tests/test_langgraph_scope.py index 745cd23f5..14611a36f 100644 --- a/third_party/langgraph_tests/test_langgraph_scope.py +++ b/third_party/langgraph_tests/test_langgraph_scope.py @@ -4,9 +4,9 @@ """Integration tests for LangGraph scope propagation. Validates that the LangGraph Pregel patch correctly instruments graph and -node execution with NeMo Flow scopes across sync, async, and parallel paths. +node execution with NeMo Relay scopes across sync, async, and parallel paths. -These tests exercise the ``_nemo_flow.py`` scope helpers directly to verify +These tests exercise the ``_nemo_relay.py`` scope helpers directly to verify the scope hierarchy, parallel isolation, and double-wrap prevention behavior without requiring the full LangGraph graph execution engine. """ @@ -18,11 +18,11 @@ from typing import Any import pytest -from langgraph._nemo_flow import ( # type: ignore[import-untyped] +from langgraph._nemo_relay import ( # type: ignore[import-untyped] _graph_scope_info, - _langgraph_nemo_flow_active, + _langgraph_nemo_relay_active, available, - langgraph_nemo_flow_active, + langgraph_nemo_relay_active, pop_graph_scope, pop_node_scope, pop_subgraph_scope, @@ -31,8 +31,8 @@ push_subgraph_scope, ) -import nemo_flow -from nemo_flow import ScopeEvent, create_scope_stack, set_thread_scope_stack +import nemo_relay +from nemo_relay import ScopeEvent, create_scope_stack, set_thread_scope_stack def _is_scope_event( @@ -86,9 +86,9 @@ def scope_stack(self): def events(self): """Register an event subscriber and collect events.""" collected: list[Any] = [] - nemo_flow.subscribers.register("test-lg-collector", lambda e: collected.append(e)) + nemo_relay.subscribers.register("test-lg-collector", lambda e: collected.append(e)) yield collected - nemo_flow.subscribers.deregister("test-lg-collector") + nemo_relay.subscribers.deregister("test-lg-collector") # ------------------------------------------------------------------- # Single-node graph scope hierarchy @@ -279,11 +279,11 @@ def test_llm_call_in_node_scope(self, scope_stack: Any, events: list[Any]) -> No graph_handle = push_graph_scope("llm_graph") node_handle, node_graph_handle, saved_token = push_node_scope("llm_node", "task-llm") - llm_handle = nemo_flow.llm.call( + llm_handle = nemo_relay.llm.call( "test-model", - nemo_flow.LLMRequest({}, {"messages": [], "model": "test-model"}), + nemo_relay.LLMRequest({}, {"messages": [], "model": "test-model"}), ) - nemo_flow.llm.call_end(llm_handle, {"response": "hello"}) + nemo_relay.llm.call_end(llm_handle, {"response": "hello"}) _pop_node_and_restore_parent_stack(node_handle, node_graph_handle, saved_token, scope_stack) pop_graph_scope(graph_handle) @@ -313,8 +313,8 @@ def test_tool_call_in_node_scope(self, scope_stack: Any, events: list[Any]) -> N graph_handle = push_graph_scope("tool_graph") node_handle, node_graph_handle, saved_token = push_node_scope("tool_node", "task-tool") - tool_handle = nemo_flow.tools.call("search_tool", {"query": "test"}) - nemo_flow.tools.call_end(tool_handle, {"results": ["a", "b"]}) + tool_handle = nemo_relay.tools.call("search_tool", {"query": "test"}) + nemo_relay.tools.call_end(tool_handle, {"results": ["a", "b"]}) _pop_node_and_restore_parent_stack(node_handle, node_graph_handle, saved_token, scope_stack) pop_graph_scope(graph_handle) @@ -340,17 +340,17 @@ def test_tool_call_in_node_scope(self, scope_stack: Any, events: list[Any]) -> N def test_no_double_wrapping(self, scope_stack: Any, events: list[Any]) -> None: """Graph and node scopes are created exactly once (no double-wrap).""" - assert langgraph_nemo_flow_active() is False + assert langgraph_nemo_relay_active() is False graph_handle = push_graph_scope("single_graph") - assert langgraph_nemo_flow_active() is True + assert langgraph_nemo_relay_active() is True node_handle, node_graph_handle, saved_token = push_node_scope("single_node", "task-1") _pop_node_and_restore_parent_stack(node_handle, node_graph_handle, saved_token, scope_stack) pop_graph_scope(graph_handle) - assert langgraph_nemo_flow_active() is False + assert langgraph_nemo_relay_active() is False graph_starts = [e for e in events if _is_scope_start(e, name="single_graph", metadata_key="langgraph.graph")] assert sum(e.uuid == graph_handle.uuid for e in graph_starts) == 1 @@ -426,9 +426,9 @@ def events(self): def _subscriber(event: Any) -> None: collected.append(event) - nemo_flow.subscribers.register("test_sub", _subscriber) + nemo_relay.subscribers.register("test_sub", _subscriber) yield collected - nemo_flow.subscribers.deregister("test_sub") + nemo_relay.subscribers.deregister("test_sub") # ------------------------------------------------------------------- # Subgraph nested scope hierarchy @@ -442,9 +442,9 @@ def test_subgraph_nested_scope_hierarchy(self, scope_stack: Any, events: list[An sub_handle, active_tok, info_tok = push_subgraph_scope("inner_graph") - inner_node_handle = nemo_flow.scope.push( + inner_node_handle = nemo_relay.scope.push( "inner_node", - nemo_flow.ScopeType.Agent, + nemo_relay.ScopeType.Agent, metadata={"langgraph.node": True}, ) @@ -462,7 +462,7 @@ def test_subgraph_nested_scope_hierarchy(self, scope_stack: Any, events: list[An assert subgraph_starts[0].metadata.get("langgraph.subgraph") is True assert subgraph_starts[0].metadata.get("langgraph.graph") is True - nemo_flow.scope.pop(inner_node_handle) + nemo_relay.scope.pop(inner_node_handle) pop_subgraph_scope(sub_handle, active_tok, info_tok) _pop_node_and_restore_parent_stack(node_handle, node_graph_handle, saved_token, scope_stack) pop_graph_scope(graph_handle) @@ -477,11 +477,11 @@ def test_subgraph_detection_via_config_key(self, scope_stack: Any, events: list[ node_handle, node_graph_handle, saved_token = push_node_scope("a_node", "task-x") - assert _langgraph_nemo_flow_active.get() is True + assert _langgraph_nemo_relay_active.get() is True sub_handle, active_tok, info_tok = push_subgraph_scope("sub_graph") - assert _langgraph_nemo_flow_active.get() is True + assert _langgraph_nemo_relay_active.get() is True info = _graph_scope_info.get() assert info is not None @@ -512,7 +512,7 @@ def test_subgraph_contextvar_restoration(self, scope_stack: Any, events: list[An assert restored_info is not None, "_graph_scope_info should be restored, not None" assert restored_info.graph_name == "parent_graph", f"Expected 'parent_graph', got '{restored_info.graph_name}'" - assert _langgraph_nemo_flow_active.get() is True + assert _langgraph_nemo_relay_active.get() is True _pop_node_and_restore_parent_stack(node_handle, node_graph_handle, saved_token, scope_stack) pop_graph_scope(graph_handle) @@ -537,7 +537,7 @@ def test_atif_graph_topology_metadata(self, scope_stack: Any, events: list[Any]) graph_handle = push_graph_scope("my_graph", graph_topology=topology) - handle = nemo_flow.scope.get_handle() + handle = nemo_relay.scope.get_handle() assert handle is not None assert handle.metadata is not None assert "graph_topology" in handle.metadata @@ -567,7 +567,7 @@ def _collect(event: Any) -> None: with lock: all_events.append(event) - nemo_flow.subscribers.register("concurrent-collector", _collect) + nemo_relay.subscribers.register("concurrent-collector", _collect) results: dict[str, dict[str, Any]] = {} errors: list[str] = [] @@ -601,7 +601,7 @@ def run_graph(name: str, node_count: int) -> None: t_b.start() t_b.join() - nemo_flow.subscribers.deregister("concurrent-collector") + nemo_relay.subscribers.deregister("concurrent-collector") assert not errors, f"Thread errors: {errors}" assert "A" in results and "B" in results diff --git a/third_party/langgraph_tests/test_langgraph_superstep_events.py b/third_party/langgraph_tests/test_langgraph_superstep_events.py index 106b2d90a..1c277a4bd 100644 --- a/third_party/langgraph_tests/test_langgraph_superstep_events.py +++ b/third_party/langgraph_tests/test_langgraph_superstep_events.py @@ -3,8 +3,8 @@ """Unit tests for LangGraph superstep boundary event emission. -Validates that emit_superstep_start and emit_superstep_end in _nemo_flow.py -emit correct NeMo Flow Mark events with expected name, step, and task_count fields. +Validates that emit_superstep_start and emit_superstep_end in _nemo_relay.py +emit correct NeMo Relay Mark events with expected name, step, and task_count fields. """ from __future__ import annotations @@ -13,7 +13,7 @@ from typing import Any import pytest -from langgraph._nemo_flow import ( # type: ignore[import-untyped] +from langgraph._nemo_relay import ( # type: ignore[import-untyped] available, emit_superstep_end, emit_superstep_start, @@ -21,8 +21,8 @@ push_graph_scope, ) -import nemo_flow -from nemo_flow import create_scope_stack, set_thread_scope_stack +import nemo_relay +from nemo_relay import create_scope_stack, set_thread_scope_stack def _is_mark_event(event: Any, name: str) -> bool: @@ -43,9 +43,9 @@ def scope_stack(self): def events(self): """Register an event subscriber and collect events.""" collected: list[Any] = [] - nemo_flow.subscribers.register("test-superstep-collector", lambda e: collected.append(e)) + nemo_relay.subscribers.register("test-superstep-collector", lambda e: collected.append(e)) yield collected - nemo_flow.subscribers.deregister("test-superstep-collector") + nemo_relay.subscribers.deregister("test-superstep-collector") def test_superstep_start_emits_event(self, scope_stack: Any, events: list[Any]) -> None: """emit_superstep_start emits a Mark event with correct name and data fields.""" diff --git a/uv.lock b/uv.lock index f3ed02336..927283937 100644 --- a/uv.lock +++ b/uv.lock @@ -1519,7 +1519,7 @@ wheels = [ ] [[package]] -name = "nemo-flow" +name = "nemo-relay" source = { editable = "." } [package.optional-dependencies] @@ -1584,9 +1584,9 @@ requires-dist = [ { name = "langchain-nvidia-ai-endpoints", marker = "extra == 'langchain-nvidia'", specifier = "~=1.0" }, { name = "langgraph", marker = "extra == 'langchain'" }, { name = "langgraph", marker = "extra == 'langgraph'", specifier = ">=1.2.0,<2.0.0" }, - { name = "nemo-flow", extras = ["langchain"], marker = "extra == 'langchain-nvidia'" }, - { name = "nemo-flow", extras = ["langchain"], marker = "extra == 'langgraph'" }, - { name = "nemo-flow", extras = ["langgraph"], marker = "extra == 'deepagents'" }, + { name = "nemo-relay", extras = ["langchain"], marker = "extra == 'langchain-nvidia'" }, + { name = "nemo-relay", extras = ["langchain"], marker = "extra == 'langgraph'" }, + { name = "nemo-relay", extras = ["langgraph"], marker = "extra == 'deepagents'" }, ] provides-extras = ["deepagents", "langchain", "langchain-nvidia", "langgraph"]