@langchain/react 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/selectors.cjs +54 -0
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.d.cts +50 -2
- package/dist/selectors.d.cts.map +1 -1
- package/dist/selectors.d.ts +50 -2
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +56 -3
- package/dist/selectors.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -80,6 +80,7 @@ Object.defineProperty(exports, "parseHeadlessToolInterruptPayload", {
|
|
|
80
80
|
exports.useAudio = require_selectors.useAudio;
|
|
81
81
|
exports.useAudioPlayer = require_use_audio_player.useAudioPlayer;
|
|
82
82
|
exports.useChannel = require_selectors.useChannel;
|
|
83
|
+
exports.useChannelEffect = require_selectors.useChannelEffect;
|
|
83
84
|
exports.useExtension = require_selectors.useExtension;
|
|
84
85
|
exports.useFiles = require_selectors.useFiles;
|
|
85
86
|
exports.useImages = require_selectors.useImages;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentServerOptions, AnyStream, CustomAdapterOptions, STREAM_CONTROLLER, UseStreamOptions, UseStreamResult, UseStreamReturn, useStream } from "./use-stream.cjs";
|
|
2
2
|
import { useProjection } from "./use-projection.cjs";
|
|
3
|
-
import { SelectorTarget, SubmissionQueueEntry, SubmissionQueueSnapshot, UseSubmissionQueueReturn, useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.cjs";
|
|
3
|
+
import { SelectorTarget, SubmissionQueueEntry, SubmissionQueueSnapshot, UseChannelEffectOptions, UseSubmissionQueueReturn, useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.cjs";
|
|
4
4
|
import { useMediaURL } from "./use-media-url.cjs";
|
|
5
5
|
import { AudioPlayerHandle, PlayerStatus, UseAudioPlayerOptions, useAudioPlayer } from "./use-audio-player.cjs";
|
|
6
6
|
import { UseVideoPlayerOptions, VideoPlayerHandle, useVideoPlayer } from "./use-video-player.cjs";
|
|
@@ -13,5 +13,5 @@ import { AgentServerAdapter, AnyMediaHandle, AssembledToolCall, AssembledToolCal
|
|
|
13
13
|
//#region src/index.d.ts
|
|
14
14
|
type ToolCallWithResult<ToolCall = DefaultToolCall$1> = ToolCallWithResult$1<ToolCall, ToolMessage, AIMessage>;
|
|
15
15
|
//#endregion
|
|
16
|
-
export { type AgentServerAdapter, type AgentServerOptions, type AnyHeadlessToolImplementation, type AnyMediaHandle, type AnyStream, type AssembledToolCall, type AudioMedia, type AudioPlayerHandle, type Channel, type CustomAdapterOptions, type DefaultToolCall, type Event, type FileMedia, type FlushPendingHeadlessToolInterruptsOptions, type HeadlessToolImplementation, type HeadlessToolInterrupt, HttpAgentServerAdapter, type HttpAgentServerAdapterOptions, type ImageMedia, type InferStateType, type InferSubagentStates, type InferToolCalls, type InferToolOutput, MediaAssemblyError, type MediaAssemblyErrorKind, type MediaBase, type MediaBlockType, type MessageMetadata, type MessageMetadataMap, type OnToolCallback, type PlayerStatus, STREAM_CONTROLLER, type SelectorTarget, StreamProvider, type StreamProviderCustomProps, type StreamProviderProps, type StreamStopOptions, type StreamSubmitOptions, type SubagentDiscoverySnapshot, type SubgraphDiscoverySnapshot, type SubmissionQueueEntry, type SubmissionQueueSnapshot, type ToolCallFromTool, type ToolCallState, type ToolCallStatus, ToolCallWithResult, type ToolCallsFromTools, type ToolEvent, type UseAudioPlayerOptions, type UseStreamOptions, type UseStreamResult, type UseStreamReturn, type UseSubmissionQueueReturn, type UseSuspenseStreamReturn, type UseVideoPlayerOptions, type VideoMedia, type VideoPlayerHandle, type WidenUpdateMessages, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
|
16
|
+
export { type AgentServerAdapter, type AgentServerOptions, type AnyHeadlessToolImplementation, type AnyMediaHandle, type AnyStream, type AssembledToolCall, type AudioMedia, type AudioPlayerHandle, type Channel, type CustomAdapterOptions, type DefaultToolCall, type Event, type FileMedia, type FlushPendingHeadlessToolInterruptsOptions, type HeadlessToolImplementation, type HeadlessToolInterrupt, HttpAgentServerAdapter, type HttpAgentServerAdapterOptions, type ImageMedia, type InferStateType, type InferSubagentStates, type InferToolCalls, type InferToolOutput, MediaAssemblyError, type MediaAssemblyErrorKind, type MediaBase, type MediaBlockType, type MessageMetadata, type MessageMetadataMap, type OnToolCallback, type PlayerStatus, STREAM_CONTROLLER, type SelectorTarget, StreamProvider, type StreamProviderCustomProps, type StreamProviderProps, type StreamStopOptions, type StreamSubmitOptions, type SubagentDiscoverySnapshot, type SubgraphDiscoverySnapshot, type SubmissionQueueEntry, type SubmissionQueueSnapshot, type ToolCallFromTool, type ToolCallState, type ToolCallStatus, ToolCallWithResult, type ToolCallsFromTools, type ToolEvent, type UseAudioPlayerOptions, type UseChannelEffectOptions, type UseStreamOptions, type UseStreamResult, type UseStreamReturn, type UseSubmissionQueueReturn, type UseSuspenseStreamReturn, type UseVideoPlayerOptions, type VideoMedia, type VideoPlayerHandle, type WidenUpdateMessages, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
|
17
17
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;KAuGY,kBAAA,YAA8B,iBAAA,IACxC,oBAAA,CAAoB,QAAA,EAAU,WAAA,EAAiB,SAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentServerOptions, AnyStream, CustomAdapterOptions, STREAM_CONTROLLER, UseStreamOptions, UseStreamResult, UseStreamReturn, useStream } from "./use-stream.js";
|
|
2
2
|
import { useProjection } from "./use-projection.js";
|
|
3
|
-
import { SelectorTarget, SubmissionQueueEntry, SubmissionQueueSnapshot, UseSubmissionQueueReturn, useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.js";
|
|
3
|
+
import { SelectorTarget, SubmissionQueueEntry, SubmissionQueueSnapshot, UseChannelEffectOptions, UseSubmissionQueueReturn, useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.js";
|
|
4
4
|
import { useMediaURL } from "./use-media-url.js";
|
|
5
5
|
import { AudioPlayerHandle, PlayerStatus, UseAudioPlayerOptions, useAudioPlayer } from "./use-audio-player.js";
|
|
6
6
|
import { UseVideoPlayerOptions, VideoPlayerHandle, useVideoPlayer } from "./use-video-player.js";
|
|
@@ -13,5 +13,5 @@ import { AIMessage, ToolMessage } from "@langchain/core/messages";
|
|
|
13
13
|
//#region src/index.d.ts
|
|
14
14
|
type ToolCallWithResult<ToolCall = DefaultToolCall$1> = ToolCallWithResult$1<ToolCall, ToolMessage, AIMessage>;
|
|
15
15
|
//#endregion
|
|
16
|
-
export { type AgentServerAdapter, type AgentServerOptions, type AnyHeadlessToolImplementation, type AnyMediaHandle, type AnyStream, type AssembledToolCall, type AudioMedia, type AudioPlayerHandle, type Channel, type CustomAdapterOptions, type DefaultToolCall, type Event, type FileMedia, type FlushPendingHeadlessToolInterruptsOptions, type HeadlessToolImplementation, type HeadlessToolInterrupt, HttpAgentServerAdapter, type HttpAgentServerAdapterOptions, type ImageMedia, type InferStateType, type InferSubagentStates, type InferToolCalls, type InferToolOutput, MediaAssemblyError, type MediaAssemblyErrorKind, type MediaBase, type MediaBlockType, type MessageMetadata, type MessageMetadataMap, type OnToolCallback, type PlayerStatus, STREAM_CONTROLLER, type SelectorTarget, StreamProvider, type StreamProviderCustomProps, type StreamProviderProps, type StreamStopOptions, type StreamSubmitOptions, type SubagentDiscoverySnapshot, type SubgraphDiscoverySnapshot, type SubmissionQueueEntry, type SubmissionQueueSnapshot, type ToolCallFromTool, type ToolCallState, type ToolCallStatus, ToolCallWithResult, type ToolCallsFromTools, type ToolEvent, type UseAudioPlayerOptions, type UseStreamOptions, type UseStreamResult, type UseStreamReturn, type UseSubmissionQueueReturn, type UseSuspenseStreamReturn, type UseVideoPlayerOptions, type VideoMedia, type VideoPlayerHandle, type WidenUpdateMessages, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
|
16
|
+
export { type AgentServerAdapter, type AgentServerOptions, type AnyHeadlessToolImplementation, type AnyMediaHandle, type AnyStream, type AssembledToolCall, type AudioMedia, type AudioPlayerHandle, type Channel, type CustomAdapterOptions, type DefaultToolCall, type Event, type FileMedia, type FlushPendingHeadlessToolInterruptsOptions, type HeadlessToolImplementation, type HeadlessToolInterrupt, HttpAgentServerAdapter, type HttpAgentServerAdapterOptions, type ImageMedia, type InferStateType, type InferSubagentStates, type InferToolCalls, type InferToolOutput, MediaAssemblyError, type MediaAssemblyErrorKind, type MediaBase, type MediaBlockType, type MessageMetadata, type MessageMetadataMap, type OnToolCallback, type PlayerStatus, STREAM_CONTROLLER, type SelectorTarget, StreamProvider, type StreamProviderCustomProps, type StreamProviderProps, type StreamStopOptions, type StreamSubmitOptions, type SubagentDiscoverySnapshot, type SubgraphDiscoverySnapshot, type SubmissionQueueEntry, type SubmissionQueueSnapshot, type ToolCallFromTool, type ToolCallState, type ToolCallStatus, ToolCallWithResult, type ToolCallsFromTools, type ToolEvent, type UseAudioPlayerOptions, type UseChannelEffectOptions, type UseStreamOptions, type UseStreamResult, type UseStreamReturn, type UseSubmissionQueueReturn, type UseSuspenseStreamReturn, type UseVideoPlayerOptions, type VideoMedia, type VideoPlayerHandle, type WidenUpdateMessages, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;KAuGY,kBAAA,YAA8B,iBAAA,IACxC,oBAAA,CAAoB,QAAA,EAAU,WAAA,EAAiB,SAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { STREAM_CONTROLLER, useStream } from "./use-stream.js";
|
|
2
2
|
import { useProjection } from "./use-projection.js";
|
|
3
|
-
import { useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.js";
|
|
3
|
+
import { useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo } from "./selectors.js";
|
|
4
4
|
import { useMediaURL } from "./use-media-url.js";
|
|
5
5
|
import { useAudioPlayer } from "./use-audio-player.js";
|
|
6
6
|
import { useVideoPlayer } from "./use-video-player.js";
|
|
@@ -8,4 +8,4 @@ import { useSuspenseStream } from "./suspense-stream.js";
|
|
|
8
8
|
import { StreamProvider, useStreamContext } from "./context.js";
|
|
9
9
|
import { HttpAgentServerAdapter, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload } from "@langchain/langgraph-sdk";
|
|
10
10
|
import { MediaAssemblyError } from "@langchain/langgraph-sdk/stream";
|
|
11
|
-
export { HttpAgentServerAdapter, MediaAssemblyError, STREAM_CONTROLLER, StreamProvider, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
|
11
|
+
export { HttpAgentServerAdapter, MediaAssemblyError, STREAM_CONTROLLER, StreamProvider, applyHeadlessToolResumeCommand, executeHeadlessTool, filterOutHeadlessToolInterrupts, findHeadlessTool, flushPendingHeadlessToolInterrupts, handleHeadlessToolInterrupt, headlessToolResumeCommand, isHeadlessToolInterrupt, parseHeadlessToolInterruptPayload, useAudio, useAudioPlayer, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMediaURL, useMessageMetadata, useMessages, useProjection, useStream, useStreamContext, useSubmissionQueue, useSuspenseStream, useToolCalls, useValues, useVideo, useVideoPlayer };
|
package/dist/selectors.cjs
CHANGED
|
@@ -172,6 +172,59 @@ function useChannel(stream, channels, target, options) {
|
|
|
172
172
|
}
|
|
173
173
|
const EMPTY_EVENTS = [];
|
|
174
174
|
/**
|
|
175
|
+
* Side-effect counterpart to {@link useChannel}. Instead of returning a
|
|
176
|
+
* buffer of events that re-renders the component, it invokes `onEvent`
|
|
177
|
+
* once per event for as long as the hook is mounted — the idiomatic
|
|
178
|
+
* place for analytics, logging, and other fire-and-forget side effects.
|
|
179
|
+
*
|
|
180
|
+
* ```tsx
|
|
181
|
+
* useChannelEffect(stream, ["lifecycle", "tools"], {
|
|
182
|
+
* replay: false,
|
|
183
|
+
* onEvent(event) {
|
|
184
|
+
* sendAnalytics(event);
|
|
185
|
+
* },
|
|
186
|
+
* onError(error) {
|
|
187
|
+
* logger.error(error);
|
|
188
|
+
* },
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* Notes:
|
|
193
|
+
* - `onEvent` / `onError` are read from a ref, so passing a fresh
|
|
194
|
+
* closure each render is fine — it never re-subscribes.
|
|
195
|
+
* - The underlying subscription is shared (ref-counted) with any
|
|
196
|
+
* matching {@link useChannel} consumer, so you only ever pay for one
|
|
197
|
+
* server subscription per channel set.
|
|
198
|
+
* - `replay` defaults to `false` (live-only). Set it to `true` only if
|
|
199
|
+
* you genuinely want to (re)process replayed history.
|
|
200
|
+
* - Events buffered before the hook mounts are not re-delivered.
|
|
201
|
+
*/
|
|
202
|
+
function useChannelEffect(stream, channels, options) {
|
|
203
|
+
const { target, enabled = true, replay, bufferSize, onEvent, onError } = options;
|
|
204
|
+
const onEventRef = (0, react.useRef)(onEvent);
|
|
205
|
+
const onErrorRef = (0, react.useRef)(onError);
|
|
206
|
+
onEventRef.current = onEvent;
|
|
207
|
+
onErrorRef.current = onError;
|
|
208
|
+
useResolveSubagentNamespace(stream, target);
|
|
209
|
+
const namespace = resolveNamespace(target);
|
|
210
|
+
const channelKey = (0, react.useMemo)(() => [...channels].sort().join(","), [channels]);
|
|
211
|
+
const key = `channelEffect|${bufferSize ?? "default"}|${replay ?? false ? "replay" : "live"}|${channelKey}|${namespaceKey(namespace)}`;
|
|
212
|
+
const registry = require_use_stream.getRegistry(stream);
|
|
213
|
+
(0, react.useEffect)(() => {
|
|
214
|
+
if (!enabled || registry == null) return void 0;
|
|
215
|
+
return (0, _langchain_langgraph_sdk_stream.acquireChannelEffect)(registry, channels, namespace, {
|
|
216
|
+
replay,
|
|
217
|
+
bufferSize,
|
|
218
|
+
onEvent: (event) => onEventRef.current(event),
|
|
219
|
+
onError: (error) => onErrorRef.current?.(error)
|
|
220
|
+
});
|
|
221
|
+
}, [
|
|
222
|
+
registry,
|
|
223
|
+
key,
|
|
224
|
+
enabled
|
|
225
|
+
]);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
175
228
|
* Read metadata recorded for a specific message id — today exposes
|
|
176
229
|
* `parentCheckpointId`, the checkpoint the message was first seen on.
|
|
177
230
|
* Designed for fork / edit flows:
|
|
@@ -207,6 +260,7 @@ function useSubmissionQueue(stream) {
|
|
|
207
260
|
//#endregion
|
|
208
261
|
exports.useAudio = useAudio;
|
|
209
262
|
exports.useChannel = useChannel;
|
|
263
|
+
exports.useChannelEffect = useChannelEffect;
|
|
210
264
|
exports.useExtension = useExtension;
|
|
211
265
|
exports.useFiles = useFiles;
|
|
212
266
|
exports.useImages = useImages;
|
package/dist/selectors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.cjs","names":["STREAM_CONTROLLER","NAMESPACE_SEPARATOR","useProjection","getRegistry"],"sources":["../src/selectors.ts"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useMemo, useSyncExternalStore } from \"react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n MessageMetadata,\n MessageMetadataMap,\n SubmissionQueueEntry,\n SubmissionQueueSnapshot,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n NAMESPACE_SEPARATOR,\n audioProjection,\n channelProjection,\n extensionProjection,\n filesProjection,\n imagesProjection,\n messagesProjection,\n toolCallsProjection,\n valuesProjection,\n videoProjection,\n type AssembledToolCall,\n type AudioMedia,\n type Channel,\n type ChannelProjectionOptions,\n type Event,\n type FileMedia,\n type ImageMedia,\n type InferToolCalls,\n type InferStateType,\n type SubagentDiscoverySnapshot,\n type SubgraphDiscoverySnapshot,\n type VideoMedia,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n getRegistry,\n STREAM_CONTROLLER,\n type AnyStream,\n type UseStreamReturn,\n} from \"./use-stream.js\";\nimport { useProjection } from \"./use-projection.js\";\n\n/**\n * Selector hooks don't need to carry `InterruptType` /\n * `ConfigurableType` — they only ever read state. Accepting a\n * `StateType`-parameterised stream (with the other two generics\n * widened to `any`) lets callers keep their full\n * `useStream<State, Interrupt, Configurable>()` handle\n * without re-declaring the interrupt / configurable shapes at every\n * selector call site.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype StreamHandle<StateType extends object> = UseStreamReturn<\n StateType,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n>;\n\n/**\n * What a selector hook can be targeted at. Callers can pass any of:\n * - `undefined` — root namespace (cheap: served by the always-on root store)\n * - a {@link SubagentDiscoverySnapshot} — the snapshot returned by `stream.subagents.get(...)`\n * - a {@link SubgraphDiscoverySnapshot} — the snapshot returned by `stream.subgraphs.get(...)`\n * - an explicit `{ namespace: string[] }` — any other namespaced scope\n * - a raw `string[]` — escape hatch identical to the object form\n */\nexport type SelectorTarget =\n | undefined\n | null\n | readonly string[]\n | { namespace: readonly string[] }\n | SubagentDiscoverySnapshot\n | SubgraphDiscoverySnapshot;\n\nfunction resolveNamespace(target: SelectorTarget): readonly string[] {\n if (target == null) return EMPTY_NAMESPACE;\n if (Array.isArray(target)) return target;\n const obj = target as { namespace?: readonly string[] };\n return obj.namespace ?? EMPTY_NAMESPACE;\n}\n\n/**\n * If `target` is a subagent snapshot still on its default\n * `tools:<toolCallId>` namespace, return that tool-call id so the\n * caller can trigger lazy execution-namespace resolution. Returns\n * `null` for root targets, subgraph hosts, explicit namespaces, and\n * already-promoted subagents.\n */\nfunction subagentNeedingNamespace(target: SelectorTarget): string | null {\n if (target == null || Array.isArray(target)) return null;\n const obj = target as { id?: unknown; namespace?: readonly string[] };\n if (typeof obj.id !== \"string\" || !Array.isArray(obj.namespace)) return null;\n if (obj.namespace.length === 1 && obj.namespace[0] === `tools:${obj.id}`) {\n return obj.id;\n }\n return null;\n}\n\n/**\n * Lazily resolve a subagent's execution namespace on the first scoped\n * mount. Deep-agent subagents execute under a `tools:<uuid>` namespace\n * distinct from their `tools:<toolCallId>` discovery key; until that is\n * known a scoped `useMessages`/`useToolCalls` would target the wrong\n * scope. The controller de-dupes and skips already-promoted ids, so\n * this is safe to call from every consumer of the same subagent.\n */\nfunction useResolveSubagentNamespace(\n stream: AnyStream,\n target: SelectorTarget\n): void {\n const controller = stream[STREAM_CONTROLLER];\n const toolCallId = subagentNeedingNamespace(target);\n useEffect(() => {\n if (toolCallId == null) return;\n void controller.resolveSubagentNamespace(toolCallId);\n }, [controller, toolCallId]);\n}\n\nconst EMPTY_NAMESPACE: readonly string[] = [];\n\nfunction isRoot(namespace: readonly string[]): boolean {\n return namespace.length === 0;\n}\n\nfunction namespaceKey(namespace: readonly string[]): string {\n return namespace.join(NAMESPACE_SEPARATOR);\n}\n\n// The stream type we accept for selectors — the public {@link AnyStream}\n// erased handle. It overrides the generic-computed covariant members\n// (`toolCalls`, `values`, `~stateType`) with their widest forms so a\n// concrete `useStream<typeof agent>()` handle flows in without an\n// `as AnyStream` cast (a bare `UseStreamReturn<any, any, any>` does not\n// — see the `AnyStream` definition in `use-stream.ts`).\n//\n// Typed selectors (`useValues<S>` etc.) use {@link StreamHandle} above\n// so the concrete `StateType` flows into the return; hooks that don't\n// depend on state (`useMessages`, `useAudio`, …) stay on `AnyStream`\n// for maximum flexibility.\n\n/**\n * Subscribe to a scoped `messages` stream. Pass `stream` and\n * optionally a subagent/subgraph snapshot (or any namespaced target).\n *\n * Contract:\n * - At the root (no target) this returns `stream.messages` directly\n * — no extra subscription is opened. `stream.messages` is the\n * live merge of `messages`-channel token deltas and\n * `values.messages` snapshots (see\n * {@link UseStreamReturn.messages}), so token-by-token\n * streaming here depends on the backend emitting `messages`\n * channel events. Backends that only emit `values` updates will\n * render full turns at once rather than streaming.\n * - For any other namespace, the mount triggers a ref-counted\n * `messages` subscription scoped to that namespace. Unmounting\n * the last component that watches this namespace closes the\n * subscription automatically.\n *\n * Messages are always `BaseMessage` class instances from\n * `@langchain/core/messages`.\n */\nexport function useMessages(\n stream: AnyStream,\n target?: SelectorTarget\n): BaseMessage[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `messages|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<BaseMessage[]>(\n registry,\n () => messagesProjection(namespace),\n key,\n EMPTY_MESSAGES\n );\n return isRoot(namespace) ? stream.messages : scoped;\n}\n\nconst EMPTY_MESSAGES: BaseMessage[] = [];\n\n/**\n * Subscribe to a scoped `tools` (tool-call) stream. Same target and\n * lifecycle rules as {@link useMessages}; at the root this just returns\n * `stream.toolCalls`.\n *\n * The optional generic `T` can be passed to narrow the type of\n * assembled tool calls on the returned array. Accepts either:\n * - an agent brand (`typeof agent`) — union is derived from the\n * agent's declared tools via {@link InferToolCalls};\n * - an array of LangGraph tools (`typeof tools`) — union is derived\n * from {@link InferToolCalls} (parallel to {@link ToolCallsFromTools}).\n *\n * When omitted, returns the plain `AssembledToolCall[]` union used by\n * the controller.\n */\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[];\nexport function useToolCalls<T>(\n stream: AnyStream,\n target?: SelectorTarget\n): InferToolCalls<T>[];\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `toolCalls|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<AssembledToolCall[]>(\n registry,\n () => toolCallsProjection(namespace),\n key,\n EMPTY_TOOLCALLS\n );\n return isRoot(namespace) ? stream.toolCalls : scoped;\n}\n\nconst EMPTY_TOOLCALLS: AssembledToolCall[] = [];\n\n/**\n * Subscribe to a scoped `values` stream — most-recent state payload\n * for a namespace. Equivalent to reading `stream.values` at the root.\n *\n * When the payload carries a `messages` array, it is coerced to\n * `BaseMessage` instances to keep parity with the root projection.\n *\n * Typing:\n * - **Root** (`useValues(stream)`): returns the `StateType` declared\n * on the parent `useStream<State>()` — no explicit\n * generic required. Non-nullable because the root snapshot always\n * carries `values` (falling back to `initialValues ?? {}`).\n * - **Scoped** (`useValues(stream, target)`): the scoped payload can\n * have a different shape than the root state (e.g. a subagent\n * returning its own substate). Callers should annotate the\n * expected shape explicitly: `useValues<SubagentState>(stream, sub)`.\n * Defaults to `unknown` when not annotated.\n */\nexport function useValues<StateType extends object>(\n stream: StreamHandle<StateType>\n): StateType;\n/**\n * Explicit-generic override. Accepts:\n * - an agent brand or compiled graph (unwrapped via\n * {@link InferStateType});\n * - a plain state shape (returned as-is).\n *\n * The root-call form is non-nullable (the root snapshot is always\n * present); the scoped form returns `T | undefined` because a\n * projection may not have emitted a payload yet.\n */\nexport function useValues<T>(stream: AnyStream): InferStateType<T>;\nexport function useValues<T = unknown>(\n stream: AnyStream,\n target: SelectorTarget,\n options?: { messagesKey?: string }\n): T | undefined;\nexport function useValues(\n stream: AnyStream,\n target?: SelectorTarget,\n options?: { messagesKey?: string }\n): unknown {\n const namespace = resolveNamespace(target);\n const messagesKey = options?.messagesKey ?? \"messages\";\n const key = `values|${messagesKey}|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<unknown>(\n registry,\n () => valuesProjection<unknown>(namespace, messagesKey),\n key,\n undefined\n );\n return isRoot(namespace) ? stream.values : scoped;\n}\n\n/**\n * Subscribe to a `custom:<name>` stream extension — the most-recent\n * payload emitted by the transformer, scoped to the target namespace.\n *\n * Returns only the latest value and resumes across serial runs, so it is\n * ideal for \"current state\" panels (progress, score, status). When you\n * need the full history of events rather than just the latest payload,\n * use {@link useChannel} instead.\n */\nexport function useExtension<T = unknown>(\n stream: AnyStream,\n name: string,\n target?: SelectorTarget\n): T | undefined {\n const namespace = resolveNamespace(target);\n const key = `extension|${name}|${namespaceKey(namespace)}`;\n return useProjection<T | undefined>(\n getRegistry(stream),\n () => extensionProjection<T>(name, namespace),\n key,\n undefined\n );\n}\n\n/**\n * Subscribe to a scoped audio-media stream. Returns an array of\n * {@link AudioMedia} handles, one per message containing at least one\n * `AudioBlock` in the target namespace.\n *\n * Each handle is yielded on its first matching `content-block-start`,\n * exposes `.partialBytes` for live access, settles `.blob` /\n * `.objectURL` / `.transcript` on `message-finish`, and surfaces\n * fail-loud errors via `.error`.\n *\n * Pair with {@link useMediaURL} to turn a handle into an `<audio src>`.\n */\nexport function useAudio(\n stream: AnyStream,\n target?: SelectorTarget\n): AudioMedia[] {\n const namespace = resolveNamespace(target);\n const key = `audio|${namespaceKey(namespace)}`;\n return useProjection<AudioMedia[]>(\n getRegistry(stream),\n () => audioProjection(namespace),\n key,\n EMPTY_AUDIO\n );\n}\n\nconst EMPTY_AUDIO: AudioMedia[] = [];\n\n/**\n * Subscribe to a scoped image-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<img src>`.\n */\nexport function useImages(\n stream: AnyStream,\n target?: SelectorTarget\n): ImageMedia[] {\n const namespace = resolveNamespace(target);\n const key = `images|${namespaceKey(namespace)}`;\n return useProjection<ImageMedia[]>(\n getRegistry(stream),\n () => imagesProjection(namespace),\n key,\n EMPTY_IMAGES\n );\n}\n\nconst EMPTY_IMAGES: ImageMedia[] = [];\n\n/**\n * Subscribe to a scoped video-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<video src>`.\n */\nexport function useVideo(\n stream: AnyStream,\n target?: SelectorTarget\n): VideoMedia[] {\n const namespace = resolveNamespace(target);\n const key = `video|${namespaceKey(namespace)}`;\n return useProjection<VideoMedia[]>(\n getRegistry(stream),\n () => videoProjection(namespace),\n key,\n EMPTY_VIDEO\n );\n}\n\nconst EMPTY_VIDEO: VideoMedia[] = [];\n\n/**\n * Subscribe to a scoped file-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for an\n * `<a download href>` target.\n */\nexport function useFiles(\n stream: AnyStream,\n target?: SelectorTarget\n): FileMedia[] {\n const namespace = resolveNamespace(target);\n const key = `files|${namespaceKey(namespace)}`;\n return useProjection<FileMedia[]>(\n getRegistry(stream),\n () => filesProjection(namespace),\n key,\n EMPTY_FILES\n );\n}\n\nconst EMPTY_FILES: FileMedia[] = [];\n\nexport type UseChannelOptions = ChannelProjectionOptions;\n\n/**\n * Raw-events escape hatch. Subscribes to one or more channels at a\n * namespace and returns a bounded buffer of raw protocol events.\n *\n * The buffer keeps accumulating across serial runs for the lifetime of\n * the thread, so this is the hook to use for an event log / stream of a\n * custom channel (e.g. `[\"custom:redaction-stats\"]`). When you only need\n * the latest payload of a single `custom:<name>` channel, prefer\n * {@link useExtension}. For the common message/tool/value cases prefer\n * {@link useMessages} / {@link useToolCalls} / {@link useValues}.\n */\nexport function useChannel(\n stream: AnyStream,\n channels: readonly Channel[],\n target?: SelectorTarget,\n options?: UseChannelOptions\n): Event[] {\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channel|${options?.bufferSize ?? \"default\"}|${(options?.replay ?? true) ? \"replay\" : \"live\"}|${channelKey}|${namespaceKey(namespace)}`;\n return useProjection<Event[]>(\n getRegistry(stream),\n () => channelProjection(channels, namespace, options),\n key,\n EMPTY_EVENTS\n );\n}\n\nconst EMPTY_EVENTS: Event[] = [];\n\n/**\n * Read metadata recorded for a specific message id — today exposes\n * `parentCheckpointId`, the checkpoint the message was first seen on.\n * Designed for fork / edit flows:\n *\n * ```tsx\n * const { parentCheckpointId } = useMessageMetadata(stream, msg.id) ?? {};\n * if (parentCheckpointId) {\n * await stream.submit(input, { forkFrom: parentCheckpointId });\n * }\n * ```\n *\n * Returns `undefined` when the id isn't known yet (e.g. the server\n * hasn't emitted `parent_checkpoint` for that message, or the message\n * arrived via `messages`-channel deltas only and no `values` snapshot\n * has landed for it yet).\n */\nexport function useMessageMetadata(\n stream: AnyStream,\n messageId: string | undefined\n): MessageMetadata | undefined {\n const store = stream[STREAM_CONTROLLER].messageMetadataStore;\n const snapshot = useSyncExternalStore<MessageMetadataMap>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return messageId == null ? undefined : snapshot.get(messageId);\n}\n\n/**\n * Reactive handle on the server-side submission queue.\n *\n * Populated when `submit()` is invoked with `multitaskStrategy:\n * \"enqueue\"` while another run is in flight. The returned object is\n * stable per snapshot so consumers can pass `entries` straight into a\n * `<Fragment key={e.id}>` list without extra memoisation.\n */\nexport interface UseSubmissionQueueReturn<\n StateType extends object = Record<string, unknown>,\n> {\n readonly entries: SubmissionQueueSnapshot<StateType>;\n readonly size: number;\n cancel(id: string): Promise<boolean>;\n clear(): Promise<void>;\n}\n\nexport function useSubmissionQueue<StateType extends object>(\n stream: StreamHandle<StateType>\n): UseSubmissionQueueReturn<StateType>;\nexport function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;\nexport function useSubmissionQueue(\n stream: AnyStream\n): UseSubmissionQueueReturn {\n const controller = stream[STREAM_CONTROLLER];\n const store = controller.queueStore;\n const entries = useSyncExternalStore<SubmissionQueueSnapshot>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return useMemo<UseSubmissionQueueReturn>(\n () => ({\n entries,\n size: entries.length,\n cancel: (id) => controller.cancelQueued(id),\n clear: () => controller.clearQueue(),\n }),\n [entries, controller]\n );\n}\n\nexport type { SubmissionQueueEntry, SubmissionQueueSnapshot };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"selectors.cjs","names":["STREAM_CONTROLLER","NAMESPACE_SEPARATOR","useProjection","getRegistry"],"sources":["../src/selectors.ts"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n MessageMetadata,\n MessageMetadataMap,\n SubmissionQueueEntry,\n SubmissionQueueSnapshot,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n NAMESPACE_SEPARATOR,\n acquireChannelEffect,\n audioProjection,\n channelProjection,\n extensionProjection,\n filesProjection,\n imagesProjection,\n messagesProjection,\n toolCallsProjection,\n valuesProjection,\n videoProjection,\n type AssembledToolCall,\n type AudioMedia,\n type Channel,\n type ChannelEffectOptions,\n type ChannelProjectionOptions,\n type Event,\n type FileMedia,\n type ImageMedia,\n type InferToolCalls,\n type InferStateType,\n type SubagentDiscoverySnapshot,\n type SubgraphDiscoverySnapshot,\n type VideoMedia,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n getRegistry,\n STREAM_CONTROLLER,\n type AnyStream,\n type UseStreamReturn,\n} from \"./use-stream.js\";\nimport { useProjection } from \"./use-projection.js\";\n\n/**\n * Selector hooks don't need to carry `InterruptType` /\n * `ConfigurableType` — they only ever read state. Accepting a\n * `StateType`-parameterised stream (with the other two generics\n * widened to `any`) lets callers keep their full\n * `useStream<State, Interrupt, Configurable>()` handle\n * without re-declaring the interrupt / configurable shapes at every\n * selector call site.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype StreamHandle<StateType extends object> = UseStreamReturn<\n StateType,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n>;\n\n/**\n * What a selector hook can be targeted at. Callers can pass any of:\n * - `undefined` — root namespace (cheap: served by the always-on root store)\n * - a {@link SubagentDiscoverySnapshot} — the snapshot returned by `stream.subagents.get(...)`\n * - a {@link SubgraphDiscoverySnapshot} — the snapshot returned by `stream.subgraphs.get(...)`\n * - an explicit `{ namespace: string[] }` — any other namespaced scope\n * - a raw `string[]` — escape hatch identical to the object form\n */\nexport type SelectorTarget =\n | undefined\n | null\n | readonly string[]\n | { namespace: readonly string[] }\n | SubagentDiscoverySnapshot\n | SubgraphDiscoverySnapshot;\n\nfunction resolveNamespace(target: SelectorTarget): readonly string[] {\n if (target == null) return EMPTY_NAMESPACE;\n if (Array.isArray(target)) return target;\n const obj = target as { namespace?: readonly string[] };\n return obj.namespace ?? EMPTY_NAMESPACE;\n}\n\n/**\n * If `target` is a subagent snapshot still on its default\n * `tools:<toolCallId>` namespace, return that tool-call id so the\n * caller can trigger lazy execution-namespace resolution. Returns\n * `null` for root targets, subgraph hosts, explicit namespaces, and\n * already-promoted subagents.\n */\nfunction subagentNeedingNamespace(target: SelectorTarget): string | null {\n if (target == null || Array.isArray(target)) return null;\n const obj = target as { id?: unknown; namespace?: readonly string[] };\n if (typeof obj.id !== \"string\" || !Array.isArray(obj.namespace)) return null;\n if (obj.namespace.length === 1 && obj.namespace[0] === `tools:${obj.id}`) {\n return obj.id;\n }\n return null;\n}\n\n/**\n * Lazily resolve a subagent's execution namespace on the first scoped\n * mount. Deep-agent subagents execute under a `tools:<uuid>` namespace\n * distinct from their `tools:<toolCallId>` discovery key; until that is\n * known a scoped `useMessages`/`useToolCalls` would target the wrong\n * scope. The controller de-dupes and skips already-promoted ids, so\n * this is safe to call from every consumer of the same subagent.\n */\nfunction useResolveSubagentNamespace(\n stream: AnyStream,\n target: SelectorTarget\n): void {\n const controller = stream[STREAM_CONTROLLER];\n const toolCallId = subagentNeedingNamespace(target);\n useEffect(() => {\n if (toolCallId == null) return;\n void controller.resolveSubagentNamespace(toolCallId);\n }, [controller, toolCallId]);\n}\n\nconst EMPTY_NAMESPACE: readonly string[] = [];\n\nfunction isRoot(namespace: readonly string[]): boolean {\n return namespace.length === 0;\n}\n\nfunction namespaceKey(namespace: readonly string[]): string {\n return namespace.join(NAMESPACE_SEPARATOR);\n}\n\n// The stream type we accept for selectors — the public {@link AnyStream}\n// erased handle. It overrides the generic-computed covariant members\n// (`toolCalls`, `values`, `~stateType`) with their widest forms so a\n// concrete `useStream<typeof agent>()` handle flows in without an\n// `as AnyStream` cast (a bare `UseStreamReturn<any, any, any>` does not\n// — see the `AnyStream` definition in `use-stream.ts`).\n//\n// Typed selectors (`useValues<S>` etc.) use {@link StreamHandle} above\n// so the concrete `StateType` flows into the return; hooks that don't\n// depend on state (`useMessages`, `useAudio`, …) stay on `AnyStream`\n// for maximum flexibility.\n\n/**\n * Subscribe to a scoped `messages` stream. Pass `stream` and\n * optionally a subagent/subgraph snapshot (or any namespaced target).\n *\n * Contract:\n * - At the root (no target) this returns `stream.messages` directly\n * — no extra subscription is opened. `stream.messages` is the\n * live merge of `messages`-channel token deltas and\n * `values.messages` snapshots (see\n * {@link UseStreamReturn.messages}), so token-by-token\n * streaming here depends on the backend emitting `messages`\n * channel events. Backends that only emit `values` updates will\n * render full turns at once rather than streaming.\n * - For any other namespace, the mount triggers a ref-counted\n * `messages` subscription scoped to that namespace. Unmounting\n * the last component that watches this namespace closes the\n * subscription automatically.\n *\n * Messages are always `BaseMessage` class instances from\n * `@langchain/core/messages`.\n */\nexport function useMessages(\n stream: AnyStream,\n target?: SelectorTarget\n): BaseMessage[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `messages|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<BaseMessage[]>(\n registry,\n () => messagesProjection(namespace),\n key,\n EMPTY_MESSAGES\n );\n return isRoot(namespace) ? stream.messages : scoped;\n}\n\nconst EMPTY_MESSAGES: BaseMessage[] = [];\n\n/**\n * Subscribe to a scoped `tools` (tool-call) stream. Same target and\n * lifecycle rules as {@link useMessages}; at the root this just returns\n * `stream.toolCalls`.\n *\n * The optional generic `T` can be passed to narrow the type of\n * assembled tool calls on the returned array. Accepts either:\n * - an agent brand (`typeof agent`) — union is derived from the\n * agent's declared tools via {@link InferToolCalls};\n * - an array of LangGraph tools (`typeof tools`) — union is derived\n * from {@link InferToolCalls} (parallel to {@link ToolCallsFromTools}).\n *\n * When omitted, returns the plain `AssembledToolCall[]` union used by\n * the controller.\n */\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[];\nexport function useToolCalls<T>(\n stream: AnyStream,\n target?: SelectorTarget\n): InferToolCalls<T>[];\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `toolCalls|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<AssembledToolCall[]>(\n registry,\n () => toolCallsProjection(namespace),\n key,\n EMPTY_TOOLCALLS\n );\n return isRoot(namespace) ? stream.toolCalls : scoped;\n}\n\nconst EMPTY_TOOLCALLS: AssembledToolCall[] = [];\n\n/**\n * Subscribe to a scoped `values` stream — most-recent state payload\n * for a namespace. Equivalent to reading `stream.values` at the root.\n *\n * When the payload carries a `messages` array, it is coerced to\n * `BaseMessage` instances to keep parity with the root projection.\n *\n * Typing:\n * - **Root** (`useValues(stream)`): returns the `StateType` declared\n * on the parent `useStream<State>()` — no explicit\n * generic required. Non-nullable because the root snapshot always\n * carries `values` (falling back to `initialValues ?? {}`).\n * - **Scoped** (`useValues(stream, target)`): the scoped payload can\n * have a different shape than the root state (e.g. a subagent\n * returning its own substate). Callers should annotate the\n * expected shape explicitly: `useValues<SubagentState>(stream, sub)`.\n * Defaults to `unknown` when not annotated.\n */\nexport function useValues<StateType extends object>(\n stream: StreamHandle<StateType>\n): StateType;\n/**\n * Explicit-generic override. Accepts:\n * - an agent brand or compiled graph (unwrapped via\n * {@link InferStateType});\n * - a plain state shape (returned as-is).\n *\n * The root-call form is non-nullable (the root snapshot is always\n * present); the scoped form returns `T | undefined` because a\n * projection may not have emitted a payload yet.\n */\nexport function useValues<T>(stream: AnyStream): InferStateType<T>;\nexport function useValues<T = unknown>(\n stream: AnyStream,\n target: SelectorTarget,\n options?: { messagesKey?: string }\n): T | undefined;\nexport function useValues(\n stream: AnyStream,\n target?: SelectorTarget,\n options?: { messagesKey?: string }\n): unknown {\n const namespace = resolveNamespace(target);\n const messagesKey = options?.messagesKey ?? \"messages\";\n const key = `values|${messagesKey}|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<unknown>(\n registry,\n () => valuesProjection<unknown>(namespace, messagesKey),\n key,\n undefined\n );\n return isRoot(namespace) ? stream.values : scoped;\n}\n\n/**\n * Subscribe to a `custom:<name>` stream extension — the most-recent\n * payload emitted by the transformer, scoped to the target namespace.\n *\n * Returns only the latest value and resumes across serial runs, so it is\n * ideal for \"current state\" panels (progress, score, status). When you\n * need the full history of events rather than just the latest payload,\n * use {@link useChannel} instead.\n */\nexport function useExtension<T = unknown>(\n stream: AnyStream,\n name: string,\n target?: SelectorTarget\n): T | undefined {\n const namespace = resolveNamespace(target);\n const key = `extension|${name}|${namespaceKey(namespace)}`;\n return useProjection<T | undefined>(\n getRegistry(stream),\n () => extensionProjection<T>(name, namespace),\n key,\n undefined\n );\n}\n\n/**\n * Subscribe to a scoped audio-media stream. Returns an array of\n * {@link AudioMedia} handles, one per message containing at least one\n * `AudioBlock` in the target namespace.\n *\n * Each handle is yielded on its first matching `content-block-start`,\n * exposes `.partialBytes` for live access, settles `.blob` /\n * `.objectURL` / `.transcript` on `message-finish`, and surfaces\n * fail-loud errors via `.error`.\n *\n * Pair with {@link useMediaURL} to turn a handle into an `<audio src>`.\n */\nexport function useAudio(\n stream: AnyStream,\n target?: SelectorTarget\n): AudioMedia[] {\n const namespace = resolveNamespace(target);\n const key = `audio|${namespaceKey(namespace)}`;\n return useProjection<AudioMedia[]>(\n getRegistry(stream),\n () => audioProjection(namespace),\n key,\n EMPTY_AUDIO\n );\n}\n\nconst EMPTY_AUDIO: AudioMedia[] = [];\n\n/**\n * Subscribe to a scoped image-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<img src>`.\n */\nexport function useImages(\n stream: AnyStream,\n target?: SelectorTarget\n): ImageMedia[] {\n const namespace = resolveNamespace(target);\n const key = `images|${namespaceKey(namespace)}`;\n return useProjection<ImageMedia[]>(\n getRegistry(stream),\n () => imagesProjection(namespace),\n key,\n EMPTY_IMAGES\n );\n}\n\nconst EMPTY_IMAGES: ImageMedia[] = [];\n\n/**\n * Subscribe to a scoped video-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<video src>`.\n */\nexport function useVideo(\n stream: AnyStream,\n target?: SelectorTarget\n): VideoMedia[] {\n const namespace = resolveNamespace(target);\n const key = `video|${namespaceKey(namespace)}`;\n return useProjection<VideoMedia[]>(\n getRegistry(stream),\n () => videoProjection(namespace),\n key,\n EMPTY_VIDEO\n );\n}\n\nconst EMPTY_VIDEO: VideoMedia[] = [];\n\n/**\n * Subscribe to a scoped file-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for an\n * `<a download href>` target.\n */\nexport function useFiles(\n stream: AnyStream,\n target?: SelectorTarget\n): FileMedia[] {\n const namespace = resolveNamespace(target);\n const key = `files|${namespaceKey(namespace)}`;\n return useProjection<FileMedia[]>(\n getRegistry(stream),\n () => filesProjection(namespace),\n key,\n EMPTY_FILES\n );\n}\n\nconst EMPTY_FILES: FileMedia[] = [];\n\nexport type UseChannelOptions = ChannelProjectionOptions;\n\n/**\n * Raw-events escape hatch. Subscribes to one or more channels at a\n * namespace and returns a bounded buffer of raw protocol events.\n *\n * The buffer keeps accumulating across serial runs for the lifetime of\n * the thread, so this is the hook to use for an event log / stream of a\n * custom channel (e.g. `[\"custom:redaction-stats\"]`). When you only need\n * the latest payload of a single `custom:<name>` channel, prefer\n * {@link useExtension}. For the common message/tool/value cases prefer\n * {@link useMessages} / {@link useToolCalls} / {@link useValues}.\n */\nexport function useChannel(\n stream: AnyStream,\n channels: readonly Channel[],\n target?: SelectorTarget,\n options?: UseChannelOptions\n): Event[] {\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channel|${options?.bufferSize ?? \"default\"}|${(options?.replay ?? true) ? \"replay\" : \"live\"}|${channelKey}|${namespaceKey(namespace)}`;\n return useProjection<Event[]>(\n getRegistry(stream),\n () => channelProjection(channels, namespace, options),\n key,\n EMPTY_EVENTS\n );\n}\n\nconst EMPTY_EVENTS: Event[] = [];\n\n/**\n * Options for {@link useChannelEffect}. Extends the projection options\n * (`bufferSize`, `replay`) with the per-event callback, an optional\n * error sink, a `target` scope, and an `enabled` gate.\n */\nexport interface UseChannelEffectOptions extends ChannelEffectOptions {\n /**\n * Scope events to a subagent / subgraph / explicit namespace.\n * Defaults to the root namespace.\n */\n target?: SelectorTarget;\n /**\n * Gate the subscription. When `false`, no subscription is opened and\n * no events are delivered. Defaults to `true`. Flipping this lets you\n * pause analytics (e.g. while the user is viewing a different thread)\n * without unmounting.\n */\n enabled?: boolean;\n}\n\n/**\n * Side-effect counterpart to {@link useChannel}. Instead of returning a\n * buffer of events that re-renders the component, it invokes `onEvent`\n * once per event for as long as the hook is mounted — the idiomatic\n * place for analytics, logging, and other fire-and-forget side effects.\n *\n * ```tsx\n * useChannelEffect(stream, [\"lifecycle\", \"tools\"], {\n * replay: false,\n * onEvent(event) {\n * sendAnalytics(event);\n * },\n * onError(error) {\n * logger.error(error);\n * },\n * });\n * ```\n *\n * Notes:\n * - `onEvent` / `onError` are read from a ref, so passing a fresh\n * closure each render is fine — it never re-subscribes.\n * - The underlying subscription is shared (ref-counted) with any\n * matching {@link useChannel} consumer, so you only ever pay for one\n * server subscription per channel set.\n * - `replay` defaults to `false` (live-only). Set it to `true` only if\n * you genuinely want to (re)process replayed history.\n * - Events buffered before the hook mounts are not re-delivered.\n */\nexport function useChannelEffect(\n stream: AnyStream,\n channels: readonly Channel[],\n options: UseChannelEffectOptions\n): void {\n const {\n target,\n enabled = true,\n replay,\n bufferSize,\n onEvent,\n onError,\n } = options;\n\n // Keep the latest callbacks in refs so re-renders that pass new inline\n // closures never tear down and re-open the subscription.\n const onEventRef = useRef(onEvent);\n const onErrorRef = useRef(onError);\n onEventRef.current = onEvent;\n onErrorRef.current = onError;\n\n useResolveSubagentNamespace(stream, target);\n\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channelEffect|${bufferSize ?? \"default\"}|${\n (replay ?? false) ? \"replay\" : \"live\"\n }|${channelKey}|${namespaceKey(namespace)}`;\n\n const registry = getRegistry(stream);\n\n useEffect(() => {\n if (!enabled || registry == null) return undefined;\n return acquireChannelEffect(registry, channels, namespace, {\n replay,\n bufferSize,\n onEvent: (event) => onEventRef.current(event),\n onError: (error) => onErrorRef.current?.(error),\n });\n // `channels` / `namespace` / `replay` / `bufferSize` are folded into\n // `key`; callbacks live in refs. Re-subscribe only when the resolved\n // scope or `enabled` changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [registry, key, enabled]);\n}\n\n/**\n * Read metadata recorded for a specific message id — today exposes\n * `parentCheckpointId`, the checkpoint the message was first seen on.\n * Designed for fork / edit flows:\n *\n * ```tsx\n * const { parentCheckpointId } = useMessageMetadata(stream, msg.id) ?? {};\n * if (parentCheckpointId) {\n * await stream.submit(input, { forkFrom: parentCheckpointId });\n * }\n * ```\n *\n * Returns `undefined` when the id isn't known yet (e.g. the server\n * hasn't emitted `parent_checkpoint` for that message, or the message\n * arrived via `messages`-channel deltas only and no `values` snapshot\n * has landed for it yet).\n */\nexport function useMessageMetadata(\n stream: AnyStream,\n messageId: string | undefined\n): MessageMetadata | undefined {\n const store = stream[STREAM_CONTROLLER].messageMetadataStore;\n const snapshot = useSyncExternalStore<MessageMetadataMap>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return messageId == null ? undefined : snapshot.get(messageId);\n}\n\n/**\n * Reactive handle on the server-side submission queue.\n *\n * Populated when `submit()` is invoked with `multitaskStrategy:\n * \"enqueue\"` while another run is in flight. The returned object is\n * stable per snapshot so consumers can pass `entries` straight into a\n * `<Fragment key={e.id}>` list without extra memoisation.\n */\nexport interface UseSubmissionQueueReturn<\n StateType extends object = Record<string, unknown>,\n> {\n readonly entries: SubmissionQueueSnapshot<StateType>;\n readonly size: number;\n cancel(id: string): Promise<boolean>;\n clear(): Promise<void>;\n}\n\nexport function useSubmissionQueue<StateType extends object>(\n stream: StreamHandle<StateType>\n): UseSubmissionQueueReturn<StateType>;\nexport function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;\nexport function useSubmissionQueue(\n stream: AnyStream\n): UseSubmissionQueueReturn {\n const controller = stream[STREAM_CONTROLLER];\n const store = controller.queueStore;\n const entries = useSyncExternalStore<SubmissionQueueSnapshot>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return useMemo<UseSubmissionQueueReturn>(\n () => ({\n entries,\n size: entries.length,\n cancel: (id) => controller.cancelQueued(id),\n clear: () => controller.clearQueue(),\n }),\n [entries, controller]\n );\n}\n\nexport type { SubmissionQueueEntry, SubmissionQueueSnapshot };\n"],"mappings":"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"}
|
package/dist/selectors.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyStream, UseStreamReturn } from "./use-stream.cjs";
|
|
2
2
|
import { BaseMessage } from "@langchain/core/messages";
|
|
3
|
-
import { AssembledToolCall, AudioMedia, Channel, ChannelProjectionOptions, Event, FileMedia, ImageMedia, InferStateType, InferToolCalls, MessageMetadata, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, SubmissionQueueEntry, SubmissionQueueSnapshot, VideoMedia } from "@langchain/langgraph-sdk/stream";
|
|
3
|
+
import { AssembledToolCall, AudioMedia, Channel, ChannelEffectOptions, ChannelProjectionOptions, Event, FileMedia, ImageMedia, InferStateType, InferToolCalls, MessageMetadata, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, SubmissionQueueEntry, SubmissionQueueSnapshot, VideoMedia } from "@langchain/langgraph-sdk/stream";
|
|
4
4
|
|
|
5
5
|
//#region src/selectors.d.ts
|
|
6
6
|
/**
|
|
@@ -148,6 +148,54 @@ type UseChannelOptions = ChannelProjectionOptions;
|
|
|
148
148
|
* {@link useMessages} / {@link useToolCalls} / {@link useValues}.
|
|
149
149
|
*/
|
|
150
150
|
declare function useChannel(stream: AnyStream, channels: readonly Channel[], target?: SelectorTarget, options?: UseChannelOptions): Event[];
|
|
151
|
+
/**
|
|
152
|
+
* Options for {@link useChannelEffect}. Extends the projection options
|
|
153
|
+
* (`bufferSize`, `replay`) with the per-event callback, an optional
|
|
154
|
+
* error sink, a `target` scope, and an `enabled` gate.
|
|
155
|
+
*/
|
|
156
|
+
interface UseChannelEffectOptions extends ChannelEffectOptions {
|
|
157
|
+
/**
|
|
158
|
+
* Scope events to a subagent / subgraph / explicit namespace.
|
|
159
|
+
* Defaults to the root namespace.
|
|
160
|
+
*/
|
|
161
|
+
target?: SelectorTarget;
|
|
162
|
+
/**
|
|
163
|
+
* Gate the subscription. When `false`, no subscription is opened and
|
|
164
|
+
* no events are delivered. Defaults to `true`. Flipping this lets you
|
|
165
|
+
* pause analytics (e.g. while the user is viewing a different thread)
|
|
166
|
+
* without unmounting.
|
|
167
|
+
*/
|
|
168
|
+
enabled?: boolean;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Side-effect counterpart to {@link useChannel}. Instead of returning a
|
|
172
|
+
* buffer of events that re-renders the component, it invokes `onEvent`
|
|
173
|
+
* once per event for as long as the hook is mounted — the idiomatic
|
|
174
|
+
* place for analytics, logging, and other fire-and-forget side effects.
|
|
175
|
+
*
|
|
176
|
+
* ```tsx
|
|
177
|
+
* useChannelEffect(stream, ["lifecycle", "tools"], {
|
|
178
|
+
* replay: false,
|
|
179
|
+
* onEvent(event) {
|
|
180
|
+
* sendAnalytics(event);
|
|
181
|
+
* },
|
|
182
|
+
* onError(error) {
|
|
183
|
+
* logger.error(error);
|
|
184
|
+
* },
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* Notes:
|
|
189
|
+
* - `onEvent` / `onError` are read from a ref, so passing a fresh
|
|
190
|
+
* closure each render is fine — it never re-subscribes.
|
|
191
|
+
* - The underlying subscription is shared (ref-counted) with any
|
|
192
|
+
* matching {@link useChannel} consumer, so you only ever pay for one
|
|
193
|
+
* server subscription per channel set.
|
|
194
|
+
* - `replay` defaults to `false` (live-only). Set it to `true` only if
|
|
195
|
+
* you genuinely want to (re)process replayed history.
|
|
196
|
+
* - Events buffered before the hook mounts are not re-delivered.
|
|
197
|
+
*/
|
|
198
|
+
declare function useChannelEffect(stream: AnyStream, channels: readonly Channel[], options: UseChannelEffectOptions): void;
|
|
151
199
|
/**
|
|
152
200
|
* Read metadata recorded for a specific message id — today exposes
|
|
153
201
|
* `parentCheckpointId`, the checkpoint the message was first seen on.
|
|
@@ -183,5 +231,5 @@ interface UseSubmissionQueueReturn<StateType extends object = Record<string, unk
|
|
|
183
231
|
declare function useSubmissionQueue<StateType extends object>(stream: StreamHandle<StateType>): UseSubmissionQueueReturn<StateType>;
|
|
184
232
|
declare function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;
|
|
185
233
|
//#endregion
|
|
186
|
-
export { SelectorTarget, type SubmissionQueueEntry, type SubmissionQueueSnapshot, UseSubmissionQueueReturn, useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
234
|
+
export { SelectorTarget, type SubmissionQueueEntry, type SubmissionQueueSnapshot, UseChannelEffectOptions, UseSubmissionQueueReturn, useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
187
235
|
//# sourceMappingURL=selectors.d.cts.map
|
package/dist/selectors.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.d.cts","names":[],"sources":["../src/selectors.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"selectors.d.cts","names":[],"sources":["../src/selectors.ts"],"mappings":";;;;;;AA2CyB;;;;;;;;KAapB,YAAA,6BAAyC,eAAA,CAC5C,SAAA;AAeF;;;;;;;;AAAA,KAAY,cAAA;EAIN,SAAA;AAAA,IACF,yBAAA,GACA,yBAAA;;;;;;;;;;;;;;AA2HJ;;;;;;;;iBAlCgB,WAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,WAAA;;;;;;;AAmCH;;;;;;;;;iBAJgB,YAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,iBAAA;AAAA,iBACa,YAAA,GAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,cAAA,CAAe,CAAA;;;;;;;;AAsClB;;;;;;;;;;;iBAAgB,SAAA,0BAAA,CACd,MAAA,EAAQ,YAAA,CAAa,SAAA,IACpB,SAAA;;;;AAWH;;;;;;;iBAAgB,SAAA,GAAA,CAAa,MAAA,EAAQ,SAAA,GAAY,cAAA,CAAe,CAAA;AAAA,iBAChD,SAAA,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,EAAQ,cAAA,EACR,OAAA;EAAY,WAAA;AAAA,IACX,CAAA;;;;;AAJH;;;;;iBAgCgB,YAAA,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,IAAA,UACA,MAAA,GAAS,cAAA,GACR,CAAA;;;;;;;;;;;;;iBAuBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;iBAiBa,SAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;iBAiBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;;iBAkBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,SAAA;AAAA,KAaS,iBAAA,GAAoB,wBAAA;;;;;;;;;;;;iBAahB,UAAA,CACd,MAAA,EAAQ,SAAA,EACR,QAAA,WAAmB,OAAA,IACnB,MAAA,GAAS,cAAA,EACT,OAAA,GAAU,iBAAA,GACT,KAAA;;;AA3EH;;;UA8FiB,uBAAA,SAAgC,oBAAA;EA5FtC;;;;EAiGT,MAAA,GAAS,cAAA;EAlGT;;;;;;EAyGA,OAAA;AAAA;;;;;;;;;;;;;;AAjEF;;;;;;;;;;;;;;;iBAgGgB,gBAAA,CACd,MAAA,EAAQ,SAAA,EACR,QAAA,WAAmB,OAAA,IACnB,OAAA,EAAS,uBAAA;;;;;AAtEX;;;;;;;;;;;;;iBAkIgB,kBAAA,CACd,MAAA,EAAQ,SAAA,EACR,SAAA,uBACC,eAAA;;;;;;;;AA7GH;UA+HiB,wBAAA,4BACY,MAAA;EAAA,SAElB,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAAA,SACjC,IAAA;EACT,MAAA,CAAO,EAAA,WAAa,OAAA;EACpB,KAAA,IAAS,OAAA;AAAA;AAAA,iBAGK,kBAAA,0BAAA,CACd,MAAA,EAAQ,YAAA,CAAa,SAAA,IACpB,wBAAA,CAAyB,SAAA;AAAA,iBACZ,kBAAA,CAAmB,MAAA,EAAQ,SAAA,GAAY,wBAAA"}
|
package/dist/selectors.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyStream, UseStreamReturn } from "./use-stream.js";
|
|
2
|
-
import { AssembledToolCall, AudioMedia, Channel, ChannelProjectionOptions, Event, FileMedia, ImageMedia, InferStateType, InferToolCalls, MessageMetadata, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, SubmissionQueueEntry, SubmissionQueueSnapshot, VideoMedia } from "@langchain/langgraph-sdk/stream";
|
|
2
|
+
import { AssembledToolCall, AudioMedia, Channel, ChannelEffectOptions, ChannelProjectionOptions, Event, FileMedia, ImageMedia, InferStateType, InferToolCalls, MessageMetadata, SubagentDiscoverySnapshot, SubgraphDiscoverySnapshot, SubmissionQueueEntry, SubmissionQueueSnapshot, VideoMedia } from "@langchain/langgraph-sdk/stream";
|
|
3
3
|
import { BaseMessage } from "@langchain/core/messages";
|
|
4
4
|
|
|
5
5
|
//#region src/selectors.d.ts
|
|
@@ -148,6 +148,54 @@ type UseChannelOptions = ChannelProjectionOptions;
|
|
|
148
148
|
* {@link useMessages} / {@link useToolCalls} / {@link useValues}.
|
|
149
149
|
*/
|
|
150
150
|
declare function useChannel(stream: AnyStream, channels: readonly Channel[], target?: SelectorTarget, options?: UseChannelOptions): Event[];
|
|
151
|
+
/**
|
|
152
|
+
* Options for {@link useChannelEffect}. Extends the projection options
|
|
153
|
+
* (`bufferSize`, `replay`) with the per-event callback, an optional
|
|
154
|
+
* error sink, a `target` scope, and an `enabled` gate.
|
|
155
|
+
*/
|
|
156
|
+
interface UseChannelEffectOptions extends ChannelEffectOptions {
|
|
157
|
+
/**
|
|
158
|
+
* Scope events to a subagent / subgraph / explicit namespace.
|
|
159
|
+
* Defaults to the root namespace.
|
|
160
|
+
*/
|
|
161
|
+
target?: SelectorTarget;
|
|
162
|
+
/**
|
|
163
|
+
* Gate the subscription. When `false`, no subscription is opened and
|
|
164
|
+
* no events are delivered. Defaults to `true`. Flipping this lets you
|
|
165
|
+
* pause analytics (e.g. while the user is viewing a different thread)
|
|
166
|
+
* without unmounting.
|
|
167
|
+
*/
|
|
168
|
+
enabled?: boolean;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Side-effect counterpart to {@link useChannel}. Instead of returning a
|
|
172
|
+
* buffer of events that re-renders the component, it invokes `onEvent`
|
|
173
|
+
* once per event for as long as the hook is mounted — the idiomatic
|
|
174
|
+
* place for analytics, logging, and other fire-and-forget side effects.
|
|
175
|
+
*
|
|
176
|
+
* ```tsx
|
|
177
|
+
* useChannelEffect(stream, ["lifecycle", "tools"], {
|
|
178
|
+
* replay: false,
|
|
179
|
+
* onEvent(event) {
|
|
180
|
+
* sendAnalytics(event);
|
|
181
|
+
* },
|
|
182
|
+
* onError(error) {
|
|
183
|
+
* logger.error(error);
|
|
184
|
+
* },
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* Notes:
|
|
189
|
+
* - `onEvent` / `onError` are read from a ref, so passing a fresh
|
|
190
|
+
* closure each render is fine — it never re-subscribes.
|
|
191
|
+
* - The underlying subscription is shared (ref-counted) with any
|
|
192
|
+
* matching {@link useChannel} consumer, so you only ever pay for one
|
|
193
|
+
* server subscription per channel set.
|
|
194
|
+
* - `replay` defaults to `false` (live-only). Set it to `true` only if
|
|
195
|
+
* you genuinely want to (re)process replayed history.
|
|
196
|
+
* - Events buffered before the hook mounts are not re-delivered.
|
|
197
|
+
*/
|
|
198
|
+
declare function useChannelEffect(stream: AnyStream, channels: readonly Channel[], options: UseChannelEffectOptions): void;
|
|
151
199
|
/**
|
|
152
200
|
* Read metadata recorded for a specific message id — today exposes
|
|
153
201
|
* `parentCheckpointId`, the checkpoint the message was first seen on.
|
|
@@ -183,5 +231,5 @@ interface UseSubmissionQueueReturn<StateType extends object = Record<string, unk
|
|
|
183
231
|
declare function useSubmissionQueue<StateType extends object>(stream: StreamHandle<StateType>): UseSubmissionQueueReturn<StateType>;
|
|
184
232
|
declare function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;
|
|
185
233
|
//#endregion
|
|
186
|
-
export { SelectorTarget, type SubmissionQueueEntry, type SubmissionQueueSnapshot, UseSubmissionQueueReturn, useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
234
|
+
export { SelectorTarget, type SubmissionQueueEntry, type SubmissionQueueSnapshot, UseChannelEffectOptions, UseSubmissionQueueReturn, useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
187
235
|
//# sourceMappingURL=selectors.d.ts.map
|
package/dist/selectors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.d.ts","names":[],"sources":["../src/selectors.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"selectors.d.ts","names":[],"sources":["../src/selectors.ts"],"mappings":";;;;;;AA2CyB;;;;;;;;KAapB,YAAA,6BAAyC,eAAA,CAC5C,SAAA;AAeF;;;;;;;;AAAA,KAAY,cAAA;EAIN,SAAA;AAAA,IACF,yBAAA,GACA,yBAAA;;;;;;;;;;;;;;AA2HJ;;;;;;;;iBAlCgB,WAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,WAAA;;;;;;;AAmCH;;;;;;;;;iBAJgB,YAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,iBAAA;AAAA,iBACa,YAAA,GAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,cAAA,CAAe,CAAA;;;;;;;;AAsClB;;;;;;;;;;;iBAAgB,SAAA,0BAAA,CACd,MAAA,EAAQ,YAAA,CAAa,SAAA,IACpB,SAAA;;;;AAWH;;;;;;;iBAAgB,SAAA,GAAA,CAAa,MAAA,EAAQ,SAAA,GAAY,cAAA,CAAe,CAAA;AAAA,iBAChD,SAAA,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,EAAQ,cAAA,EACR,OAAA;EAAY,WAAA;AAAA,IACX,CAAA;;;;;AAJH;;;;;iBAgCgB,YAAA,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,IAAA,UACA,MAAA,GAAS,cAAA,GACR,CAAA;;;;;;;;;;;;;iBAuBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;iBAiBa,SAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;iBAiBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,UAAA;;;;;;iBAkBa,QAAA,CACd,MAAA,EAAQ,SAAA,EACR,MAAA,GAAS,cAAA,GACR,SAAA;AAAA,KAaS,iBAAA,GAAoB,wBAAA;;;;;;;;;;;;iBAahB,UAAA,CACd,MAAA,EAAQ,SAAA,EACR,QAAA,WAAmB,OAAA,IACnB,MAAA,GAAS,cAAA,EACT,OAAA,GAAU,iBAAA,GACT,KAAA;;;AA3EH;;;UA8FiB,uBAAA,SAAgC,oBAAA;EA5FtC;;;;EAiGT,MAAA,GAAS,cAAA;EAlGT;;;;;;EAyGA,OAAA;AAAA;;;;;;;;;;;;;;AAjEF;;;;;;;;;;;;;;;iBAgGgB,gBAAA,CACd,MAAA,EAAQ,SAAA,EACR,QAAA,WAAmB,OAAA,IACnB,OAAA,EAAS,uBAAA;;;;;AAtEX;;;;;;;;;;;;;iBAkIgB,kBAAA,CACd,MAAA,EAAQ,SAAA,EACR,SAAA,uBACC,eAAA;;;;;;;;AA7GH;UA+HiB,wBAAA,4BACY,MAAA;EAAA,SAElB,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAAA,SACjC,IAAA;EACT,MAAA,CAAO,EAAA,WAAa,OAAA;EACpB,KAAA,IAAS,OAAA;AAAA;AAAA,iBAGK,kBAAA,0BAAA,CACd,MAAA,EAAQ,YAAA,CAAa,SAAA,IACpB,wBAAA,CAAyB,SAAA;AAAA,iBACZ,kBAAA,CAAmB,MAAA,EAAQ,SAAA,GAAY,wBAAA"}
|
package/dist/selectors.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { STREAM_CONTROLLER, getRegistry } from "./use-stream.js";
|
|
3
3
|
import { useProjection } from "./use-projection.js";
|
|
4
|
-
import { useEffect, useMemo, useSyncExternalStore } from "react";
|
|
5
|
-
import { NAMESPACE_SEPARATOR, audioProjection, channelProjection, extensionProjection, filesProjection, imagesProjection, messagesProjection, toolCallsProjection, valuesProjection, videoProjection } from "@langchain/langgraph-sdk/stream";
|
|
4
|
+
import { useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
5
|
+
import { NAMESPACE_SEPARATOR, acquireChannelEffect, audioProjection, channelProjection, extensionProjection, filesProjection, imagesProjection, messagesProjection, toolCallsProjection, valuesProjection, videoProjection } from "@langchain/langgraph-sdk/stream";
|
|
6
6
|
//#region src/selectors.ts
|
|
7
7
|
function resolveNamespace(target) {
|
|
8
8
|
if (target == null) return EMPTY_NAMESPACE;
|
|
@@ -172,6 +172,59 @@ function useChannel(stream, channels, target, options) {
|
|
|
172
172
|
}
|
|
173
173
|
const EMPTY_EVENTS = [];
|
|
174
174
|
/**
|
|
175
|
+
* Side-effect counterpart to {@link useChannel}. Instead of returning a
|
|
176
|
+
* buffer of events that re-renders the component, it invokes `onEvent`
|
|
177
|
+
* once per event for as long as the hook is mounted — the idiomatic
|
|
178
|
+
* place for analytics, logging, and other fire-and-forget side effects.
|
|
179
|
+
*
|
|
180
|
+
* ```tsx
|
|
181
|
+
* useChannelEffect(stream, ["lifecycle", "tools"], {
|
|
182
|
+
* replay: false,
|
|
183
|
+
* onEvent(event) {
|
|
184
|
+
* sendAnalytics(event);
|
|
185
|
+
* },
|
|
186
|
+
* onError(error) {
|
|
187
|
+
* logger.error(error);
|
|
188
|
+
* },
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* Notes:
|
|
193
|
+
* - `onEvent` / `onError` are read from a ref, so passing a fresh
|
|
194
|
+
* closure each render is fine — it never re-subscribes.
|
|
195
|
+
* - The underlying subscription is shared (ref-counted) with any
|
|
196
|
+
* matching {@link useChannel} consumer, so you only ever pay for one
|
|
197
|
+
* server subscription per channel set.
|
|
198
|
+
* - `replay` defaults to `false` (live-only). Set it to `true` only if
|
|
199
|
+
* you genuinely want to (re)process replayed history.
|
|
200
|
+
* - Events buffered before the hook mounts are not re-delivered.
|
|
201
|
+
*/
|
|
202
|
+
function useChannelEffect(stream, channels, options) {
|
|
203
|
+
const { target, enabled = true, replay, bufferSize, onEvent, onError } = options;
|
|
204
|
+
const onEventRef = useRef(onEvent);
|
|
205
|
+
const onErrorRef = useRef(onError);
|
|
206
|
+
onEventRef.current = onEvent;
|
|
207
|
+
onErrorRef.current = onError;
|
|
208
|
+
useResolveSubagentNamespace(stream, target);
|
|
209
|
+
const namespace = resolveNamespace(target);
|
|
210
|
+
const channelKey = useMemo(() => [...channels].sort().join(","), [channels]);
|
|
211
|
+
const key = `channelEffect|${bufferSize ?? "default"}|${replay ?? false ? "replay" : "live"}|${channelKey}|${namespaceKey(namespace)}`;
|
|
212
|
+
const registry = getRegistry(stream);
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (!enabled || registry == null) return void 0;
|
|
215
|
+
return acquireChannelEffect(registry, channels, namespace, {
|
|
216
|
+
replay,
|
|
217
|
+
bufferSize,
|
|
218
|
+
onEvent: (event) => onEventRef.current(event),
|
|
219
|
+
onError: (error) => onErrorRef.current?.(error)
|
|
220
|
+
});
|
|
221
|
+
}, [
|
|
222
|
+
registry,
|
|
223
|
+
key,
|
|
224
|
+
enabled
|
|
225
|
+
]);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
175
228
|
* Read metadata recorded for a specific message id — today exposes
|
|
176
229
|
* `parentCheckpointId`, the checkpoint the message was first seen on.
|
|
177
230
|
* Designed for fork / edit flows:
|
|
@@ -205,6 +258,6 @@ function useSubmissionQueue(stream) {
|
|
|
205
258
|
}), [entries, controller]);
|
|
206
259
|
}
|
|
207
260
|
//#endregion
|
|
208
|
-
export { useAudio, useChannel, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
261
|
+
export { useAudio, useChannel, useChannelEffect, useExtension, useFiles, useImages, useMessageMetadata, useMessages, useSubmissionQueue, useToolCalls, useValues, useVideo };
|
|
209
262
|
|
|
210
263
|
//# sourceMappingURL=selectors.js.map
|
package/dist/selectors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.js","names":[],"sources":["../src/selectors.ts"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useMemo, useSyncExternalStore } from \"react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n MessageMetadata,\n MessageMetadataMap,\n SubmissionQueueEntry,\n SubmissionQueueSnapshot,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n NAMESPACE_SEPARATOR,\n audioProjection,\n channelProjection,\n extensionProjection,\n filesProjection,\n imagesProjection,\n messagesProjection,\n toolCallsProjection,\n valuesProjection,\n videoProjection,\n type AssembledToolCall,\n type AudioMedia,\n type Channel,\n type ChannelProjectionOptions,\n type Event,\n type FileMedia,\n type ImageMedia,\n type InferToolCalls,\n type InferStateType,\n type SubagentDiscoverySnapshot,\n type SubgraphDiscoverySnapshot,\n type VideoMedia,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n getRegistry,\n STREAM_CONTROLLER,\n type AnyStream,\n type UseStreamReturn,\n} from \"./use-stream.js\";\nimport { useProjection } from \"./use-projection.js\";\n\n/**\n * Selector hooks don't need to carry `InterruptType` /\n * `ConfigurableType` — they only ever read state. Accepting a\n * `StateType`-parameterised stream (with the other two generics\n * widened to `any`) lets callers keep their full\n * `useStream<State, Interrupt, Configurable>()` handle\n * without re-declaring the interrupt / configurable shapes at every\n * selector call site.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype StreamHandle<StateType extends object> = UseStreamReturn<\n StateType,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n>;\n\n/**\n * What a selector hook can be targeted at. Callers can pass any of:\n * - `undefined` — root namespace (cheap: served by the always-on root store)\n * - a {@link SubagentDiscoverySnapshot} — the snapshot returned by `stream.subagents.get(...)`\n * - a {@link SubgraphDiscoverySnapshot} — the snapshot returned by `stream.subgraphs.get(...)`\n * - an explicit `{ namespace: string[] }` — any other namespaced scope\n * - a raw `string[]` — escape hatch identical to the object form\n */\nexport type SelectorTarget =\n | undefined\n | null\n | readonly string[]\n | { namespace: readonly string[] }\n | SubagentDiscoverySnapshot\n | SubgraphDiscoverySnapshot;\n\nfunction resolveNamespace(target: SelectorTarget): readonly string[] {\n if (target == null) return EMPTY_NAMESPACE;\n if (Array.isArray(target)) return target;\n const obj = target as { namespace?: readonly string[] };\n return obj.namespace ?? EMPTY_NAMESPACE;\n}\n\n/**\n * If `target` is a subagent snapshot still on its default\n * `tools:<toolCallId>` namespace, return that tool-call id so the\n * caller can trigger lazy execution-namespace resolution. Returns\n * `null` for root targets, subgraph hosts, explicit namespaces, and\n * already-promoted subagents.\n */\nfunction subagentNeedingNamespace(target: SelectorTarget): string | null {\n if (target == null || Array.isArray(target)) return null;\n const obj = target as { id?: unknown; namespace?: readonly string[] };\n if (typeof obj.id !== \"string\" || !Array.isArray(obj.namespace)) return null;\n if (obj.namespace.length === 1 && obj.namespace[0] === `tools:${obj.id}`) {\n return obj.id;\n }\n return null;\n}\n\n/**\n * Lazily resolve a subagent's execution namespace on the first scoped\n * mount. Deep-agent subagents execute under a `tools:<uuid>` namespace\n * distinct from their `tools:<toolCallId>` discovery key; until that is\n * known a scoped `useMessages`/`useToolCalls` would target the wrong\n * scope. The controller de-dupes and skips already-promoted ids, so\n * this is safe to call from every consumer of the same subagent.\n */\nfunction useResolveSubagentNamespace(\n stream: AnyStream,\n target: SelectorTarget\n): void {\n const controller = stream[STREAM_CONTROLLER];\n const toolCallId = subagentNeedingNamespace(target);\n useEffect(() => {\n if (toolCallId == null) return;\n void controller.resolveSubagentNamespace(toolCallId);\n }, [controller, toolCallId]);\n}\n\nconst EMPTY_NAMESPACE: readonly string[] = [];\n\nfunction isRoot(namespace: readonly string[]): boolean {\n return namespace.length === 0;\n}\n\nfunction namespaceKey(namespace: readonly string[]): string {\n return namespace.join(NAMESPACE_SEPARATOR);\n}\n\n// The stream type we accept for selectors — the public {@link AnyStream}\n// erased handle. It overrides the generic-computed covariant members\n// (`toolCalls`, `values`, `~stateType`) with their widest forms so a\n// concrete `useStream<typeof agent>()` handle flows in without an\n// `as AnyStream` cast (a bare `UseStreamReturn<any, any, any>` does not\n// — see the `AnyStream` definition in `use-stream.ts`).\n//\n// Typed selectors (`useValues<S>` etc.) use {@link StreamHandle} above\n// so the concrete `StateType` flows into the return; hooks that don't\n// depend on state (`useMessages`, `useAudio`, …) stay on `AnyStream`\n// for maximum flexibility.\n\n/**\n * Subscribe to a scoped `messages` stream. Pass `stream` and\n * optionally a subagent/subgraph snapshot (or any namespaced target).\n *\n * Contract:\n * - At the root (no target) this returns `stream.messages` directly\n * — no extra subscription is opened. `stream.messages` is the\n * live merge of `messages`-channel token deltas and\n * `values.messages` snapshots (see\n * {@link UseStreamReturn.messages}), so token-by-token\n * streaming here depends on the backend emitting `messages`\n * channel events. Backends that only emit `values` updates will\n * render full turns at once rather than streaming.\n * - For any other namespace, the mount triggers a ref-counted\n * `messages` subscription scoped to that namespace. Unmounting\n * the last component that watches this namespace closes the\n * subscription automatically.\n *\n * Messages are always `BaseMessage` class instances from\n * `@langchain/core/messages`.\n */\nexport function useMessages(\n stream: AnyStream,\n target?: SelectorTarget\n): BaseMessage[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `messages|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<BaseMessage[]>(\n registry,\n () => messagesProjection(namespace),\n key,\n EMPTY_MESSAGES\n );\n return isRoot(namespace) ? stream.messages : scoped;\n}\n\nconst EMPTY_MESSAGES: BaseMessage[] = [];\n\n/**\n * Subscribe to a scoped `tools` (tool-call) stream. Same target and\n * lifecycle rules as {@link useMessages}; at the root this just returns\n * `stream.toolCalls`.\n *\n * The optional generic `T` can be passed to narrow the type of\n * assembled tool calls on the returned array. Accepts either:\n * - an agent brand (`typeof agent`) — union is derived from the\n * agent's declared tools via {@link InferToolCalls};\n * - an array of LangGraph tools (`typeof tools`) — union is derived\n * from {@link InferToolCalls} (parallel to {@link ToolCallsFromTools}).\n *\n * When omitted, returns the plain `AssembledToolCall[]` union used by\n * the controller.\n */\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[];\nexport function useToolCalls<T>(\n stream: AnyStream,\n target?: SelectorTarget\n): InferToolCalls<T>[];\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `toolCalls|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<AssembledToolCall[]>(\n registry,\n () => toolCallsProjection(namespace),\n key,\n EMPTY_TOOLCALLS\n );\n return isRoot(namespace) ? stream.toolCalls : scoped;\n}\n\nconst EMPTY_TOOLCALLS: AssembledToolCall[] = [];\n\n/**\n * Subscribe to a scoped `values` stream — most-recent state payload\n * for a namespace. Equivalent to reading `stream.values` at the root.\n *\n * When the payload carries a `messages` array, it is coerced to\n * `BaseMessage` instances to keep parity with the root projection.\n *\n * Typing:\n * - **Root** (`useValues(stream)`): returns the `StateType` declared\n * on the parent `useStream<State>()` — no explicit\n * generic required. Non-nullable because the root snapshot always\n * carries `values` (falling back to `initialValues ?? {}`).\n * - **Scoped** (`useValues(stream, target)`): the scoped payload can\n * have a different shape than the root state (e.g. a subagent\n * returning its own substate). Callers should annotate the\n * expected shape explicitly: `useValues<SubagentState>(stream, sub)`.\n * Defaults to `unknown` when not annotated.\n */\nexport function useValues<StateType extends object>(\n stream: StreamHandle<StateType>\n): StateType;\n/**\n * Explicit-generic override. Accepts:\n * - an agent brand or compiled graph (unwrapped via\n * {@link InferStateType});\n * - a plain state shape (returned as-is).\n *\n * The root-call form is non-nullable (the root snapshot is always\n * present); the scoped form returns `T | undefined` because a\n * projection may not have emitted a payload yet.\n */\nexport function useValues<T>(stream: AnyStream): InferStateType<T>;\nexport function useValues<T = unknown>(\n stream: AnyStream,\n target: SelectorTarget,\n options?: { messagesKey?: string }\n): T | undefined;\nexport function useValues(\n stream: AnyStream,\n target?: SelectorTarget,\n options?: { messagesKey?: string }\n): unknown {\n const namespace = resolveNamespace(target);\n const messagesKey = options?.messagesKey ?? \"messages\";\n const key = `values|${messagesKey}|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<unknown>(\n registry,\n () => valuesProjection<unknown>(namespace, messagesKey),\n key,\n undefined\n );\n return isRoot(namespace) ? stream.values : scoped;\n}\n\n/**\n * Subscribe to a `custom:<name>` stream extension — the most-recent\n * payload emitted by the transformer, scoped to the target namespace.\n *\n * Returns only the latest value and resumes across serial runs, so it is\n * ideal for \"current state\" panels (progress, score, status). When you\n * need the full history of events rather than just the latest payload,\n * use {@link useChannel} instead.\n */\nexport function useExtension<T = unknown>(\n stream: AnyStream,\n name: string,\n target?: SelectorTarget\n): T | undefined {\n const namespace = resolveNamespace(target);\n const key = `extension|${name}|${namespaceKey(namespace)}`;\n return useProjection<T | undefined>(\n getRegistry(stream),\n () => extensionProjection<T>(name, namespace),\n key,\n undefined\n );\n}\n\n/**\n * Subscribe to a scoped audio-media stream. Returns an array of\n * {@link AudioMedia} handles, one per message containing at least one\n * `AudioBlock` in the target namespace.\n *\n * Each handle is yielded on its first matching `content-block-start`,\n * exposes `.partialBytes` for live access, settles `.blob` /\n * `.objectURL` / `.transcript` on `message-finish`, and surfaces\n * fail-loud errors via `.error`.\n *\n * Pair with {@link useMediaURL} to turn a handle into an `<audio src>`.\n */\nexport function useAudio(\n stream: AnyStream,\n target?: SelectorTarget\n): AudioMedia[] {\n const namespace = resolveNamespace(target);\n const key = `audio|${namespaceKey(namespace)}`;\n return useProjection<AudioMedia[]>(\n getRegistry(stream),\n () => audioProjection(namespace),\n key,\n EMPTY_AUDIO\n );\n}\n\nconst EMPTY_AUDIO: AudioMedia[] = [];\n\n/**\n * Subscribe to a scoped image-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<img src>`.\n */\nexport function useImages(\n stream: AnyStream,\n target?: SelectorTarget\n): ImageMedia[] {\n const namespace = resolveNamespace(target);\n const key = `images|${namespaceKey(namespace)}`;\n return useProjection<ImageMedia[]>(\n getRegistry(stream),\n () => imagesProjection(namespace),\n key,\n EMPTY_IMAGES\n );\n}\n\nconst EMPTY_IMAGES: ImageMedia[] = [];\n\n/**\n * Subscribe to a scoped video-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<video src>`.\n */\nexport function useVideo(\n stream: AnyStream,\n target?: SelectorTarget\n): VideoMedia[] {\n const namespace = resolveNamespace(target);\n const key = `video|${namespaceKey(namespace)}`;\n return useProjection<VideoMedia[]>(\n getRegistry(stream),\n () => videoProjection(namespace),\n key,\n EMPTY_VIDEO\n );\n}\n\nconst EMPTY_VIDEO: VideoMedia[] = [];\n\n/**\n * Subscribe to a scoped file-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for an\n * `<a download href>` target.\n */\nexport function useFiles(\n stream: AnyStream,\n target?: SelectorTarget\n): FileMedia[] {\n const namespace = resolveNamespace(target);\n const key = `files|${namespaceKey(namespace)}`;\n return useProjection<FileMedia[]>(\n getRegistry(stream),\n () => filesProjection(namespace),\n key,\n EMPTY_FILES\n );\n}\n\nconst EMPTY_FILES: FileMedia[] = [];\n\nexport type UseChannelOptions = ChannelProjectionOptions;\n\n/**\n * Raw-events escape hatch. Subscribes to one or more channels at a\n * namespace and returns a bounded buffer of raw protocol events.\n *\n * The buffer keeps accumulating across serial runs for the lifetime of\n * the thread, so this is the hook to use for an event log / stream of a\n * custom channel (e.g. `[\"custom:redaction-stats\"]`). When you only need\n * the latest payload of a single `custom:<name>` channel, prefer\n * {@link useExtension}. For the common message/tool/value cases prefer\n * {@link useMessages} / {@link useToolCalls} / {@link useValues}.\n */\nexport function useChannel(\n stream: AnyStream,\n channels: readonly Channel[],\n target?: SelectorTarget,\n options?: UseChannelOptions\n): Event[] {\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channel|${options?.bufferSize ?? \"default\"}|${(options?.replay ?? true) ? \"replay\" : \"live\"}|${channelKey}|${namespaceKey(namespace)}`;\n return useProjection<Event[]>(\n getRegistry(stream),\n () => channelProjection(channels, namespace, options),\n key,\n EMPTY_EVENTS\n );\n}\n\nconst EMPTY_EVENTS: Event[] = [];\n\n/**\n * Read metadata recorded for a specific message id — today exposes\n * `parentCheckpointId`, the checkpoint the message was first seen on.\n * Designed for fork / edit flows:\n *\n * ```tsx\n * const { parentCheckpointId } = useMessageMetadata(stream, msg.id) ?? {};\n * if (parentCheckpointId) {\n * await stream.submit(input, { forkFrom: parentCheckpointId });\n * }\n * ```\n *\n * Returns `undefined` when the id isn't known yet (e.g. the server\n * hasn't emitted `parent_checkpoint` for that message, or the message\n * arrived via `messages`-channel deltas only and no `values` snapshot\n * has landed for it yet).\n */\nexport function useMessageMetadata(\n stream: AnyStream,\n messageId: string | undefined\n): MessageMetadata | undefined {\n const store = stream[STREAM_CONTROLLER].messageMetadataStore;\n const snapshot = useSyncExternalStore<MessageMetadataMap>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return messageId == null ? undefined : snapshot.get(messageId);\n}\n\n/**\n * Reactive handle on the server-side submission queue.\n *\n * Populated when `submit()` is invoked with `multitaskStrategy:\n * \"enqueue\"` while another run is in flight. The returned object is\n * stable per snapshot so consumers can pass `entries` straight into a\n * `<Fragment key={e.id}>` list without extra memoisation.\n */\nexport interface UseSubmissionQueueReturn<\n StateType extends object = Record<string, unknown>,\n> {\n readonly entries: SubmissionQueueSnapshot<StateType>;\n readonly size: number;\n cancel(id: string): Promise<boolean>;\n clear(): Promise<void>;\n}\n\nexport function useSubmissionQueue<StateType extends object>(\n stream: StreamHandle<StateType>\n): UseSubmissionQueueReturn<StateType>;\nexport function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;\nexport function useSubmissionQueue(\n stream: AnyStream\n): UseSubmissionQueueReturn {\n const controller = stream[STREAM_CONTROLLER];\n const store = controller.queueStore;\n const entries = useSyncExternalStore<SubmissionQueueSnapshot>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return useMemo<UseSubmissionQueueReturn>(\n () => ({\n entries,\n size: entries.length,\n cancel: (id) => controller.cancelQueued(id),\n clear: () => controller.clearQueue(),\n }),\n [entries, controller]\n );\n}\n\nexport type { SubmissionQueueEntry, SubmissionQueueSnapshot };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"selectors.js","names":[],"sources":["../src/selectors.ts"],"sourcesContent":["/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */\n\n\"use client\";\n\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport type {\n MessageMetadata,\n MessageMetadataMap,\n SubmissionQueueEntry,\n SubmissionQueueSnapshot,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n NAMESPACE_SEPARATOR,\n acquireChannelEffect,\n audioProjection,\n channelProjection,\n extensionProjection,\n filesProjection,\n imagesProjection,\n messagesProjection,\n toolCallsProjection,\n valuesProjection,\n videoProjection,\n type AssembledToolCall,\n type AudioMedia,\n type Channel,\n type ChannelEffectOptions,\n type ChannelProjectionOptions,\n type Event,\n type FileMedia,\n type ImageMedia,\n type InferToolCalls,\n type InferStateType,\n type SubagentDiscoverySnapshot,\n type SubgraphDiscoverySnapshot,\n type VideoMedia,\n} from \"@langchain/langgraph-sdk/stream\";\nimport {\n getRegistry,\n STREAM_CONTROLLER,\n type AnyStream,\n type UseStreamReturn,\n} from \"./use-stream.js\";\nimport { useProjection } from \"./use-projection.js\";\n\n/**\n * Selector hooks don't need to carry `InterruptType` /\n * `ConfigurableType` — they only ever read state. Accepting a\n * `StateType`-parameterised stream (with the other two generics\n * widened to `any`) lets callers keep their full\n * `useStream<State, Interrupt, Configurable>()` handle\n * without re-declaring the interrupt / configurable shapes at every\n * selector call site.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype StreamHandle<StateType extends object> = UseStreamReturn<\n StateType,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n>;\n\n/**\n * What a selector hook can be targeted at. Callers can pass any of:\n * - `undefined` — root namespace (cheap: served by the always-on root store)\n * - a {@link SubagentDiscoverySnapshot} — the snapshot returned by `stream.subagents.get(...)`\n * - a {@link SubgraphDiscoverySnapshot} — the snapshot returned by `stream.subgraphs.get(...)`\n * - an explicit `{ namespace: string[] }` — any other namespaced scope\n * - a raw `string[]` — escape hatch identical to the object form\n */\nexport type SelectorTarget =\n | undefined\n | null\n | readonly string[]\n | { namespace: readonly string[] }\n | SubagentDiscoverySnapshot\n | SubgraphDiscoverySnapshot;\n\nfunction resolveNamespace(target: SelectorTarget): readonly string[] {\n if (target == null) return EMPTY_NAMESPACE;\n if (Array.isArray(target)) return target;\n const obj = target as { namespace?: readonly string[] };\n return obj.namespace ?? EMPTY_NAMESPACE;\n}\n\n/**\n * If `target` is a subagent snapshot still on its default\n * `tools:<toolCallId>` namespace, return that tool-call id so the\n * caller can trigger lazy execution-namespace resolution. Returns\n * `null` for root targets, subgraph hosts, explicit namespaces, and\n * already-promoted subagents.\n */\nfunction subagentNeedingNamespace(target: SelectorTarget): string | null {\n if (target == null || Array.isArray(target)) return null;\n const obj = target as { id?: unknown; namespace?: readonly string[] };\n if (typeof obj.id !== \"string\" || !Array.isArray(obj.namespace)) return null;\n if (obj.namespace.length === 1 && obj.namespace[0] === `tools:${obj.id}`) {\n return obj.id;\n }\n return null;\n}\n\n/**\n * Lazily resolve a subagent's execution namespace on the first scoped\n * mount. Deep-agent subagents execute under a `tools:<uuid>` namespace\n * distinct from their `tools:<toolCallId>` discovery key; until that is\n * known a scoped `useMessages`/`useToolCalls` would target the wrong\n * scope. The controller de-dupes and skips already-promoted ids, so\n * this is safe to call from every consumer of the same subagent.\n */\nfunction useResolveSubagentNamespace(\n stream: AnyStream,\n target: SelectorTarget\n): void {\n const controller = stream[STREAM_CONTROLLER];\n const toolCallId = subagentNeedingNamespace(target);\n useEffect(() => {\n if (toolCallId == null) return;\n void controller.resolveSubagentNamespace(toolCallId);\n }, [controller, toolCallId]);\n}\n\nconst EMPTY_NAMESPACE: readonly string[] = [];\n\nfunction isRoot(namespace: readonly string[]): boolean {\n return namespace.length === 0;\n}\n\nfunction namespaceKey(namespace: readonly string[]): string {\n return namespace.join(NAMESPACE_SEPARATOR);\n}\n\n// The stream type we accept for selectors — the public {@link AnyStream}\n// erased handle. It overrides the generic-computed covariant members\n// (`toolCalls`, `values`, `~stateType`) with their widest forms so a\n// concrete `useStream<typeof agent>()` handle flows in without an\n// `as AnyStream` cast (a bare `UseStreamReturn<any, any, any>` does not\n// — see the `AnyStream` definition in `use-stream.ts`).\n//\n// Typed selectors (`useValues<S>` etc.) use {@link StreamHandle} above\n// so the concrete `StateType` flows into the return; hooks that don't\n// depend on state (`useMessages`, `useAudio`, …) stay on `AnyStream`\n// for maximum flexibility.\n\n/**\n * Subscribe to a scoped `messages` stream. Pass `stream` and\n * optionally a subagent/subgraph snapshot (or any namespaced target).\n *\n * Contract:\n * - At the root (no target) this returns `stream.messages` directly\n * — no extra subscription is opened. `stream.messages` is the\n * live merge of `messages`-channel token deltas and\n * `values.messages` snapshots (see\n * {@link UseStreamReturn.messages}), so token-by-token\n * streaming here depends on the backend emitting `messages`\n * channel events. Backends that only emit `values` updates will\n * render full turns at once rather than streaming.\n * - For any other namespace, the mount triggers a ref-counted\n * `messages` subscription scoped to that namespace. Unmounting\n * the last component that watches this namespace closes the\n * subscription automatically.\n *\n * Messages are always `BaseMessage` class instances from\n * `@langchain/core/messages`.\n */\nexport function useMessages(\n stream: AnyStream,\n target?: SelectorTarget\n): BaseMessage[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `messages|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<BaseMessage[]>(\n registry,\n () => messagesProjection(namespace),\n key,\n EMPTY_MESSAGES\n );\n return isRoot(namespace) ? stream.messages : scoped;\n}\n\nconst EMPTY_MESSAGES: BaseMessage[] = [];\n\n/**\n * Subscribe to a scoped `tools` (tool-call) stream. Same target and\n * lifecycle rules as {@link useMessages}; at the root this just returns\n * `stream.toolCalls`.\n *\n * The optional generic `T` can be passed to narrow the type of\n * assembled tool calls on the returned array. Accepts either:\n * - an agent brand (`typeof agent`) — union is derived from the\n * agent's declared tools via {@link InferToolCalls};\n * - an array of LangGraph tools (`typeof tools`) — union is derived\n * from {@link InferToolCalls} (parallel to {@link ToolCallsFromTools}).\n *\n * When omitted, returns the plain `AssembledToolCall[]` union used by\n * the controller.\n */\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[];\nexport function useToolCalls<T>(\n stream: AnyStream,\n target?: SelectorTarget\n): InferToolCalls<T>[];\nexport function useToolCalls(\n stream: AnyStream,\n target?: SelectorTarget\n): AssembledToolCall[] {\n useResolveSubagentNamespace(stream, target);\n const namespace = resolveNamespace(target);\n const key = `toolCalls|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<AssembledToolCall[]>(\n registry,\n () => toolCallsProjection(namespace),\n key,\n EMPTY_TOOLCALLS\n );\n return isRoot(namespace) ? stream.toolCalls : scoped;\n}\n\nconst EMPTY_TOOLCALLS: AssembledToolCall[] = [];\n\n/**\n * Subscribe to a scoped `values` stream — most-recent state payload\n * for a namespace. Equivalent to reading `stream.values` at the root.\n *\n * When the payload carries a `messages` array, it is coerced to\n * `BaseMessage` instances to keep parity with the root projection.\n *\n * Typing:\n * - **Root** (`useValues(stream)`): returns the `StateType` declared\n * on the parent `useStream<State>()` — no explicit\n * generic required. Non-nullable because the root snapshot always\n * carries `values` (falling back to `initialValues ?? {}`).\n * - **Scoped** (`useValues(stream, target)`): the scoped payload can\n * have a different shape than the root state (e.g. a subagent\n * returning its own substate). Callers should annotate the\n * expected shape explicitly: `useValues<SubagentState>(stream, sub)`.\n * Defaults to `unknown` when not annotated.\n */\nexport function useValues<StateType extends object>(\n stream: StreamHandle<StateType>\n): StateType;\n/**\n * Explicit-generic override. Accepts:\n * - an agent brand or compiled graph (unwrapped via\n * {@link InferStateType});\n * - a plain state shape (returned as-is).\n *\n * The root-call form is non-nullable (the root snapshot is always\n * present); the scoped form returns `T | undefined` because a\n * projection may not have emitted a payload yet.\n */\nexport function useValues<T>(stream: AnyStream): InferStateType<T>;\nexport function useValues<T = unknown>(\n stream: AnyStream,\n target: SelectorTarget,\n options?: { messagesKey?: string }\n): T | undefined;\nexport function useValues(\n stream: AnyStream,\n target?: SelectorTarget,\n options?: { messagesKey?: string }\n): unknown {\n const namespace = resolveNamespace(target);\n const messagesKey = options?.messagesKey ?? \"messages\";\n const key = `values|${messagesKey}|${namespaceKey(namespace)}`;\n const registry = isRoot(namespace) ? null : getRegistry(stream);\n const scoped = useProjection<unknown>(\n registry,\n () => valuesProjection<unknown>(namespace, messagesKey),\n key,\n undefined\n );\n return isRoot(namespace) ? stream.values : scoped;\n}\n\n/**\n * Subscribe to a `custom:<name>` stream extension — the most-recent\n * payload emitted by the transformer, scoped to the target namespace.\n *\n * Returns only the latest value and resumes across serial runs, so it is\n * ideal for \"current state\" panels (progress, score, status). When you\n * need the full history of events rather than just the latest payload,\n * use {@link useChannel} instead.\n */\nexport function useExtension<T = unknown>(\n stream: AnyStream,\n name: string,\n target?: SelectorTarget\n): T | undefined {\n const namespace = resolveNamespace(target);\n const key = `extension|${name}|${namespaceKey(namespace)}`;\n return useProjection<T | undefined>(\n getRegistry(stream),\n () => extensionProjection<T>(name, namespace),\n key,\n undefined\n );\n}\n\n/**\n * Subscribe to a scoped audio-media stream. Returns an array of\n * {@link AudioMedia} handles, one per message containing at least one\n * `AudioBlock` in the target namespace.\n *\n * Each handle is yielded on its first matching `content-block-start`,\n * exposes `.partialBytes` for live access, settles `.blob` /\n * `.objectURL` / `.transcript` on `message-finish`, and surfaces\n * fail-loud errors via `.error`.\n *\n * Pair with {@link useMediaURL} to turn a handle into an `<audio src>`.\n */\nexport function useAudio(\n stream: AnyStream,\n target?: SelectorTarget\n): AudioMedia[] {\n const namespace = resolveNamespace(target);\n const key = `audio|${namespaceKey(namespace)}`;\n return useProjection<AudioMedia[]>(\n getRegistry(stream),\n () => audioProjection(namespace),\n key,\n EMPTY_AUDIO\n );\n}\n\nconst EMPTY_AUDIO: AudioMedia[] = [];\n\n/**\n * Subscribe to a scoped image-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<img src>`.\n */\nexport function useImages(\n stream: AnyStream,\n target?: SelectorTarget\n): ImageMedia[] {\n const namespace = resolveNamespace(target);\n const key = `images|${namespaceKey(namespace)}`;\n return useProjection<ImageMedia[]>(\n getRegistry(stream),\n () => imagesProjection(namespace),\n key,\n EMPTY_IMAGES\n );\n}\n\nconst EMPTY_IMAGES: ImageMedia[] = [];\n\n/**\n * Subscribe to a scoped video-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for `<video src>`.\n */\nexport function useVideo(\n stream: AnyStream,\n target?: SelectorTarget\n): VideoMedia[] {\n const namespace = resolveNamespace(target);\n const key = `video|${namespaceKey(namespace)}`;\n return useProjection<VideoMedia[]>(\n getRegistry(stream),\n () => videoProjection(namespace),\n key,\n EMPTY_VIDEO\n );\n}\n\nconst EMPTY_VIDEO: VideoMedia[] = [];\n\n/**\n * Subscribe to a scoped file-media stream. See {@link useAudio} for\n * shared semantics; pair with {@link useMediaURL} for an\n * `<a download href>` target.\n */\nexport function useFiles(\n stream: AnyStream,\n target?: SelectorTarget\n): FileMedia[] {\n const namespace = resolveNamespace(target);\n const key = `files|${namespaceKey(namespace)}`;\n return useProjection<FileMedia[]>(\n getRegistry(stream),\n () => filesProjection(namespace),\n key,\n EMPTY_FILES\n );\n}\n\nconst EMPTY_FILES: FileMedia[] = [];\n\nexport type UseChannelOptions = ChannelProjectionOptions;\n\n/**\n * Raw-events escape hatch. Subscribes to one or more channels at a\n * namespace and returns a bounded buffer of raw protocol events.\n *\n * The buffer keeps accumulating across serial runs for the lifetime of\n * the thread, so this is the hook to use for an event log / stream of a\n * custom channel (e.g. `[\"custom:redaction-stats\"]`). When you only need\n * the latest payload of a single `custom:<name>` channel, prefer\n * {@link useExtension}. For the common message/tool/value cases prefer\n * {@link useMessages} / {@link useToolCalls} / {@link useValues}.\n */\nexport function useChannel(\n stream: AnyStream,\n channels: readonly Channel[],\n target?: SelectorTarget,\n options?: UseChannelOptions\n): Event[] {\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channel|${options?.bufferSize ?? \"default\"}|${(options?.replay ?? true) ? \"replay\" : \"live\"}|${channelKey}|${namespaceKey(namespace)}`;\n return useProjection<Event[]>(\n getRegistry(stream),\n () => channelProjection(channels, namespace, options),\n key,\n EMPTY_EVENTS\n );\n}\n\nconst EMPTY_EVENTS: Event[] = [];\n\n/**\n * Options for {@link useChannelEffect}. Extends the projection options\n * (`bufferSize`, `replay`) with the per-event callback, an optional\n * error sink, a `target` scope, and an `enabled` gate.\n */\nexport interface UseChannelEffectOptions extends ChannelEffectOptions {\n /**\n * Scope events to a subagent / subgraph / explicit namespace.\n * Defaults to the root namespace.\n */\n target?: SelectorTarget;\n /**\n * Gate the subscription. When `false`, no subscription is opened and\n * no events are delivered. Defaults to `true`. Flipping this lets you\n * pause analytics (e.g. while the user is viewing a different thread)\n * without unmounting.\n */\n enabled?: boolean;\n}\n\n/**\n * Side-effect counterpart to {@link useChannel}. Instead of returning a\n * buffer of events that re-renders the component, it invokes `onEvent`\n * once per event for as long as the hook is mounted — the idiomatic\n * place for analytics, logging, and other fire-and-forget side effects.\n *\n * ```tsx\n * useChannelEffect(stream, [\"lifecycle\", \"tools\"], {\n * replay: false,\n * onEvent(event) {\n * sendAnalytics(event);\n * },\n * onError(error) {\n * logger.error(error);\n * },\n * });\n * ```\n *\n * Notes:\n * - `onEvent` / `onError` are read from a ref, so passing a fresh\n * closure each render is fine — it never re-subscribes.\n * - The underlying subscription is shared (ref-counted) with any\n * matching {@link useChannel} consumer, so you only ever pay for one\n * server subscription per channel set.\n * - `replay` defaults to `false` (live-only). Set it to `true` only if\n * you genuinely want to (re)process replayed history.\n * - Events buffered before the hook mounts are not re-delivered.\n */\nexport function useChannelEffect(\n stream: AnyStream,\n channels: readonly Channel[],\n options: UseChannelEffectOptions\n): void {\n const {\n target,\n enabled = true,\n replay,\n bufferSize,\n onEvent,\n onError,\n } = options;\n\n // Keep the latest callbacks in refs so re-renders that pass new inline\n // closures never tear down and re-open the subscription.\n const onEventRef = useRef(onEvent);\n const onErrorRef = useRef(onError);\n onEventRef.current = onEvent;\n onErrorRef.current = onError;\n\n useResolveSubagentNamespace(stream, target);\n\n const namespace = resolveNamespace(target);\n const channelKey = useMemo(() => [...channels].sort().join(\",\"), [channels]);\n const key = `channelEffect|${bufferSize ?? \"default\"}|${\n (replay ?? false) ? \"replay\" : \"live\"\n }|${channelKey}|${namespaceKey(namespace)}`;\n\n const registry = getRegistry(stream);\n\n useEffect(() => {\n if (!enabled || registry == null) return undefined;\n return acquireChannelEffect(registry, channels, namespace, {\n replay,\n bufferSize,\n onEvent: (event) => onEventRef.current(event),\n onError: (error) => onErrorRef.current?.(error),\n });\n // `channels` / `namespace` / `replay` / `bufferSize` are folded into\n // `key`; callbacks live in refs. Re-subscribe only when the resolved\n // scope or `enabled` changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [registry, key, enabled]);\n}\n\n/**\n * Read metadata recorded for a specific message id — today exposes\n * `parentCheckpointId`, the checkpoint the message was first seen on.\n * Designed for fork / edit flows:\n *\n * ```tsx\n * const { parentCheckpointId } = useMessageMetadata(stream, msg.id) ?? {};\n * if (parentCheckpointId) {\n * await stream.submit(input, { forkFrom: parentCheckpointId });\n * }\n * ```\n *\n * Returns `undefined` when the id isn't known yet (e.g. the server\n * hasn't emitted `parent_checkpoint` for that message, or the message\n * arrived via `messages`-channel deltas only and no `values` snapshot\n * has landed for it yet).\n */\nexport function useMessageMetadata(\n stream: AnyStream,\n messageId: string | undefined\n): MessageMetadata | undefined {\n const store = stream[STREAM_CONTROLLER].messageMetadataStore;\n const snapshot = useSyncExternalStore<MessageMetadataMap>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return messageId == null ? undefined : snapshot.get(messageId);\n}\n\n/**\n * Reactive handle on the server-side submission queue.\n *\n * Populated when `submit()` is invoked with `multitaskStrategy:\n * \"enqueue\"` while another run is in flight. The returned object is\n * stable per snapshot so consumers can pass `entries` straight into a\n * `<Fragment key={e.id}>` list without extra memoisation.\n */\nexport interface UseSubmissionQueueReturn<\n StateType extends object = Record<string, unknown>,\n> {\n readonly entries: SubmissionQueueSnapshot<StateType>;\n readonly size: number;\n cancel(id: string): Promise<boolean>;\n clear(): Promise<void>;\n}\n\nexport function useSubmissionQueue<StateType extends object>(\n stream: StreamHandle<StateType>\n): UseSubmissionQueueReturn<StateType>;\nexport function useSubmissionQueue(stream: AnyStream): UseSubmissionQueueReturn;\nexport function useSubmissionQueue(\n stream: AnyStream\n): UseSubmissionQueueReturn {\n const controller = stream[STREAM_CONTROLLER];\n const store = controller.queueStore;\n const entries = useSyncExternalStore<SubmissionQueueSnapshot>(\n store.subscribe,\n store.getSnapshot,\n store.getSnapshot\n );\n return useMemo<UseSubmissionQueueReturn>(\n () => ({\n entries,\n size: entries.length,\n cancel: (id) => controller.cancelQueued(id),\n clear: () => controller.clearQueue(),\n }),\n [entries, controller]\n );\n}\n\nexport type { SubmissionQueueEntry, SubmissionQueueSnapshot };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"description": "React integration for LangGraph & LangChain",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"directory": "libs/sdk-react"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@langchain/langgraph-sdk": "1.9.
|
|
13
|
+
"@langchain/langgraph-sdk": "1.9.22"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@hono/node-server": "^1.19.13",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"vitest-browser-react": "^2.2.0",
|
|
31
31
|
"webdriverio": "^9.25.0",
|
|
32
32
|
"zod": "^4.3.6",
|
|
33
|
-
"@langchain/langgraph": "^1.4.
|
|
34
|
-
"@langchain/langgraph-api": "^1.3.
|
|
35
|
-
"@langchain/langgraph-checkpoint": "^1.1.
|
|
33
|
+
"@langchain/langgraph": "^1.4.2",
|
|
34
|
+
"@langchain/langgraph-api": "^1.3.1",
|
|
35
|
+
"@langchain/langgraph-checkpoint": "^1.1.1"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@langchain/core": "^1.1.48",
|