Changelog

Stay up to date with all the latest features, improvements, and bug fixes.


Vector Search in Python & TypeScript SDKs

Both official SDKs now have typed models and convenience methods for all Flux vector search modes: vector_search, vector_field_search, hybrid_search, and boosted_search.

Python SDK 0.5.0

  • New flux.models module: SearchMode, VectorSearch, VectorFieldSearch, VectorBoostConfig, HybridConfig, SearchRequest with cross-field validation
  • Convenience methods on FluxClient / AsyncFluxClient with **extra_body pass-through for where, sort, etc.
results = client.hybrid_search(
    "articles",
    query="ML applications",
    find_text={"query": "machine learning"},
    vector_weight=0.7,
    text_weight=0.3,
)

TypeScript SDK 0.3.0

  • New types: SearchMode, VectorSearch, VectorFieldSearch, VectorBoostConfig, HybridConfig, SearchRequest with buildSearchBody() runtime validation
  • Convenience methods on FluxClient with extra parameter forwarding via rest spread
const results = await client.hybridSearch('articles', {
  query: 'ML applications',
  findText: { query: 'machine learning' },
  vectorWeight: 0.7,
  textWeight: 0.3,
});

Vector Fields & Custom Vector Search

FoxNose now supports a full workflow for custom embeddings: you can define vector fields in Management API, store model-generated vectors directly in resources, and search them in Flux with vector_field_search.

This unlocks semantic experiences beyond classic text search, including voice/speaker matching, image similarity, recommendation and ranking scenarios, while keeping search behavior explicit and predictable in vector and vector_boosted modes. For custom vector search, the distance metric is cosine only.

Management API

  • New field type: vector
  • Supported dimensions: 256, 384, 768, 1024, 1536

Flux API

  • New search payload: vector_field_search
  • Supported parameters: field, query_vector, top_k, similarity_threshold
  • vector_field_search is supported with search_mode="vector" and search_mode="vector_boosted"
  • vector_field_search is not supported with search_mode="text" or search_mode="hybrid"
  • vector_field_search and vector_search are mutually exclusive
  • Distance metric for vector field search: cosine only

TypeScript SDK 0.2.0

Support for Flux API introspection and route-level descriptions on API folder connections.

New: Flux introspection methods

  • FluxClient.getRouter() — calls GET /{api_prefix}/_router
  • FluxClient.getSchema(folderPath) — calls GET /{api_prefix}/{folder_path}/_schema
const router = await fluxClient.getRouter();
const schema = await fluxClient.getSchema('content/articles');

Updated: API folder connection methods

  • ManagementClient.addApiFolder() and updateApiFolder() now accept optional route descriptions:
    • descriptionGetOne
    • descriptionGetMany
    • descriptionSearch
    • descriptionSchema
const connection = await managementClient.addApiFolder(apiKey, folderKey, {
  allowedMethods: ['get_many', 'get_one'],
  descriptionGetOne: 'Get one article by key',
  descriptionGetMany: 'List published articles',
  descriptionSearch: 'Search published articles',
  descriptionSchema: 'Read article schema',
});

Updated model

  • APIFolderSummary now includes all description_* fields from Management API responses

Python SDK 0.4.0

Support for Flux API introspection and route-level descriptions on API folder connections.

New: Flux introspection methods

  • FluxClient.get_router() / AsyncFluxClient.get_router() — calls GET /{api_prefix}/_router
  • FluxClient.get_schema(folder_path) / AsyncFluxClient.get_schema(folder_path) — calls GET /{api_prefix}/{folder_path}/_schema
router = flux_client.get_router()
schema = flux_client.get_schema("content/articles")

Updated: API folder connection methods

  • ManagementClient.add_api_folder() and update_api_folder() now accept optional route descriptions:
    • description_get_one
    • description_get_many
    • description_search
    • description_schema
  • Same signature updates are available on AsyncManagementClient
