SDK Parity
Feature comparison between the Python and JavaScript SDKs.
Feature comparison between the Python (v0.1.14) and JavaScript/TypeScript (v0.4.2) SDKs. Both SDKs share the same wire format and connect to the same gateway — differences are in API surface and integration breadth.
Core API
| Feature | Python | JavaScript | Notes |
|---|---|---|---|
init() | risicare.init() | init() | Same config options |
shutdown() | risicare.shutdown(timeout_ms=5000) | await shutdown() | JS is async |
flush() | client.flush() | await flush() | JS is async |
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
| Tier | Feature | Python | JavaScript |
|---|---|---|---|
| 0 | Env var auto-instrumentation | RISICARE_TRACING=true | RISICARE_TRACING=true |
| 1 | Explicit init | risicare.init() | init() |
| 1 | @trace / trace() | Decorator + context manager | — (no trace() wrapper; auto-traced via patchX() provider patches) |
| 2 | @agent | Decorator | agent(opts, fn) wrapper |
| 3 | @session / session_context() | Decorator + context manager | session(opts, fn) / withSession() |
| 4 | Phase decorators | @trace_think, @trace_decide, @trace_act, @trace_observe | traceThink(fn), traceDecide(fn), traceAct(fn), traceObserve(fn) |
| 5 | Multi-agent | @trace_message, @trace_delegate, @trace_coordinate | traceMessage(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
| Feature | Python | JavaScript |
|---|---|---|
| Mechanism | contextvars | AsyncLocalStorage |
| Thread propagation | auto_patch=True patches ThreadPoolExecutor | Automatic via Node.js |
| Async propagation | auto_patch=True patches asyncio.create_task | Automatic via AsyncLocalStorage |
session_context() | Sync + async variants | withSession() (single API) |
agent_context() | Sync + async variants | withAgent() (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 | None | Returns SessionContext | undefined |
get_current_agent() | Returns AgentContext | None | Returns AgentContext | undefined |
get_current_span() | Returns Span | None | Returns Span | undefined |
| Span registry | register_span(), get_span_by_id(), unregister_span() | registerSpan(), getSpanById(), unregisterSpan() |
LLM Provider Support
| Provider | Python | JavaScript |
|---|---|---|
| OpenAI | Auto-instrumented | patchOpenAI() |
| Anthropic | Auto-instrumented | patchAnthropic() |
| Vercel AI SDK | — | patchVercelAI() |
| Google Gemini | Auto-instrumented | patchGoogleAI() |
| Cohere | Auto-instrumented | patchCohere() |
| Mistral | Auto-instrumented | patchMistral() |
| Groq | Auto-instrumented | patchGroq() |
| Together AI | Auto-instrumented | patchTogether() |
| Ollama | Auto-instrumented | patchOllama() |
| Amazon Bedrock | Auto-instrumented | patchBedrock() |
| Google Vertex AI | Auto-instrumented | Via patchGoogleAI() |
| Cerebras | Auto-instrumented | patchCerebras() |
| HuggingFace | Auto-instrumented | patchHuggingFace() |
| 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
| Python | JavaScript | |
|---|---|---|
| Method | Import hooks (sys.meta_path) — automatic | ES Proxy wrapping — manual patchX() call |
| When | On first import openai after init() | After calling patchOpenAI(new OpenAI()) |
| Control | install_import_hooks() / remove_import_hooks() | Call or skip patchX() |
| Check | is_instrumented("openai") | — |
| List | get_supported_modules() | — |
Framework Support
| Framework | Python | JavaScript |
|---|---|---|
| LangChain | Callback + patches | RisicareCallbackHandler |
| LangGraph | Patches | instrumentLangGraph() |
| Instructor | Patches | patchInstructor() |
| LlamaIndex | Span handler | RisicareLlamaIndexHandler |
| CrewAI | Patches | — (Python only) |
| AutoGen | Patches (v0.2 + v0.4) | — (Python only) |
| OpenAI Agents SDK | Patches | — (Python only) |
| LiteLLM | Callback | — (Python only) |
| DSPy | Callback | — (Python only) |
| Pydantic AI | Patches | — (Python only) |
Python supports 10 framework integrations. JavaScript supports 4 (LangChain.js, LangGraph.js, Instructor, LlamaIndex.TS). The remaining 6 frameworks are Python-only — no JavaScript npm packages exist for CrewAI, AutoGen, OpenAI Agents, LiteLLM, DSPy, or Pydantic AI.
Exporters
| Exporter | Python | JavaScript |
|---|---|---|
HttpExporter | HTTP/2 via httpx | Native fetch |
ConsoleExporter | To stderr | To stdout |
BatchSpanProcessor | Timer + count threshold | setInterval + count threshold |
OTLPExporter | OTLP/HTTP JSON + circuit breaker | — |
SpanExporter base | Abstract class | Interface |
Fix Runtime
| Feature | Python | JavaScript |
|---|---|---|
FixRuntime | Full implementation | Full implementation |
init_runtime() | init_runtime(config) | initFixRuntime() (called by init()) |
get_runtime() | get_runtime() | getFixRuntime() |
shutdown_runtime() | shutdown_runtime() | shutdownFixRuntime() |
FixLoader | Loads fixes from API | Loads fixes from API |
FixApplier | Applies fixes to functions | Applies fixes to functions |
FixCache | Local fix caching | Local fix caching |
FixInterceptor | Routes calls via A/B test | preCall / postCall in runtime/interceptors.ts |
Both SDKs wire the Fix Runtime into init() automatically. 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. Because no fix is ever promoted past draft today, the runtime has nothing to apply — see Fix Runtime.
OpenTelemetry
| Feature | Python | JavaScript |
|---|---|---|
| OTel bridge | otel_bridge=True in init() | — |
RisicareSpanExporter | Plugs into OTel SDK | — |
RisicareSpanProcessor | Plugs into OTel SDK | — |
| OTLP export | OTLPExporter class | — |
| OTLP ingestion | Gateway accepts OTLP/HTTP | Gateway accepts OTLP/HTTP |
Configuration
| Option | Python | JavaScript |
|---|---|---|
api_key | api_key | apiKey |
endpoint | endpoint | endpoint |
environment | environment | environment |
service_name | service_name | serviceName |
service_version | service_version | serviceVersion |
enabled | enabled | enabled |
trace_content | trace_content | traceContent |
sample_rate | sample_rate | sampleRate |
batch_size | batch_size | batchSize |
batch_timeout_ms | batch_timeout_ms | batchTimeoutMs |
max_queue_size | — | maxQueueSize |
auto_patch | auto_patch (default True) | — |
debug | debug | debug |
compress | — | compress |
metadata | metadata | metadata |
exporters | exporters | — |
otlp_endpoint | otlp_endpoint | — |
otlp_headers | otlp_headers | — |
otel_bridge | otel_bridge | — |
project_id (deprecated) | Emits DeprecationWarning | Emits console.warn |
Enums
SpanKind, SpanStatus, and SemanticPhase have identical values in both SDKs. AgentRole and MessageType differ:
| Enum | Python | JavaScript |
|---|---|---|
SpanKind | 17 values (identical) | 17 values (identical) |
SpanStatus | UNSET, OK, ERROR | UNSET, OK, ERROR |
SemanticPhase | THINK, DECIDE, ACT, OBSERVE, REFLECT, COMMUNICATE, COORDINATE | Same 7 values |
AgentRole | 12 values | 14 values (superset — adds REVIEWER, CUSTOM) |
MessageType | 15 values | 18 values (superset — adds REQUEST, DELEGATE, COORDINATE) |
Wire Format
Both SDKs produce identical JSON payloads sent to POST /v1/spans. The gateway does not distinguish between Python and JavaScript origins. All 37 SpanData fields are supported by both SDKs.