Skip to main content
GitHub

SDK Parity

Feature comparison between the Python and JavaScript SDKs.

Feature comparison between the Python and JavaScript/TypeScript SDKs. The published versions are Python risicare 0.6.0 and npm risicare 0.9.0; not every row below has been re-checked against them. Both SDKs share the same wire format and connect to the same gateway — differences are in API surface and integration breadth.

Core API

FeaturePythonJavaScriptNotes
init()risicare.init()init()Same config options
shutdown()risicare.shutdown(timeout_ms=5000)await shutdown(timeoutMs?)JS is async. Both default to 5000 ms
flush()risicare.flush(timeout_ms=5000)await flush(timeoutMs?)JS is async. Both default to 5000 ms and return a boolean
enable() / disable()risicare.enable()enable()
is_enabled()risicare.is_enabled()isEnabled()
get_client()risicare.get_client()—JS uses getTracer() instead
get_tracer()risicare.get_tracer()getTracer()
reset_for_testing()risicare.reset_for_testing()—Python only

Progressive Integration Tiers

TierFeaturePythonJavaScript
0Import + env var auto-instrumentationimport risicare + RISICARE_API_KEY + RISICARE_TRACING=true— (requires init(); see Tier 1)
1Explicit initrisicare.init()init()
1@trace / trace()Decorator + context manager— (no trace() wrapper; auto-traced via patchX() provider patches)
2@agentDecoratoragent(opts, fn) wrapper
3@session / session_context()Decorator + context managersession(opts, fn) / withSession()
4Phase decorators@trace_think, @trace_decide, @trace_act, @trace_observetraceThink(fn), traceDecide(fn), traceAct(fn), traceObserve(fn)
5Multi-agent@trace_message, @trace_delegate, @trace_coordinatetraceMessage(opts, fn), traceDelegate(opts, fn), traceCoordinate(opts, fn)

Phase wrappers return a callable in both SDKs