connection = management_client.add_api_folder(
    api_key,
    folder_key,
    allowed_methods=["get_many", "get_one"],
    description_get_one="Get one article by key",
    description_get_many="List published articles",
    description_search="Search published articles",
    description_schema="Read article schema",
)

Updated model

  • APIFolderSummary now includes all description_* fields from Management API responses

Flux API Introspection Updates

New introspection capabilities for Flux APIs to improve runtime discovery for users, MCP servers, and LLM agents.

Flux API

  • New endpoint: GET /{api_prefix}/_router — returns a flat route catalog with method, path, action, scope, path params, query params, request body contract, and response shape
  • New endpoint: GET /{api_prefix}/{folder_path}/_schema — returns live JSON Schema and route metadata for the target folder path
  • /_schema now includes searchable metadata:
    • searchable_fields — fields available for filtering/search
    • non_searchable_fields — fields present in schema but not indexed for search

Management API

  • Folder-to-API connection supports per-action route descriptions:
    • description_get_many
    • description_get_one
    • description_search
    • description_schema
  • These descriptions are used by Flux /_router for each action route

LangChain.js Integration 0.1.0

Initial release of the official LangChain.js integration for FoxNose.

Features

  • FoxNoseRetriever — LangChain BaseRetriever backed by FoxNose Flux search with text, vector, hybrid, and vector-boosted modes
  • FoxNoseLoaderBaseDocumentLoader with cursor-based pagination and loadLazy() async generator for memory-efficient bulk loading
  • createFoxNoseTool — factory that wraps retrieval as a DynamicStructuredTool for LLM agents
  • Flexible content mapping: single field, multiple fields, or custom mapper
  • Metadata control: whitelist, blacklist, system metadata toggle
  • Structured filtering via where parameter
  • Dual output: ESM and CommonJS with full TypeScript declarations

Installation

npm install @foxnose/langchain @foxnose/sdk @langchain/core

Quick Start

import { FluxClient, SimpleKeyAuth } from '@foxnose/sdk';
import { FoxNoseRetriever } from '@foxnose/langchain';

const client = new FluxClient({
  baseUrl: 'https://your-env.fxns.io',
  apiPrefix: 'content',
  auth: new SimpleKeyAuth('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY'),
});

const retriever = new FoxNoseRetriever({
  client,
  folderPath: 'knowledge-base',
  pageContentField: 'body',
  searchMode: 'hybrid',
});

const docs = await retriever.invoke('how to build AI applications');

Links

TypeScript SDK 0.1.0

Initial release of the official FoxNose TypeScript SDK.

Features

  • ManagementClient — full coverage of Management API v1: folders, components, resources, revisions, roles, API keys, environments, projects, and more
  • FluxClient — content delivery: list resources, get resource, search with text/vector/hybrid modes
  • Four auth strategies — Anonymous, JWT, Simple key, and Secure (ECDSA P-256)
  • Automatic retries — exponential backoff with jitter and Retry-After support
  • Batch upsert — concurrent resource upserts with configurable maxConcurrency and progress callback
  • Zero dependencies — built on native fetch (Node 18+)
  • Dual output — ESM and CommonJS with full TypeScript declarations

Installation

npm install @foxnose/sdk

Quick Start

import { FluxClient, SimpleKeyAuth } from '@foxnose/sdk';

const client = new FluxClient({
  baseUrl: 'https://your-env.fxns.io',
  apiPrefix: 'content',
  auth: new SimpleKeyAuth('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY'),
});

const resources = await client.listResources('articles');

const results = await client.search('articles', {
  search_mode: 'hybrid',
  vector_search: { query: 'how to build AI applications', top_k: 5 },
});

client.close();

Links

Resource External IDs & Upsert API

New external_id field on resources enables idempotent syncing from external systems.

