@langchain/langgraph-sdk 0.0.111 → 0.1.0

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.
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StreamManager = void 0;
4
+ const messages_js_1 = require("./messages.cjs");
5
+ const errors_js_1 = require("./errors.cjs");
6
+ class StreamManager {
7
+ constructor(messages) {
8
+ Object.defineProperty(this, "abortRef", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: new AbortController()
13
+ });
14
+ Object.defineProperty(this, "messages", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ Object.defineProperty(this, "listeners", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: new Set()
25
+ });
26
+ Object.defineProperty(this, "state", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: void 0
31
+ });
32
+ Object.defineProperty(this, "setState", {
33
+ enumerable: true,
34
+ configurable: true,
35
+ writable: true,
36
+ value: (newState) => {
37
+ this.state = { ...this.state, ...newState };
38
+ this.notifyListeners();
39
+ }
40
+ });
41
+ Object.defineProperty(this, "notifyListeners", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: () => {
46
+ this.listeners.forEach((listener) => listener());
47
+ }
48
+ });
49
+ Object.defineProperty(this, "subscribe", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: (listener) => {
54
+ this.listeners.add(listener);
55
+ return () => this.listeners.delete(listener);
56
+ }
57
+ });
58
+ Object.defineProperty(this, "getSnapshot", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: () => this.state
63
+ });
64
+ Object.defineProperty(this, "setStreamValues", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: (values, kind = "stream") => {
69
+ if (typeof values === "function") {
70
+ const [prevValues, prevKind] = this.state.values ?? [null, "stream"];
71
+ const nextValues = values(prevValues, prevKind);
72
+ this.setState({ values: nextValues != null ? [nextValues, kind] : null });
73
+ }
74
+ else {
75
+ const nextValues = values != null ? [values, kind] : null;
76
+ this.setState({ values: nextValues });
77
+ }
78
+ }
79
+ });
80
+ Object.defineProperty(this, "getMutateFn", {
81
+ enumerable: true,
82
+ configurable: true,
83
+ writable: true,
84
+ value: (kind, historyValues) => {
85
+ return (update) => {
86
+ const prev = { ...historyValues, ...this.state.values };
87
+ const next = typeof update === "function" ? update(prev) : update;
88
+ this.setStreamValues({ ...prev, ...next }, kind);
89
+ };
90
+ }
91
+ });
92
+ Object.defineProperty(this, "matchEventType", {
93
+ enumerable: true,
94
+ configurable: true,
95
+ writable: true,
96
+ value: (expected, actual, _data) => {
97
+ return expected === actual || actual.startsWith(`${expected}|`);
98
+ }
99
+ });
100
+ Object.defineProperty(this, "start", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: async (action, options) => {
105
+ if (this.state.isLoading)
106
+ return;
107
+ try {
108
+ this.setState({ isLoading: true, error: undefined });
109
+ this.abortRef = new AbortController();
110
+ const run = await action(this.abortRef.signal);
111
+ let streamError;
112
+ for await (const { event, data } of run) {
113
+ if (event === "error") {
114
+ streamError = new errors_js_1.StreamError(data);
115
+ break;
116
+ }
117
+ const namespace = event.includes("|")
118
+ ? event.split("|").slice(1)
119
+ : undefined;
120
+ const mutate = this.getMutateFn("stream", options.initialValues);
121
+ if (event === "metadata")
122
+ options.callbacks.onMetadataEvent?.(data);
123
+ if (event === "events")
124
+ options.callbacks.onLangChainEvent?.(data);
125
+ if (this.matchEventType("updates", event, data)) {
126
+ options.callbacks.onUpdateEvent?.(data, { namespace, mutate });
127
+ }
128
+ if (this.matchEventType("custom", event, data)) {
129
+ options.callbacks.onCustomEvent?.(data, { namespace, mutate });
130
+ }
131
+ if (this.matchEventType("checkpoints", event, data)) {
132
+ options.callbacks.onCheckpointEvent?.(data, { namespace });
133
+ }
134
+ if (this.matchEventType("tasks", event, data)) {
135
+ options.callbacks.onTaskEvent?.(data, { namespace });
136
+ }
137
+ if (this.matchEventType("debug", event, data)) {
138
+ options.callbacks.onDebugEvent?.(data, { namespace });
139
+ }
140
+ if (event === "values") {
141
+ // don't update values on interrupt values event
142
+ if ("__interrupt__" in data)
143
+ continue;
144
+ this.setStreamValues(data);
145
+ }
146
+ if (this.matchEventType("messages", event, data)) {
147
+ const [serialized, metadata] = data;
148
+ const messageId = this.messages.add(serialized, metadata);
149
+ if (!messageId) {
150
+ console.warn("Failed to add message to manager, no message ID found");
151
+ continue;
152
+ }
153
+ this.setStreamValues((streamValues) => {
154
+ const values = { ...options.initialValues, ...streamValues };
155
+ // Assumption: we're concatenating the message
156
+ const messages = options.getMessages(values).slice();
157
+ const { chunk, index } = this.messages.get(messageId, messages.length) ?? {};
158
+ if (!chunk || index == null)
159
+ return values;
160
+ messages[index] = (0, messages_js_1.toMessageDict)(chunk);
161
+ return options.setMessages(values, messages);
162
+ });
163
+ }
164
+ }
165
+ if (streamError != null)
166
+ throw streamError;
167
+ const values = await options.onSuccess?.();
168
+ if (typeof values !== "undefined")
169
+ this.setStreamValues(values);
170
+ }
171
+ catch (error) {
172
+ if (!(error instanceof Error && // eslint-disable-line no-instanceof/no-instanceof
173
+ (error.name === "AbortError" || error.name === "TimeoutError"))) {
174
+ console.error(error);
175
+ this.setState({ error });
176
+ await options.onError?.(error);
177
+ }
178
+ }
179
+ finally {
180
+ this.setState({ isLoading: false });
181
+ this.abortRef = new AbortController();
182
+ }
183
+ }
184
+ });
185
+ Object.defineProperty(this, "stop", {
186
+ enumerable: true,
187
+ configurable: true,
188
+ writable: true,
189
+ value: async (historyValues, options) => {
190
+ if (this.abortRef) {
191
+ this.abortRef.abort();
192
+ this.abortRef = new AbortController();
193
+ }
194
+ options.onStop?.({ mutate: this.getMutateFn("stop", historyValues) });
195
+ }
196
+ });
197
+ Object.defineProperty(this, "clear", {
198
+ enumerable: true,
199
+ configurable: true,
200
+ writable: true,
201
+ value: () => {
202
+ this.setState({ error: undefined, values: null });
203
+ this.messages.clear();
204
+ }
205
+ });
206
+ this.messages = messages;
207
+ this.state = { isLoading: false, values: null, error: undefined };
208
+ }
209
+ get isLoading() {
210
+ return this.state.isLoading;
211
+ }
212
+ get values() {
213
+ return this.state.values?.[0] ?? null;
214
+ }
215
+ get error() {
216
+ return this.state.error;
217
+ }
218
+ }
219
+ exports.StreamManager = StreamManager;
@@ -0,0 +1,86 @@
1
+ import type { CheckpointsStreamEvent, CustomStreamEvent, DebugStreamEvent, ErrorStreamEvent, EventsStreamEvent, FeedbackStreamEvent, MessagesTupleStreamEvent, MetadataStreamEvent, TasksStreamEvent, UpdatesStreamEvent, ValuesStreamEvent } from "../types.stream.js";
2
+ import { MessageTupleManager } from "./messages.js";
3
+ import type { Message } from "../types.messages.js";
4
+ type BagTemplate = {
5
+ ConfigurableType?: Record<string, unknown>;
6
+ InterruptType?: unknown;
7
+ CustomEventType?: unknown;
8
+ UpdateType?: unknown;
9
+ };
10
+ type GetUpdateType<Bag extends BagTemplate, StateType extends Record<string, unknown>> = Bag extends {
11
+ UpdateType: unknown;
12
+ } ? Bag["UpdateType"] : Partial<StateType>;
13
+ type GetCustomEventType<Bag extends BagTemplate> = Bag extends {
14
+ CustomEventType: unknown;
15
+ } ? Bag["CustomEventType"] : unknown;
16
+ type EventStreamMap<StateType, UpdateType, CustomType> = {
17
+ values: ValuesStreamEvent<StateType>;
18
+ updates: UpdatesStreamEvent<UpdateType>;
19
+ custom: CustomStreamEvent<CustomType>;
20
+ debug: DebugStreamEvent;
21
+ messages: MessagesTupleStreamEvent;
22
+ events: EventsStreamEvent;
23
+ metadata: MetadataStreamEvent;
24
+ checkpoints: CheckpointsStreamEvent<StateType>;
25
+ tasks: TasksStreamEvent<StateType, UpdateType>;
26
+ error: ErrorStreamEvent;
27
+ feedback: FeedbackStreamEvent;
28
+ };
29
+ export type EventStreamEvent<StateType, UpdateType, CustomType> = EventStreamMap<StateType, UpdateType, CustomType>[keyof EventStreamMap<StateType, UpdateType, CustomType>];
30
+ interface StreamManagerEventCallbacks<StateType extends Record<string, unknown>, Bag extends BagTemplate = BagTemplate> {
31
+ onUpdateEvent?: (data: UpdatesStreamEvent<GetUpdateType<Bag, StateType>>["data"], options: {
32
+ namespace: string[] | undefined;
33
+ mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void;
34
+ }) => void;
35
+ onCustomEvent?: (data: GetCustomEventType<Bag>, options: {
36
+ namespace: string[] | undefined;
37
+ mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void;
38
+ }) => void;
39
+ onMetadataEvent?: (data: MetadataStreamEvent["data"]) => void;
40
+ onLangChainEvent?: (data: EventsStreamEvent["data"]) => void;
41
+ onDebugEvent?: (data: DebugStreamEvent["data"], options: {
42
+ namespace: string[] | undefined;
43
+ }) => void;
44
+ onCheckpointEvent?: (data: CheckpointsStreamEvent<StateType>["data"], options: {
45
+ namespace: string[] | undefined;
46
+ }) => void;
47
+ onTaskEvent?: (data: TasksStreamEvent<StateType, GetUpdateType<Bag, StateType>>["data"], options: {
48
+ namespace: string[] | undefined;
49
+ }) => void;
50
+ }
51
+ export declare class StreamManager<StateType extends Record<string, unknown>, Bag extends BagTemplate = BagTemplate> {
52
+ private abortRef;
53
+ private messages;
54
+ private listeners;
55
+ private state;
56
+ constructor(messages: MessageTupleManager);
57
+ private setState;
58
+ private notifyListeners;
59
+ subscribe: (listener: () => void) => (() => void);
60
+ getSnapshot: () => {
61
+ isLoading: boolean;
62
+ values: [values: StateType, kind: "stream" | "stop"] | null;
63
+ error: unknown;
64
+ };
65
+ get isLoading(): boolean;
66
+ get values(): StateType | null;
67
+ get error(): unknown;
68
+ setStreamValues: (values: (StateType | null) | ((prev: StateType | null, kind: "stream" | "stop") => StateType | null), kind?: "stream" | "stop") => void;
69
+ private getMutateFn;
70
+ private matchEventType;
71
+ start: (action: (signal: AbortSignal) => Promise<AsyncGenerator<EventStreamEvent<StateType, GetUpdateType<Bag, StateType>, GetCustomEventType<Bag>>>>, options: {
72
+ getMessages: (values: StateType) => Message[];
73
+ setMessages: (current: StateType, messages: Message[]) => StateType;
74
+ initialValues: StateType;
75
+ callbacks: StreamManagerEventCallbacks<StateType, Bag>;
76
+ onSuccess: () => StateType | null | undefined | void | Promise<StateType | null | undefined | void>;
77
+ onError: (error: unknown) => void | Promise<void>;
78
+ }) => Promise<void>;
79
+ stop: (historyValues: StateType, options: {
80
+ onStop?: (options: {
81
+ mutate: (update: Partial<StateType> | ((prev: StateType) => Partial<StateType>)) => void;
82
+ }) => void;
83
+ }) => Promise<void>;
84
+ clear: () => void;
85
+ }
86
+ export {};
@@ -0,0 +1,215 @@
1
+ import { toMessageDict } from "./messages.js";
2
+ import { StreamError } from "./errors.js";
3
+ export class StreamManager {
4
+ constructor(messages) {
5
+ Object.defineProperty(this, "abortRef", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: new AbortController()
10
+ });
11
+ Object.defineProperty(this, "messages", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "listeners", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: new Set()
22
+ });
23
+ Object.defineProperty(this, "state", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: void 0
28
+ });
29
+ Object.defineProperty(this, "setState", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: (newState) => {
34
+ this.state = { ...this.state, ...newState };
35
+ this.notifyListeners();
36
+ }
37
+ });
38
+ Object.defineProperty(this, "notifyListeners", {
39
+ enumerable: true,
40
+ configurable: true,
41
+ writable: true,
42
+ value: () => {
43
+ this.listeners.forEach((listener) => listener());
44
+ }
45
+ });
46
+ Object.defineProperty(this, "subscribe", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: (listener) => {
51
+ this.listeners.add(listener);
52
+ return () => this.listeners.delete(listener);
53
+ }
54
+ });
55
+ Object.defineProperty(this, "getSnapshot", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: () => this.state
60
+ });
61
+ Object.defineProperty(this, "setStreamValues", {
62
+ enumerable: true,
63
+ configurable: true,
64
+ writable: true,
65
+ value: (values, kind = "stream") => {
66
+ if (typeof values === "function") {
67
+ const [prevValues, prevKind] = this.state.values ?? [null, "stream"];
68
+ const nextValues = values(prevValues, prevKind);
69
+ this.setState({ values: nextValues != null ? [nextValues, kind] : null });
70
+ }
71
+ else {
72
+ const nextValues = values != null ? [values, kind] : null;
73
+ this.setState({ values: nextValues });
74
+ }
75
+ }
76
+ });
77
+ Object.defineProperty(this, "getMutateFn", {
78
+ enumerable: true,
79
+ configurable: true,
80
+ writable: true,
81
+ value: (kind, historyValues) => {
82
+ return (update) => {
83
+ const prev = { ...historyValues, ...this.state.values };
84
+ const next = typeof update === "function" ? update(prev) : update;
85
+ this.setStreamValues({ ...prev, ...next }, kind);
86
+ };
87
+ }
88
+ });
89
+ Object.defineProperty(this, "matchEventType", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: (expected, actual, _data) => {
94
+ return expected === actual || actual.startsWith(`${expected}|`);
95
+ }
96
+ });
97
+ Object.defineProperty(this, "start", {
98
+ enumerable: true,
99
+ configurable: true,
100
+ writable: true,
101
+ value: async (action, options) => {
102
+ if (this.state.isLoading)
103
+ return;
104
+ try {
105
+ this.setState({ isLoading: true, error: undefined });
106
+ this.abortRef = new AbortController();
107
+ const run = await action(this.abortRef.signal);
108
+ let streamError;
109
+ for await (const { event, data } of run) {
110
+ if (event === "error") {
111
+ streamError = new StreamError(data);
112
+ break;
113
+ }
114
+ const namespace = event.includes("|")
115
+ ? event.split("|").slice(1)
116
+ : undefined;
117
+ const mutate = this.getMutateFn("stream", options.initialValues);
118
+ if (event === "metadata")
119
+ options.callbacks.onMetadataEvent?.(data);
120
+ if (event === "events")
121
+ options.callbacks.onLangChainEvent?.(data);
122
+ if (this.matchEventType("updates", event, data)) {
123
+ options.callbacks.onUpdateEvent?.(data, { namespace, mutate });
124
+ }
125
+ if (this.matchEventType("custom", event, data)) {
126
+ options.callbacks.onCustomEvent?.(data, { namespace, mutate });
127
+ }
128
+ if (this.matchEventType("checkpoints", event, data)) {
129
+ options.callbacks.onCheckpointEvent?.(data, { namespace });
130
+ }
131
+ if (this.matchEventType("tasks", event, data)) {
132
+ options.callbacks.onTaskEvent?.(data, { namespace });
133
+ }
134
+ if (this.matchEventType("debug", event, data)) {
135
+ options.callbacks.onDebugEvent?.(data, { namespace });
136
+ }
137
+ if (event === "values") {
138
+ // don't update values on interrupt values event
139
+ if ("__interrupt__" in data)
140
+ continue;
141
+ this.setStreamValues(data);
142
+ }
143
+ if (this.matchEventType("messages", event, data)) {
144
+ const [serialized, metadata] = data;
145
+ const messageId = this.messages.add(serialized, metadata);
146
+ if (!messageId) {
147
+ console.warn("Failed to add message to manager, no message ID found");
148
+ continue;
149
+ }
150
+ this.setStreamValues((streamValues) => {
151
+ const values = { ...options.initialValues, ...streamValues };
152
+ // Assumption: we're concatenating the message
153
+ const messages = options.getMessages(values).slice();
154
+ const { chunk, index } = this.messages.get(messageId, messages.length) ?? {};
155
+ if (!chunk || index == null)
156
+ return values;
157
+ messages[index] = toMessageDict(chunk);
158
+ return options.setMessages(values, messages);
159
+ });
160
+ }
161
+ }
162
+ if (streamError != null)
163
+ throw streamError;
164
+ const values = await options.onSuccess?.();
165
+ if (typeof values !== "undefined")
166
+ this.setStreamValues(values);
167
+ }
168
+ catch (error) {
169
+ if (!(error instanceof Error && // eslint-disable-line no-instanceof/no-instanceof
170
+ (error.name === "AbortError" || error.name === "TimeoutError"))) {
171
+ console.error(error);
172
+ this.setState({ error });
173
+ await options.onError?.(error);
174
+ }
175
+ }
176
+ finally {
177
+ this.setState({ isLoading: false });
178
+ this.abortRef = new AbortController();
179
+ }
180
+ }
181
+ });
182
+ Object.defineProperty(this, "stop", {
183
+ enumerable: true,
184
+ configurable: true,
185
+ writable: true,
186
+ value: async (historyValues, options) => {
187
+ if (this.abortRef) {
188
+ this.abortRef.abort();
189
+ this.abortRef = new AbortController();
190
+ }
191
+ options.onStop?.({ mutate: this.getMutateFn("stop", historyValues) });
192
+ }
193
+ });
194
+ Object.defineProperty(this, "clear", {
195
+ enumerable: true,
196
+ configurable: true,
197
+ writable: true,
198
+ value: () => {
199
+ this.setState({ error: undefined, values: null });
200
+ this.messages.clear();
201
+ }
202
+ });
203
+ this.messages = messages;
204
+ this.state = { isLoading: false, values: null, error: undefined };
205
+ }
206
+ get isLoading() {
207
+ return this.state.isLoading;
208
+ }
209
+ get values() {
210
+ return this.state.values?.[0] ?? null;
211
+ }
212
+ get error() {
213
+ return this.state.error;
214
+ }
215
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toMessageDict = exports.MessageTupleManager = void 0;
4
+ const messages_1 = require("@langchain/core/messages");
5
+ function tryConvertToChunk(message) {
6
+ try {
7
+ return (0, messages_1.convertToChunk)(message);
8
+ }
9
+ catch {
10
+ return null;
11
+ }
12
+ }
13
+ class MessageTupleManager {
14
+ constructor() {
15
+ Object.defineProperty(this, "chunks", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: {}
20
+ });
21
+ this.chunks = {};
22
+ }
23
+ add(serialized, metadata) {
24
+ // TODO: this is sometimes sent from the API
25
+ // figure out how to prevent this or move this to LC.js
26
+ if (serialized.type.endsWith("MessageChunk")) {
27
+ // eslint-disable-next-line no-param-reassign
28
+ serialized.type = serialized.type
29
+ .slice(0, -"MessageChunk".length)
30
+ .toLowerCase();
31
+ }
32
+ const message = (0, messages_1.coerceMessageLikeToMessage)(serialized);
33
+ const chunk = tryConvertToChunk(message);
34
+ const { id } = chunk ?? message;
35
+ if (!id) {
36
+ console.warn("No message ID found for chunk, ignoring in state", serialized);
37
+ return null;
38
+ }
39
+ this.chunks[id] ??= {};
40
+ this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;
41
+ if (chunk) {
42
+ const prev = this.chunks[id].chunk;
43
+ this.chunks[id].chunk =
44
+ ((0, messages_1.isBaseMessageChunk)(prev) ? prev : null)?.concat(chunk) ?? chunk;
45
+ }
46
+ else {
47
+ this.chunks[id].chunk = message;
48
+ }
49
+ return id;
50
+ }
51
+ clear() {
52
+ this.chunks = {};
53
+ }
54
+ get(id, defaultIndex) {
55
+ if (id == null)
56
+ return null;
57
+ if (this.chunks[id] == null)
58
+ return null;
59
+ if (defaultIndex != null)
60
+ this.chunks[id].index ??= defaultIndex;
61
+ return this.chunks[id];
62
+ }
63
+ }
64
+ exports.MessageTupleManager = MessageTupleManager;
65
+ const toMessageDict = (chunk) => {
66
+ const { type, data } = chunk.toDict();
67
+ return { ...data, type };
68
+ };
69
+ exports.toMessageDict = toMessageDict;
@@ -0,0 +1,18 @@
1
+ import { type BaseMessage, type BaseMessageChunk } from "@langchain/core/messages";
2
+ import type { Message } from "../types.messages.js";
3
+ export declare class MessageTupleManager {
4
+ chunks: Record<string, {
5
+ chunk?: BaseMessageChunk | BaseMessage;
6
+ metadata?: Record<string, unknown>;
7
+ index?: number;
8
+ }>;
9
+ constructor();
10
+ add(serialized: Message, metadata: Record<string, unknown> | undefined): string | null;
11
+ clear(): void;
12
+ get(id: string | null | undefined, defaultIndex?: number): {
13
+ chunk?: BaseMessageChunk | BaseMessage;
14
+ metadata?: Record<string, unknown>;
15
+ index?: number;
16
+ } | null;
17
+ }
18
+ export declare const toMessageDict: (chunk: BaseMessage) => Message;
@@ -0,0 +1,64 @@
1
+ import { convertToChunk, coerceMessageLikeToMessage, isBaseMessageChunk, } from "@langchain/core/messages";
2
+ function tryConvertToChunk(message) {
3
+ try {
4
+ return convertToChunk(message);
5
+ }
6
+ catch {
7
+ return null;
8
+ }
9
+ }
10
+ export class MessageTupleManager {
11
+ constructor() {
12
+ Object.defineProperty(this, "chunks", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: {}
17
+ });
18
+ this.chunks = {};
19
+ }
20
+ add(serialized, metadata) {
21
+ // TODO: this is sometimes sent from the API
22
+ // figure out how to prevent this or move this to LC.js
23
+ if (serialized.type.endsWith("MessageChunk")) {
24
+ // eslint-disable-next-line no-param-reassign
25
+ serialized.type = serialized.type
26
+ .slice(0, -"MessageChunk".length)
27
+ .toLowerCase();
28
+ }
29
+ const message = coerceMessageLikeToMessage(serialized);
30
+ const chunk = tryConvertToChunk(message);
31
+ const { id } = chunk ?? message;
32
+ if (!id) {
33
+ console.warn("No message ID found for chunk, ignoring in state", serialized);
34
+ return null;
35
+ }
36
+ this.chunks[id] ??= {};
37
+ this.chunks[id].metadata = metadata ?? this.chunks[id].metadata;
38
+ if (chunk) {
39
+ const prev = this.chunks[id].chunk;
40
+ this.chunks[id].chunk =
41
+ (isBaseMessageChunk(prev) ? prev : null)?.concat(chunk) ?? chunk;
42
+ }
43
+ else {
44
+ this.chunks[id].chunk = message;
45
+ }
46
+ return id;
47
+ }
48
+ clear() {
49
+ this.chunks = {};
50
+ }
51
+ get(id, defaultIndex) {
52
+ if (id == null)
53
+ return null;
54
+ if (this.chunks[id] == null)
55
+ return null;
56
+ if (defaultIndex != null)
57
+ this.chunks[id].index ??= defaultIndex;
58
+ return this.chunks[id];
59
+ }
60
+ }
61
+ export const toMessageDict = (chunk) => {
62
+ const { type, data } = chunk.toDict();
63
+ return { ...data, type };
64
+ };