Phase wrappers behave the same way in Python and JavaScript — each returns a wrapped function that you invoke later (not the function's result).

Python — @trace_think is a decorator; applying it to a function yields a wrapped function:

@trace_think("analyze")        # or bare: @trace_think
def analyze():
    return "the answer"
 
result = analyze()             # result = "the answer"

JavaScript — traceThink returns the wrapped function you then call:

const analyze = traceThink("analyze", () => "the answer");  // wrapped fn
const result = analyze();                                    // result = "the answer"

JavaScript accepts both traceThink('name', fn) and traceThink(fn) (bare) forms — matching Python's @trace_think("name") and @trace_think. This applies to traceThink, traceDecide, traceAct, traceObserve, traceMessage, traceDelegate, and traceCoordinate. The agent() and session() wrappers follow the same return-a-callable pattern in both SDKs.

Context Propagation

FeaturePythonJavaScript
MechanismcontextvarsAsyncLocalStorage
Thread propagationauto_patch=True patches ThreadPoolExecutorAutomatic via Node.js
Async propagationauto_patch=True patches asyncio.create_taskAutomatic via AsyncLocalStorage
session_context()Sync + async variantswithSession() (single API)
agent_context()Sync + async variantswithAgent() (single API)
phase_context()phase_context(SemanticPhase.THINK)withPhase(SemanticPhase.THINK, fn)
W3C inject_trace_context()inject_trace_context(headers)injectTraceContext(headers)
W3C extract_trace_context()extract_trace_context(headers)extractTraceContext(headers)
get_current_session()Returns SessionContext | NoneReturns SessionContext | undefined
get_current_agent()Returns AgentContext | NoneReturns AgentContext | undefined
get_current_span()Returns Span | NoneReturns Span | undefined
Span registryregister_span(), get_span_by_id(), unregister_span()registerSpan(), getSpanById(), unregisterSpan()

LLM Provider Support

ProviderPythonJavaScript
OpenAIAuto-instrumentedpatchOpenAI()
AnthropicAuto-instrumentedpatchAnthropic()
Vercel AI SDK—patchVercelAI()
Google GeminiAuto-instrumentedpatchGoogleAI()
CohereAuto-instrumentedpatchCohere()
MistralChat completions (sync and async); streaming calls are not tracedpatchMistral()
GroqAuto-instrumentedpatchGroq()
Together AIAuto-instrumentedpatchTogether()
OllamaAuto-instrumentedpatchOllama()
Amazon BedrockAuto-instrumentedpatchBedrock()
Google Vertex AIAuto-instrumentedVia patchGoogleAI()
CerebrasAuto-instrumentedpatchCerebras()
HuggingFaceAuto-instrumentedpatchHuggingFace()
OpenAI-compatible (base_url)Host detection (8 providers)Host detection via patchOpenAI()

Both SDKs support 12 native providers plus 8 OpenAI-compatible hosts detected by base URL (DeepSeek, Together AI, Groq, xAI, Fireworks, Baseten, Novita, BytePlus). Any other OpenAI-compatible endpoint (for example a self-hosted vLLM server) is still traced through patchOpenAI() / the OpenAI import hook, but is reported generically rather than as a named provider. Python auto-patches on import; JavaScript requires an explicit patchX() call.

Instrumentation Style

PythonJavaScript
MethodImport hooks (a wrapper around builtins.__import__) — automaticES Proxy wrapping — manual patchX() call
WhenAt init() for a library that is already imported, and on the first import openai after init(). A library that is imported after init() is patched tooAfter calling patchOpenAI(new OpenAI())
Controlinstall_import_hooks() / remove_import_hooks()Call or skip patchX()
Checkis_instrumented("openai")—
Listget_supported_modules()—

Framework Support

FrameworkPythonJavaScript
LangChainCallback + patchesRisicareCallbackHandler
LangGraphPatchesinstrumentLangGraph()
InstructorPatchespatchInstructor()
LlamaIndexSpan handlerRisicareLlamaIndexHandler
CrewAIPatches— (Python only)
AutoGenPatches (v0.2 + v0.4)— (Python only)
OpenAI Agents SDKPatches— (Python only)
LiteLLMCallback— (Python only)
DSPyCallback— (Python only)
Pydantic AIPatches— (Python only)

Python supports 10 framework integrations. JavaScript supports 4 (LangChain.js, LangGraph.js, Instructor, LlamaIndex.TS). The remaining 6 frameworks have no JavaScript integration in the Risicare SDK: CrewAI, AutoGen, OpenAI Agents, LiteLLM, DSPy, or Pydantic AI.

Exporters

ExporterPythonJavaScript
HttpExporterHTTP/2 via httpxNative fetch
ConsoleExporterTo stdout (debug=True)— (npm 0.8.0 and earlier attached one with debug: true and no key; 0.9.0 does not)
BatchSpanProcessorTimer + count thresholdsetInterval + count threshold
OTLPExporterOTLP/HTTP JSON + circuit breaker—
SpanExporter baseAbstract classInterface

Fix Runtime

FeaturePythonJavaScript
FixRuntimeFull implementationFull implementation
init_runtime()init_runtime(config)initFixRuntime() (called by init() only when fixRuntime is true)
get_runtime()get_runtime()getFixRuntime()
shutdown_runtime()shutdown_runtime()shutdownFixRuntime()
FixLoaderLoads fixes from APILoads fixes from API
FixApplierApplies fixes to functionsApplies fixes to functions
FixCacheLocal fix cachingLocal fix caching
FixInterceptorRoutes calls via A/B testpreCall / postCall in runtime/interceptors.ts

Neither SDK starts the Fix Runtime by default: init() starts it only with fix_runtime=True (Python) or fixRuntime: true (JavaScript). In JS the interceptor logic lives in runtime/interceptors.ts (preCall / postCall); the OpenAI provider patch consults the Fix Runtime only when it is enabled and has active fixes. Fix deployment is not enabled in this release, and the route that the runtime reads (GET /v1/fixes/active on the API host) is not reachable with an API key during the beta — so no fix can reach the runtime. See Fix Runtime.

OpenTelemetry

FeaturePythonJavaScript
OTel bridgeotel_bridge=True in init()—
RisicareSpanExporterPlugs into OTel SDK—
RisicareSpanProcessorPlugs into OTel SDK—
OTLP exportOTLPExporter class—
OTLP ingestionGateway accepts OTLP/HTTPGateway accepts OTLP/HTTP

Configuration

OptionPythonJavaScript
api_keyapi_keyapiKey
endpointendpointendpoint
api_endpointapi_endpointapiEndpoint
environmentenvironmentenvironment
service_nameservice_nameserviceName
service_versionservice_versionserviceVersion
enabledenabledenabled
trace_contenttrace_contenttraceContent
sample_ratesample_ratesampleRate
batch_sizebatch_sizebatchSize
batch_timeout_msbatch_timeout_msbatchTimeoutMs
max_queue_size—maxQueueSize
auto_patchauto_patch (default True)—
debugdebugdebug
compress—compress
metadatametadatametadata
exportersexporters—
otlp_endpointotlp_endpoint—
otlp_headersotlp_headers—
otel_bridgeotel_bridge—
maskmaskmask
fix_runtimefix_runtime (default False)fixRuntime (default false)
project_id (deprecated)Emits DeprecationWarningEmits console.warn

Enums

SpanKind, SpanStatus, and SemanticPhase have identical values in both SDKs. AgentRole and MessageType differ:

EnumPythonJavaScript
SpanKind17 values (identical)17 values (identical)
SpanStatusUNSET, OK, ERRORUNSET, OK, ERROR
SemanticPhaseTHINK, DECIDE, ACT, OBSERVE, REFLECT, COMMUNICATE, COORDINATESame 7 values
AgentRole12 values14 values (superset — adds REVIEWER, CUSTOM)
MessageType15 values18 values (superset — adds REQUEST, DELEGATE, COORDINATE)

Wire Format

Both SDKs send spans to POST /v1/spans in the same JSON format. The gateway does not distinguish between Python and JavaScript origins. A few span fields are sent by one SDK only.

Next Steps