Upsert by external_id

  • New endpoint: PUT /v1/:env/folders/:folder/resources/?external_id=<value>
  • Creates a new resource if the external_id doesn't exist in the folder, or creates a new revision if it does
  • Returns 201 Created, 200 OK, or 202 Accepted (async mode)
  • Supports all standard resource options: name, mode, resource_owner, validate_data, component

external_id on resources

  • Optional identifier — allowed characters: a-z A-Z 0-9 - _ / ., max 255 characters
  • Can be set during POST creation or PUT upsert
  • POST returns 409 external_id_conflict if the ID is already taken in the folder
  • Returned in the resource object as external_id (null when not set)

Improved error handling

  • Non-GET requests (POST, PUT, PATCH, DELETE) to URLs without a trailing slash now return 422 trailing_slash_required instead of 500
  • GET requests without a trailing slash continue to redirect via 301

Endpoints

  • PUT /v1/:env/folders/:folder/resources/?external_id=<value>Upsert Resource
  • POST /v1/:env/folders/:folder/resources/Create Resource (now accepts optional external_id)

Python SDK 0.3.0

Full support for external_id and upsert operations, including concurrent batch upserts.

New: upsert_resource()

  • Creates a resource if the external_id doesn't exist, or creates a new revision if it does
  • Uses PUT /folders/:folder/resources/?external_id=<value> under the hood
folder = client.get_folder_by_path("content/blog-posts")

resource = client.upsert_resource(
    folder,
    {"title": "Hello World", "body": "..."},
    external_id="post-42",
)

New: batch_upsert_resources()

  • Upserts multiple resources in parallel with configurable concurrency
  • Collects successes and failures into a BatchUpsertResult
  • fail_fast=True stops on first error; fail_fast=False (default) processes all items
  • Optional on_progress callback: (completed_count, total_count)
from foxnose_sdk import BatchUpsertItem

folder = client.get_folder_by_path("content/articles")

items = [
    BatchUpsertItem(external_id=f"article-{i}", payload={"title": f"Article {i}"})
    for i in range(100)
]

result = client.batch_upsert_resources(
    folder,
    items,
    max_concurrency=10,
    on_progress=lambda done, total: print(f"{done}/{total}"),
)

print(f"OK: {result.success_count}, Failed: {result.failure_count}")

Updated: create_resource()

  • New optional external_id parameter to assign an external ID during creation
folder = client.get_folder_by_path("content/blog-posts")

resource = client.create_resource(
    folder,
    {"title": "New Post"},
    external_id="post-99",
)

New model field

  • ResourceSummary.external_idstr | None, populated from API responses

New types

  • BatchUpsertItem — input container with external_id, payload, and optional component
  • BatchUpsertResult — output with succeeded, failed lists and total, success_count, failure_count, has_failures properties
  • BatchItemError — error details with index, external_id, and exception

Async support

All new methods are available on AsyncManagementClient with identical signatures.

LangChain Integration 0.2.0

Two new components that extend the LangChain integration beyond retrieval.

FoxNoseLoader

  • Bulk document loading from FoxNose folders with cursor-based pagination
  • Memory-efficient lazy_load() for large folders
  • Async support via alazy_load()
  • Filtering, sorting, and configurable batch size

create_foxnose_tool

  • Factory function that wraps FoxNoseRetriever as a LangChain tool for LLM agents
  • Compatible with any LangChain agent framework (langgraph, etc.)
  • Customizable tool name and description
  • Two response formats: plain string or (str, list[Document]) tuple
from langchain_foxnose import FoxNoseLoader, create_foxnose_tool

# Bulk-load all documents from a folder
loader = FoxNoseLoader(
    client=client,
    folder_path="knowledge-base",
    page_content_field="body",
)
docs = loader.load()

# Create a search tool for agents
tool = create_foxnose_tool(
    client=client,
    folder_path="knowledge-base",
    page_content_field="body",
    search_mode="hybrid",
)

Events API

Audit trail for all content changes — now accessible via API and dashboard.

