Changelog
Stay up to date with all the latest features, improvements, and bug fixes.
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.modelsmodule:SearchMode,VectorSearch,VectorFieldSearch,VectorBoostConfig,HybridConfig,SearchRequestwith cross-field validation - Convenience methods on
FluxClient/AsyncFluxClientwith**extra_bodypass-through forwhere,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,SearchRequestwithbuildSearchBody()runtime validation - Convenience methods on
FluxClientwith 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,
});
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_searchis supported withsearch_mode="vector"andsearch_mode="vector_boosted"vector_field_searchis not supported withsearch_mode="text"orsearch_mode="hybrid"vector_field_searchandvector_searchare mutually exclusive- Distance metric for vector field search: cosine only
Support for Flux API introspection and route-level descriptions on API folder connections.
New: Flux introspection methods
FluxClient.getRouter()— callsGET /{api_prefix}/_routerFluxClient.getSchema(folderPath)— callsGET /{api_prefix}/{folder_path}/_schema
const router = await fluxClient.getRouter();
const schema = await fluxClient.getSchema('content/articles');
Updated: API folder connection methods
ManagementClient.addApiFolder()andupdateApiFolder()now accept optional route descriptions:descriptionGetOnedescriptionGetManydescriptionSearchdescriptionSchema
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
APIFolderSummarynow includes alldescription_*fields from Management API responses
Support for Flux API introspection and route-level descriptions on API folder connections.
New: Flux introspection methods
FluxClient.get_router()/AsyncFluxClient.get_router()— callsGET /{api_prefix}/_routerFluxClient.get_schema(folder_path)/AsyncFluxClient.get_schema(folder_path)— callsGET /{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()andupdate_api_folder()now accept optional route descriptions:description_get_onedescription_get_manydescription_searchdescription_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
APIFolderSummarynow includes alldescription_*fields from Management API responses
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 /_schemanow includes searchable metadata:searchable_fields— fields available for filtering/searchnon_searchable_fields— fields present in schema but not indexed for search
Management API
- Folder-to-API connection supports per-action route descriptions:
description_get_manydescription_get_onedescription_searchdescription_schema
- These descriptions are used by Flux
/_routerfor each action route
Initial release of the official LangChain.js integration for FoxNose.
Features
- FoxNoseRetriever — LangChain
BaseRetrieverbacked by FoxNose Flux search with text, vector, hybrid, and vector-boosted modes - FoxNoseLoader —
BaseDocumentLoaderwith cursor-based pagination andloadLazy()async generator for memory-efficient bulk loading - createFoxNoseTool — factory that wraps retrieval as a
DynamicStructuredToolfor LLM agents - Flexible content mapping: single field, multiple fields, or custom mapper
- Metadata control: whitelist, blacklist, system metadata toggle
- Structured filtering via
whereparameter - 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
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
maxConcurrencyand 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
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_iddoesn't exist in the folder, or creates a new revision if it does - Returns
201 Created,200 OK, or202 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
POSTcreation orPUTupsert POSTreturns409 external_id_conflictif the ID is already taken in the folder- Returned in the resource object as
external_id(nullwhen not set)
Improved error handling
- Non-GET requests (POST, PUT, PATCH, DELETE) to URLs without a trailing slash now return
422 trailing_slash_requiredinstead of500 - GET requests without a trailing slash continue to redirect via
301
Endpoints
PUT /v1/:env/folders/:folder/resources/?external_id=<value>— Upsert ResourcePOST /v1/:env/folders/:folder/resources/— Create Resource (now accepts optionalexternal_id)
Full support for external_id and upsert operations, including concurrent batch upserts.
New: upsert_resource()
- Creates a resource if the
external_iddoesn'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=Truestops on first error;fail_fast=False(default) processes all items- Optional
on_progresscallback:(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_idparameter 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_id—str | None, populated from API responses
New types
BatchUpsertItem— input container withexternal_id,payload, and optionalcomponentBatchUpsertResult— output withsucceeded,failedlists andtotal,success_count,failure_count,has_failurespropertiesBatchItemError— error details withindex,external_id, andexception
Async support
All new methods are available on AsyncManagementClient with identical signatures.
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
FoxNoseRetrieveras 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",
)
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
GET /v1/:env/events/— List environment eventsGET /v1/global-events/— List global events
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"])
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
FolderSummaryorResourceSummarydirectly 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)
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()