Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@langchain/protocol

Package Overview
Dependencies
Maintainers
13
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@langchain/protocol - npm Package Compare versions

Comparing version
0.0.8
to
0.0.9
+1
-1
package.json
{
"name": "@langchain/protocol",
"version": "0.0.8",
"version": "0.0.9",
"description": "TypeScript bindings for the LangChain agent streaming protocol",

@@ -5,0 +5,0 @@ "license": "MIT",

+109
-528

@@ -10,14 +10,12 @@ // ==========================================================================

// abstraction level (chat model, tool, graph, agent).
// 2. Streaming protocol — BiDi-modeled (after W3C WebDriver BiDi) with
// subscription-based event filtering, hierarchical namespace scoping,
// multi-transport support (WebSocket, SSE, in-process), and extended
// modules for resource access, sandbox control, and cost tracking.
// 2. Streaming protocol — thread-centric design with connection-scoped
// event filtering, hierarchical namespace scoping, and multi-transport
// support (WebSocket, SSE, in-process).
// The result is a single protocol where:
// - Content blocks are the universal delta carrier for LLM streaming
// - Events have full lifecycle semantics (no inferred boundaries)
// - Namespace-based subscription filtering provides server-side routing
// - A shared session core spans multiple transport profiles with explicit
// capability advertisement
// - Namespace-based filtering provides server-side routing
// - Threads are the primary routing key across all transports
// Status: DRAFT
// Version: 0.4.0
// Version: 0.5.0
// ==========================================================================

@@ -204,3 +202,3 @@ // ==========================================================================

// 3. Top-Level Message Framing
// Three message types flow over the connection, mirroring WebDriver BiDi:
// Three message types flow over the connection:
// Command — client -> server

@@ -223,3 +221,3 @@ // CommandResponse — server -> client (success)

// --- Server -> Client ---
export type CommandData = SessionCommand | RunCommand | SubscriptionCommand | FlowCommand | AgentCommand | ResourceCommand | SandboxCommand | InputCommand | StateCommand | UsageCommand;
export type CommandData = RunCommand | SubscriptionCommand | FlowCommand | AgentCommand | InputCommand | StateCommand;

@@ -257,88 +255,53 @@ export type Message = CommandResponse | ErrorResponse | Event;

export type ResultData = SessionResult | RunResult | SubscriptionResult | AgentResult | ResourceResult | SandboxResult | InputResult | StateResult | UsageResult | EmptyResult;
export type ResultData = RunResult | SubscriptionResult | AgentResult | InputResult | StateResult | EmptyResult;
export type EmptyResult = Extensible;
export type ErrorCode = "invalid_argument" | "unknown_command" | "unknown_error" | "no_such_run" | "no_such_subscription" | "no_such_namespace" | "no_such_interrupt" | "no_such_checkpoint" | "permission_denied" | "not_supported";
// 4. Session Module
// Explicit session establishment and capability advertisement. Every transport
// profile exposes the same logical session metadata even when delivery differs.
// ==========================================================================
export type ErrorCode = "invalid_argument" | "unknown_command" | "unknown_error" | "unsupported_version" | "no_such_run" | "no_such_subscription" | "no_such_namespace" | "no_such_resource" | "no_such_terminal" | "no_such_interrupt" | "no_such_checkpoint" | "budget_exceeded" | "permission_denied" | "not_supported";
export type SessionCommand = SessionOpen | SessionDescribe | SessionClose;
export interface SessionOpen {
method: "session.open";
params: SessionOpenParams;
}
export type SessionTarget = Extensible & {
/**
* Host-scoped ID for the runnable target
*/
id: string;
};
export type SessionOpenParams = Extensible & {
protocol_version: string;
/**
* Required when one endpoint hosts many targets
*/
target?: SessionTarget;
preferred_transports?: TransportName[];
media_transfer_modes?: MediaTransferMode[];
};
export interface SessionDescribe {
method: "session.describe";
params: EmptyResult;
}
export interface SessionClose {
method: "session.close";
params: EmptyResult;
}
export type SessionResult = Extensible & {
session_id: string;
protocol_version: string;
transport: TransportProfile;
capabilities: CapabilityAdvertisement;
};
export type ResponseMeta = Extensible & {
session_id?: string;
applied_through_seq?: JsUint;
};
export type TransportProfile = Extensible & {
name: TransportName;
event_ordering: "connection-order" | "seq";
command_delivery: "in-band" | "request-response" | "direct-call";
media_transfer_modes?: MediaTransferMode[];
};
export type TransportName = "websocket" | "sse-http" | "in-process" | string;
export type MediaTransferMode = "binary-frame" | "base64-inline" | "parallel-binary-channel" | "upgrade-to-websocket" | "artifact-only" | string;
export type CapabilityAdvertisement = Extensible & {
modules: ModuleCapability[];
payload_types?: string[];
content_block_types?: string[];
};
// 4. Thread-Centric Model
// The protocol is thread-centric: threads are the primary routing key
// for commands, events, and subscriptions. There is no session handshake
// or server-side session state.
// Thread IDs may be client-generated (UUID) or server-assigned. The
// server creates the thread lazily on the first `run.input` if it does
// not already exist.
// Transport endpoints:
// **SSE/HTTP:**
// POST /v2/threads/:thread_id/events — filtered SSE event stream
// POST /v2/threads/:thread_id/commands — JSON command request/response
// **WebSocket:**
// ws://.../v2/threads/:thread_id — full-duplex connection
// Subscription model varies by transport:
// **SSE/HTTP:** Subscriptions are connection-scoped. Each
// `POST .../events` request carries its own filter (channels, namespaces,
// depth) and the server streams matching events for the lifetime of that
// connection. Closing the connection unsubscribes. No subscription state
// is persisted on the server. Event streams can be opened before or after
// `run.input`; streams opened before a run exists stay idle until events
// are produced.
// **WebSocket:** Subscriptions are managed via in-band
// `subscription.subscribe` and `subscription.unsubscribe` commands on
// the single bidirectional connection. Subscriptions persist across run
// boundaries and are removed by explicit `subscription.unsubscribe` or
// when the WebSocket connection is closed.
// Multiple connections may observe the same thread concurrently, each
// with independent event filters. The thread is the durable identity
// (checkpoint, state, run history); each connection is an ephemeral
// transport scope for what a particular consumer sees.
// Cleanup is implicit: when the run completes and all connections close,
// the server drops ephemeral in-memory state (event buffer, run session).
// The thread itself persists in the checkpoint store.
// ==========================================================================
// ==========================================================================
// 4a. Run Module
// `run.input` is the single entry point for all input to the graph.
// The session manages a state machine:
// The thread manages a state machine:
// - No active run → starts a new run with the provided input
// - Run interrupted → resumes with the input as the resume value
// - Run active → injects input into the running graph
// This replaces the pattern of passing `input` at session creation time
// and unifies start, resume, and inject into one command.
// The `assistantId` field identifies which deployed graph or agent to
// run on this thread. It replaces session-level target binding.
// ==========================================================================
export type ModuleCapability = Extensible & {
name: string;
channels?: Channel[];
commands?: string[];
events?: string[];
export type ResponseMeta = Extensible & {
applied_through_seq?: JsUint;
};

@@ -355,2 +318,6 @@

/**
* Deployed graph/agent to run
*/
assistant_id: string;
/**
* Graph input, resume value, or injected message

@@ -372,4 +339,4 @@ */

// Each channel corresponds to a subscribable event stream. Clients
// include channel names in subscription.subscribe to select which
// event types to receive.
// include channel names in event stream filters or subscription commands
// to select which event types to receive.
// ==========================================================================

@@ -385,11 +352,50 @@ export interface RunResult {

// ==========================================================================
// 6. Subscription Module
// Mirrors BiDi session.subscribe / session.unsubscribe. The core
// mechanism for server-side event filtering. Subscriptions filter
// on two dimensions: channels (event types) and namespaces (agent
// hierarchy positions). Namespace subscriptions use prefix matching.
// 6. Subscription & Event Streaming
// The protocol supports two subscription models depending on transport:
// **SSE/HTTP transport (connection-scoped subscriptions):**
// Clients open one or more `POST /v2/threads/:thread_id/events` requests,
// each carrying an `EventStreamRequest` body with the desired channel
// and namespace filters. The server responds with an SSE stream
// filtered to match. Each connection IS the subscription — closing
// the connection unsubscribes. No subscription state is persisted on
// the server beyond the lifetime of the TCP connection.
// Multiple concurrent event streams are supported. Each stream
// independently filters the same underlying event source. Clients
// may bundle multiple channels into one connection or open dedicated
// connections per channel.
// **WebSocket transport (in-band command subscriptions):**
// WebSocket connections use `subscription.subscribe` and
// `subscription.unsubscribe` as in-band commands on the single
// bidirectional connection. Subscriptions persist across run
// boundaries and are removed by explicit `subscription.unsubscribe`
// or when the connection is closed.
// **Replay / reconnection:**
// For SSE/HTTP, the `EventStreamRequest` includes an optional `since`
// field (sequence number). The server replays matching events from its
// ring buffer starting after that sequence, then switches to live
// delivery. For WebSocket, `subscription.reconnect` serves the same
// purpose.
// ==========================================================================
export type Channel = "values" | "updates" | "messages" | "tools" | "lifecycle" | "media" | "resource" | "sandbox" | "input" | "usage" | "debug" | "checkpoints" | "tasks" | "custom" | `custom:${string}`;
// --- Event stream request (SSE/HTTP transport only) ---
// Sent as the JSON body of `POST /v2/threads/:thread_id/events`.
// The server responds with `Content-Type: text/event-stream`.
export type Channel = "values" | "updates" | "messages" | "tools" | "lifecycle" | "input" | "debug" | "checkpoints" | "tasks" | "custom" | `custom:${string}`;
// --- subscription.subscribe ---
// --- WebSocket-only subscription commands ---
export type EventStreamRequest = Extensible & {
channels: Channel[];
/**
* Prefix-match these namespace paths
*/
namespaces?: Namespace[];
/**
* Max depth below namespace prefix
*/
depth?: number;
/**
* Replay events after this seq number
*/
since?: JsUint;
};
export type SubscriptionCommand = SubscriptionSubscribe | SubscriptionUnsubscribe | SubscriptionReconnect;

@@ -412,9 +418,4 @@

depth?: number;
/**
* Filter media channel by modality
*/
media_types?: MediaType[];
};
// --- subscription.unsubscribe ---
export type SubscribeResult = Extensible & {

@@ -433,7 +434,2 @@ subscription_id: string;

// --- subscription.reconnect ---
// Supports reconnection after disconnect. The server replays missed
// events from a bounded event buffer, then drains any events that
// arrived during replay before switching to live delivery (snapshot +
// drain pattern).
export type UnsubscribeParams = Extensible & {

@@ -533,3 +529,3 @@ subscription_id: string;

// product-specific knowledge.
export type EventData = LifecycleEvent | MessagesEvent | ToolsEvent | MediaEvent | ResourceEvent | SandboxEvent | InputEvent | UsageEvent | ValuesEvent | UpdatesEvent | CustomEvent | DebugEvent | CheckpointsEvent | TasksEvent;
export type EventData = LifecycleEvent | MessagesEvent | ToolsEvent | InputEvent | ValuesEvent | UpdatesEvent | CustomEvent | DebugEvent | CheckpointsEvent | TasksEvent;

@@ -723,7 +719,6 @@ export interface LifecycleEvent {

// ==========================================================================
// 10. Media Module
// Audio, video, and image streaming. JSON events manage stream lifecycle;
// binary frames carry the actual media payload over WebSocket. For SSE
// transport, media data falls back to Base64-encoded JSON events or
// parallel binary fetch channels.
// 10. Input Module
// Human-in-the-loop. Wraps LangGraph's interrupt() / Command({ resume })
// as in-band protocol messages. Also supports unsolicited user input
// injection while the agent is running.
// ==========================================================================

@@ -737,339 +732,2 @@ export type ToolErrorData = Extensible & {

export type MediaEvent = MediaStreamStart | MediaStreamEnd | MediaArtifact;
// --- media.streamStart ---
export type MediaType = "audio" | "video" | "image";
export interface MediaStreamStart {
method: "media.streamStart";
params: MediaStreamStartParams;
}
// --- media.streamEnd ---
export interface MediaStreamStartParams {
namespace: Namespace;
timestamp: Timestamp;
stream_id: JsUint;
media_type: MediaType;
codec: string;
/**
* Audio: samples per second
*/
sample_rate?: number;
/**
* Audio: channel count (1=mono, 2=stereo)
*/
channels?: number;
/**
* Video/image: pixel width
*/
width?: number;
/**
* Video/image: pixel height
*/
height?: number;
/**
* Video: frames per second
*/
frame_rate?: number;
/**
* MIME type
*/
mime_type?: string;
/**
* Total size when known (for progress)
*/
size_bytes?: number;
/**
* Codec-specific or voice metadata
*/
metadata?: Record<string, any>;
}
export interface MediaStreamEnd {
method: "media.streamEnd";
params: MediaStreamEndParams;
}
// --- media.artifact (non-streaming media, e.g. single image) ---
export interface MediaStreamEndParams {
namespace: Namespace;
timestamp: Timestamp;
stream_id: JsUint;
reason: "completed" | "failed" | "cancelled";
duration_ms?: number;
error?: string;
}
// --- Binary frame header (not JSON — fixed 16 bytes on the wire) ---
// Transmitted as raw bytes in WebSocket binary frames, not as JSON.
// CDDL is used here only for documentation; implementations
// serialize/deserialize manually.
// BinaryFrameHeader = (
// streamId: uint32, ; Maps to media.streamStart streamId
// sequence: uint32, ; Monotonic per stream, for gap detection
// timestampMicros: uint32, ; Microsecond offset from stream start
// payloadLength: uint32, ; Byte count of following payload
// )
// Total: 16 bytes header + payloadLength bytes payload per binary frame.
// ==========================================================================
// 11. Resource Module
// File system access to agent sandboxes. Provides browsing, reading,
// writing, and downloading files from the agent's execution environment.
// ==========================================================================
export interface MediaArtifact {
method: "media.artifact";
/**
* Same shape as streamStart
*/
params: MediaStreamStartParams;
}
// --- resource.list ---
export type ResourceCommand = ResourceList | ResourceRead | ResourceWrite | ResourceDownload;
export interface ResourceList {
method: "resource.list";
params: ResourceListParams;
}
export interface ResourceListParams {
namespace: Namespace;
path: string;
/**
* Recurse N levels (default: 1)
*/
depth?: number;
/**
* Include size, mtime, permissions
*/
include_metadata?: boolean;
}
export interface ResourceEntry {
name: string;
path: string;
type: "file" | "directory" | "symlink";
size_bytes?: number;
modified_at?: Timestamp;
/**
* Unix-style e.g. "rwxr-xr-x"
*/
permissions?: string;
/**
* When depth > 1
*/
children?: ResourceEntry[];
}
// --- resource.read ---
export interface ResourceListResult {
entries: ResourceEntry[];
}
export interface ResourceRead {
method: "resource.read";
params: ResourceReadParams;
}
export interface ResourceReadParams {
namespace: Namespace;
path: string;
/**
* Default: utf-8
*/
encoding?: "utf-8" | "binary";
/**
* Partial read
*/
range?: LineRange;
}
export interface LineRange {
start_line: number;
end_line: number;
}
// --- resource.write ---
export interface ResourceReadResult {
/**
* Text content (utf-8) or null for binary
*/
content: string | null;
/**
* For binary: content delivered via binary frames
*/
stream_id?: JsUint;
size_bytes?: number;
mime_type?: string;
}
export interface ResourceWrite {
method: "resource.write";
params: ResourceWriteParams;
}
// --- resource.download ---
export interface ResourceWriteParams {
namespace: Namespace;
path: string;
content: string;
encoding?: "utf-8";
/**
* mkdir -p parent directories
*/
create_directories?: boolean;
}
export interface ResourceDownload {
method: "resource.download";
params: ResourceDownloadParams;
}
export interface ResourceDownloadParams {
namespace: Namespace;
path: string;
}
export interface ResourceDownloadResult {
/**
* Binary frames follow with file data
*/
stream_id: JsUint;
size_bytes: number;
mime_type: string;
}
// --- Resource events (server -> client, channel: "resource") ---
export type ResourceResult = ResourceListResult | ResourceReadResult | ResourceDownloadResult | EmptyResult;
export interface ResourceEvent {
method: "resource.changed";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: ResourceChangedData;
};
}
export interface ResourceChangedData {
changes: ResourceChange[];
}
// ==========================================================================
// 12. Sandbox Module
// Shell command execution in sandboxed agent environments (Modal,
// Daytona, E2B, local VFS). Streams stdout/stderr in real time.
// ==========================================================================
export interface ResourceChange {
type: "created" | "modified" | "deleted" | "moved";
path: string;
size_bytes?: number;
/**
* For "moved" type
*/
old_path?: string;
/**
* Optional inline content for small files
*/
content?: string;
/**
* Optional unified diff for "modified"
*/
diff?: string;
}
// --- sandbox.input ---
export type SandboxCommand = SandboxInput | SandboxKill;
export interface SandboxInput {
method: "sandbox.input";
params: SandboxInputParams;
}
// --- sandbox.kill ---
export interface SandboxInputParams {
namespace: Namespace;
terminal_id: string;
text: string;
}
export interface SandboxKill {
method: "sandbox.kill";
params: SandboxKillParams;
}
export interface SandboxKillParams {
namespace: Namespace;
terminal_id: string;
/**
* Default: "SIGTERM"
*/
signal?: string;
}
// --- Sandbox events (server -> client, channel: "sandbox") ---
export type SandboxResult = EmptyResult;
export type SandboxEvent = SandboxStarted | SandboxOutput | SandboxExited;
export interface SandboxStarted {
method: "sandbox.started";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: SandboxStartedData;
};
}
export interface SandboxStartedData {
terminal_id: string;
command: string;
cwd?: string;
/**
* Sanitized, no secrets
*/
env?: Record<string, string>;
}
export interface SandboxOutput {
method: "sandbox.output";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: SandboxOutputData;
};
}
export interface SandboxOutputData {
terminal_id: string;
stream: "stdout" | "stderr";
text: string;
}
export interface SandboxExited {
method: "sandbox.exited";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: SandboxExitedData;
};
}
// ==========================================================================
// 13. Input Module
// Human-in-the-loop. Wraps LangGraph's interrupt() / Command({ resume })
// as in-band protocol messages. Also supports unsolicited user input
// injection while the agent is running.
// ==========================================================================
export interface SandboxExitedData {
terminal_id: string;
exit_code: number;
duration_ms?: number;
/**
* If killed by signal
*/
signal?: string;
}
// --- input.respond ---

@@ -1119,3 +777,3 @@ export type InputCommand = InputRespond | InputInject;

// ==========================================================================
// 14. State Module
// 11. State Module
// Graph state and checkpoint access. Enables state inspection and

@@ -1220,77 +878,3 @@ // time-travel debugging (fork from checkpoint).

// ==========================================================================
// 15. Usage Module
// Cost tracking, token usage, and budget enforcement. Enables
// real-time cost dashboards and runaway-agent protection.
// ==========================================================================
export type StateResult = StateGetResult | ListCheckpointsResult | StateForkResult | EmptyResult;
// --- usage.setBudget ---
export type UsageCommand = UsageSetBudget;
export interface UsageSetBudget {
method: "usage.setBudget";
params: UsageBudgetParams;
}
export interface UsageBudgetParams {
/**
* Per-agent budget; omit for run-wide
*/
namespace?: Namespace;
max_cost_usd: number;
/**
* What to do when budget exceeded
*/
action: "pause" | "cancel";
}
// --- Usage events (server -> client, channel: "usage") ---
export type UsageResult = EmptyResult;
export type UsageEvent = UsageLlmCall | UsageSummary;
export interface UsageLlmCall {
method: "usage.llmCall";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: LlmCallUsageData;
};
}
export interface LlmCallUsageData {
model: string;
provider?: string;
input_tokens: number;
output_tokens: number;
cached_tokens?: number;
cost_usd?: number;
latency_ms?: number;
request_id?: string;
}
export interface UsageSummary {
method: "usage.summary";
params: {
namespace: Namespace;
timestamp: Timestamp;
data: UsageSummaryData;
};
}
export interface UsageSummaryData {
total_input_tokens: number;
total_output_tokens: number;
total_cost_usd?: number;
by_model?: Record<string, ModelUsage>;
by_namespace?: Record<string, NamespaceUsage>;
}
export interface ModelUsage {
calls: number;
cost_usd?: number;
}
// ==========================================================================
// 16. Passthrough Channels
// 12. Passthrough Channels
// These channels carry payloads shaped by the LangGraph runtime and

@@ -1306,6 +890,3 @@ // user graph schemas. Their data shapes are intentionally open

// Full graph state after each step or initial snapshot.
export interface NamespaceUsage {
calls: number;
cost_usd?: number;
}
export type StateResult = StateGetResult | ListCheckpointsResult | StateForkResult | EmptyResult;

@@ -1312,0 +893,0 @@ // --- updates (channel: "updates") ---