Features

  • Environment Events — track changes to folders, resources, revisions, components, versions, APIs, roles, and API keys
  • Global Events — track changes to users and projects at the organization level
  • Rich filtering by entity type, event type, time range, and related entities
  • Actor information including user details or API key metadata
  • Detailed metadata for each event type with contextual information

Dashboard

  • Activity Log section added to environment dashboard — view and filter environment events
  • Activity Log section added to organization dashboard — view and filter global events

Endpoints

LangChain Integration 0.1.0

Initial release of the official LangChain integration for FoxNose.

Features

  • FoxNoseRetriever — LangChain BaseRetriever backed by FoxNose Flux search
  • Support for all search modes: text, vector, hybrid, and vector-boosted
  • Flexible content mapping: single field, multiple fields, or custom mapper
  • Metadata control: whitelist, blacklist, system metadata toggle
  • Native async support via AsyncFluxClient
  • Structured filtering via where parameter
  • Convenience from_client_params() constructor

Installation

pip install langchain-foxnose

Quick Start

from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain_foxnose import FoxNoseRetriever

retriever = FoxNoseRetriever.from_client_params(
    base_url="https://7c9h4pwu.fxns.io",
    api_prefix="content",
    public_key="YOUR_PUBLIC_KEY",
    secret_key="YOUR_SECRET_KEY",
    folder="articles",
    search_mode="hybrid",
    content_field="body",
)

qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o"),
    retriever=retriever,
)

answer = qa.invoke("What are the best practices for API design?")
print(answer["result"])

Python SDK 0.2.0

Management client methods now accept either string keys or corresponding model objects (e.g. FolderSummary, ResourceSummary) wherever a *_key parameter is used. This eliminates the need to manually extract .key from objects returned by the API.

Added

  • Model objects as identifiers — pass objects like FolderSummary or ResourceSummary directly instead of extracting .key
  • _resolve_key() helper for extracting string keys from model objects
  • 13 type aliases for method parameters: FolderRef, ResourceRef, RevisionRef, ComponentRef, SchemaVersionRef, OrgRef, ProjectRef, EnvironmentRef, ManagementRoleRef, FluxRoleRef, ManagementAPIKeyRef, FluxAPIKeyRef, APIRef
from foxnose_sdk.management import ManagementClient
from foxnose_sdk.auth import SimpleKeyAuth

client = ManagementClient(
    base_url="https://api.foxnose.net",
    auth=SimpleKeyAuth("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY"),
)

# Before 0.2.0 — manually extract .key
folder = client.get_folder("my-folder")
resources = client.list_resources(folder.key)

# With 0.2.0 — pass the object directly
folder = client.get_folder("my-folder")
resources = client.list_resources(folder)

Python SDK 0.1.0

Initial release of the official FoxNose Python SDK.

Features

  • Full support for Flux API v1
  • Sync and async clients
  • Simple and Secure authentication methods
  • Type hints for all methods and responses
  • Built-in error handling

Installation

pip install foxnose-sdk

Quick Start

from foxnose_sdk.flux import FluxClient
from foxnose_sdk.auth import SimpleKeyAuth

client = FluxClient(
    base_url="https://7c9h4pwu.fxns.io",
    api_prefix="content",
    auth=SimpleKeyAuth("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY"),
)

# List resources
data = client.list_resources("articles")
for article in data["results"]:
    print(f"- {article['data']['title']}")

# Search with filters
data = client.search("articles", body={
    "where": {
        "$": {
            "all_of": [
                {"status__eq": "published"},
                {"category__in": ["tech", "science"]}
            ]
        }
    },
    "limit": 10
})

# Vector search
data = client.search("articles", body={
    "search_mode": "vector",
    "vector_search": {
        "query": "how to build AI applications",
        "top_k": 5,
        "similarity_threshold": 0.7
    }
})

client.close()

Was this page helpful?