NIA One · Docs
Intégration SDK

Intégrations frameworks

Brancher le SDK sur un framework web ne demande plus d'ouvrir un flow à la main : un middleware (composant qui s'intercale dans le traitement des requêtes) enregistre tout le trafic HTTP en une seule ligne.

Une ligne instrumente tout le trafic HTTP

Enregistrez le middleware une fois, et chaque requête HTTP devient un flow NiaOne, sans toucher à vos routes. Le middleware capte automatiquement, en labels/métriques sur le flow :

  • http.method, http.route (le template /users/<id> quand le framework l'expose, sinon le path → faible cardinalité), http.status_code, et niaone.integration (l'adaptateur : express, flask…)
  • latency_ms, error_count (+ le label error.type) sur erreur ou statut 5xx
  • la trace distribuée : reprise depuis les headers niaone-* entrants, réinjection sur la réponse

Comme le flow de la requête est lié au contexte, current_flow_from_context(), @instrument / instrument, trace_llm_call et submit_feedback fonctionnent directement dans vos handlers, sans passer le flow en argument.

Safe par défaut

Sans NIAONE_API_KEY (client désactivé), le middleware est un no-op (sans effet) et ne lève jamais : toute erreur d'instrumentation reste isolée de votre requête. Vous pouvez le laisser branché en local et en CI.

Python — niaone_sdk.integrations.*

Flaskpip install niaone-python-sdk[flask]

from flask import Flaskfrom niaone_sdk.integrations.flask import NiaoneFlaskapp = Flask(__name__)niaone = NiaoneFlask(app)   # c'est tout — zéro config (NiaoneSDK.from_env())# App-factory : NiaoneFlask().init_app(app)# Mapper une vue à un flow definition précis :@app.post("/support")@niaone.flow_definition("fd_support")def support(): ...

FastAPI / Starlettepip install niaone-python-sdk[fastapi]

from niaone_sdk.integrations.fastapi import add_niaoneadd_niaone(app)   # ou app.add_middleware(NiaoneASGIMiddleware, client=...)

Django — ajoutez le middleware à settings.MIDDLEWARE

