SDKs
Connect from any language.
All client SDKs speak the same WHIP protocol and DataChannel event format. Plugin SDKs handle the JSON-RPC protocol so you can focus on your tool logic.
Client SDKs
One protocol, four languages. Use TypeScript for browser apps, Go or Rust for CLI tools, Python for notebooks and automation. Drop-in connection in under 10 lines of code.
TypeScript
@streamcore/js-sdkFor browsers, React, Next.js, and Node.js. Handles WHIP negotiation, DataChannel events, and media stream management.
Install
npm install @streamcore/js-sdkUsage
import { StreamCoreAIClient } from "@streamcore/js-sdk";
const client = new StreamCoreAIClient(
{ whipUrl: "http://localhost:8080/whip" },
{
onTranscript: (entry) => console.log(entry),
onStatusChange: (s) => console.log(s),
}
);
await client.connect();Go
github.com/streamcoreai/go-sdkFor CLI tools, backend services, and server-to-server integrations. Native WebRTC via Pion.
Install
go get github.com/streamcoreai/go-sdkUsage
import streamcoreai "github.com/streamcoreai/go-sdk"
client := streamcoreai.NewClient(
streamcoreai.Config{WHIPEndpoint: "http://localhost:8080/whip"},
streamcoreai.EventHandler{
OnTranscript: func(e streamcoreai.TranscriptEntry, all []streamcoreai.TranscriptEntry) {
fmt.Println(e.Role, e.Text)
},
},
)
client.Connect(ctx)Python
streamcoreai-sdkFor notebooks, automation scripts, and Python applications. Async-first with callback support.
Install
pip install streamcoreai-sdkUsage
import asyncio
import streamcore
async def main():
client = streamcore.Client(
config=streamcore.Config(whip_endpoint="http://localhost:8080/whip"),
events=streamcore.EventHandler(
on_transcript=lambda entry, _: print(f"[{entry.role}] {entry.text}"),
),
)
await client.connect()
# ... send/receive audio ...
await client.disconnect()
asyncio.run(main())Rust
streamcore-rust-sdkFor high-performance CLI tools and embedded systems. Native WebRTC via webrtc-rs.
Install
cargo add streamcore-rust-sdkUsage
use streamcore_rust_sdk::{Client, Config, EventHandler};
let client = Client::new(
Config {
whip_endpoint: "http://localhost:8080/whip".into(),
..Default::default()
},
EventHandler {
on_transcript: Some(Box::new(|e, _all| {
println!("{}: {}", e.role, e.text);
})),
..Default::default()
},
);
client.connect().await?;WHIP + DataChannel Protocol
All SDKs use the same underlying protocol. WHIP (RFC 9725) handles signaling with a single HTTP POST. A WebRTC DataChannel carries structured events bidirectionally.
DataChannel Events
transcript— Real-time speech-to-text results (partial and final)response— LLM response text as it streamserror— Error messages from the servertiming— Pipeline latency events (LLM first token, TTS first byte)
Event format
// Transcript (partial or final)
{"type": "transcript", "text": "What's the weather in Tokyo?", "final": true}
// LLM response
{"type": "response", "text": "Let me check that for you."}
// Timing metrics
{"type": "timing", "stage": "llm_first_token", "ms": 312}
// Error
{"type": "error", "message": "TTS provider timeout"}Connection Lifecycle
- 1. Client creates SDP offer (audio
sendrecv, datachannel for events) - 2. Client gathers ICE candidates
- 3. Client POSTs SDP offer to
POST /whip - 4. Server responds with 201 Created, SDP answer, and
Location: /whip/{sessionId} - 5. ICE handshake completes, bidirectional RTP starts flowing
- 6. DataChannel opens for transcript/response events
- 7. Client sends
DELETE /whip/{sessionId}to tear down
Plugin SDKs
Plugin SDKs handle the JSON-RPC protocol, initialization, and logging. You just implement the execute handler.
Python Plugin SDK
streamcore-pluginInstall
pip install streamcore-pluginUsage
from streamcoreai_plugin import StreamCoreAIPlugin
plugin = StreamCoreAIPlugin()
@plugin.on_execute
def handle(params):
return f"Result for {params['query']}"
@plugin.on_initialize
def init():
plugin.log("Plugin ready")
plugin.run()TypeScript Plugin SDK
@streamcore/pluginInstall
npm install @streamcore/pluginUsage
import { StreamCoreAIPlugin } from '@streamcore/plugin';
const plugin = new StreamCoreAIPlugin();
plugin.onExecute(async (params) => {
return `Result for ${params.query}`;
});
plugin.onInitialize(() => {
plugin.log("Plugin ready");
});
plugin.run();