MIDDLEWARE = [  "niaone_sdk.integrations.django.NiaoneMiddleware",  # ... vos autres middlewares ...]# config optionnelle via settings : NIAONE_CLIENT, NIAONE_FLOW_DEFINITION_ID,# NIAONE_FLOW_DEFINITION_RESOLVER, NIAONE_EXCLUDE_PATHS, NIAONE_SESSION_ID /# NIAONE_ACTOR_ID (callables), NIAONE_PROPAGATE_CARRIER, NIAONE_INJECT_CARRIER

ASGI générique (Quart, ou toute application ASGI)

from niaone_sdk.integrations.asgi import NiaoneASGIMiddlewareapp = NiaoneASGIMiddleware(app)

WSGI générique (Bottle, Pyramid, ou toute application WSGI)

from niaone_sdk.integrations.wsgi import NiaoneWSGIMiddlewareapp = NiaoneWSGIMiddleware(app)

TypeScript — sous-imports @niaone/sdk/<framework>

Chaque framework est une peer-dependency optionnelle (seuls ses types sont utilisés, donc aucune dépendance runtime ajoutée).

Express@niaone/sdk/express

import express from 'express';import { niaoneExpress, niaoneExpressError } from '@niaone/sdk/express';const app = express();app.use(niaoneExpress());          // zéro config (NiaoneSDK.fromEnv())// ... vos routes ...app.use(niaoneExpressError());     // optionnel, à enregistrer EN DERNIER

Fastify@niaone/sdk/fastify

import { niaoneFastify } from '@niaone/sdk/fastify';await app.register(niaoneFastify, { client });

Koa@niaone/sdk/koa

import { niaoneKoa } from '@niaone/sdk/koa';app.use(niaoneKoa({ client }));

Next.js (route handlers App Router) — @niaone/sdk/next

import { withNiaone } from '@niaone/sdk/next';export const GET = withNiaone(async (req) => Response.json({ ok: true }));

node:http / connect@niaone/sdk/node-http

import { niaoneNodeHttp } from '@niaone/sdk/node-http';const trace = niaoneNodeHttp({ client });   // style connect (req, res, next)

Accéder au flow de la requête

Le middleware en place, le flow de chaque requête vit dans le contexte. Récupérez-le sans le passer en argument :

from niaone_sdk import current_flow_from_context, submit_feedback@app.post("/chat")def chat():  flow = current_flow_from_context()      # le flow de cette requête  resp = openai.chat.completions.create(...)  submit_feedback(flow, True)  return {"trace_id": flow.trace_id}

Options

Tous les adaptateurs partagent les mêmes réglages (camelCase en TS, snake_case en Python).

OptionRôleDéfaut
clientClient SDK à utiliserNiaoneSDK.fromEnv()
flowDefinitionIdID de flow definition fixe"http.request"
flowDefinitionResolverRésout l’ID par requête : (req) => string
sessionIdExtrait l’ID de session : (req) => string
actorIdExtrait l’ID utilisateur : (req) => string
excludePathsChemins ignorés (exact ou préfixe en *) — absent en Next.js[]
propagateCarrierReprend la trace depuis les headers niaone-* entrantstrue
injectCarrierRéinjecte les headers niaone-* sur la réponsetrue
NiaoneFlask(  app,  client=my_client,                       # défaut : NiaoneSDK.from_env()  flow_definition_id="fd_support",        # ou flow_definition_resolver=lambda req: ...  session_id=lambda req: req.headers.get("X-Session-Id"),  actor_id=lambda req: req.headers.get("X-User-Id"),  exclude_paths=["/health"],              # aussi exclude_endpoints / exclude_blueprints)

Template de route & cardinalité

Les middlewares protocolaires (node:http, ASGI, WSGI) tournent avant le routing : ils ne connaissent pas encore le template, d'où le défaut flow_definition_id = "http.request" et http.route = le path concret. Express, Fastify, Koa (avec router), Flask et Django exposent le template de route (faible cardinalité). En Flask, le flow_definition_id retombe par défaut sur le nom d'endpoint de la vue (default_to_endpoint). Passez flowDefinitionId / flow_definition_id ou un resolver pour une valeur métier. Les route handlers Next.js sont runtime Node uniquement (ils dépendent d'AsyncLocalStorage).

Référence complète

Tables d'options exhaustives, tracing distribué inter-services, recettes et troubleshooting par adaptateur : voir sdk/docs/framework-integrations.md.

Cas avancés & sans middleware

Ouvrir un flow manuellement (stack non couverte)

Si aucun middleware ne couvre votre stack, ouvrez le flow dès l'entrée du handler, avant tout traitement, pour que vos spans métier ne soient pas orphelins derrière le span « http request » de l'auto-instrumentation OTel (cf. Instrumenter).

# FastAPI@app.post("/predict")async def predict(req: PredictRequest):  with flow(client, flow_definition_id="prediction_api", name="prediction_main",            actor_id=req.user_id) as f:      return await run_prediction(f, req)

Agents — CrewAI

Instrumentez sans toucher à votre logique : branchez les callbacks de CrewAI et mappez chaque agent à un Asset (rôle + span_kind). Un exemple complet est fourni dans le SDK (sdk/python/demo/crewai_integration/).

Python

CrewAI est un framework Python : l'exemple ci-dessous est en Python uniquement.

from niaone_sdk import flow, stepfrom niaone_sdk.models import Asset, Flowfrom niaone_sdk.enums import AssetKind, AssetRole, SpanKindROLE_MAP = {"researcher": AssetRole.RETRIEVAL, "analyst": AssetRole.ANALYSIS, "writer": AssetRole.POSTPROCESS}def run_crew(crew, user_input: str):  with flow(client, flow_definition_id="research_crew", name="research_crew_main") as f:      for task in crew.tasks:          asset = Asset(kind=AssetKind.LLM, role=ROLE_MAP[task.agent.role], name=task.agent.role)          with step(f, asset=asset, flow=Flow(name="research_crew_main", step=task.agent.role),                    span_kind=SpanKind.AGENT) as s:              result = task.execute()              payload(s, "output", out_data, str(result))      return crew.kickoff(inputs={"input": user_input})

LangChain — usage des tokens

normalize_llm_usage comprend les formats LangChain (Python et JS), donc vous récupérez les tokens quel que soit le vendor sous-jacent.

from niaone_sdk import normalize_llm_usageresult = llm.generate([messages])s.add_metrics(normalize_llm_usage(result.llm_output.get("token_usage", {})))

Migration depuis OpenTelemetry brut

Sans le SDK, émettez vous-même les attributs attendus : record_type = "run" et un raw_payload JSON portant payload.flow.* et payload.asset.*.

with tracer.start_as_current_span("answer") as span:  span.set_attribute("payload.flow.name", "my_sia_main")  span.set_attribute("payload.flow.phase", "ANALYSIS")  span.set_attribute("payload.asset.kind", "llm")  span.set_attribute("payload.asset.name", "gpt-4o")

On this page