@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
117 lines (116 loc) • 4.1 kB
JavaScript
import { ensureMessageInstances } from "./message-coercion.js";
import { toMessageDict } from "../ui/messages.js";
//#region src/stream/optimistic-input.ts
function isBaseMessageInstance(value) {
return value != null && typeof value.getType === "function";
}
/**
* Serialize `BaseMessage` instances under a state update's message key
* into plain message dicts so they survive JSON transport.
*
* `respond({ update })` / `respondAll({}, { update })` fold `update` into
* `Command(update=...)` on the wire. A `BaseMessage`'s default JSON form
* is the `lc` "constructor" envelope (`{ lc, type: "constructor", id,
* kwargs }`), which the server's `add_messages` reducer does **not**
* coerce — whereas the flat `{ type, content, ... }` dict that
* {@link toMessageDict} emits (and that `submit()` already sends) does.
* Mirroring the `submit()` path lets
* `respond({ update: { messages: [new AIMessage(...)] } })` behave like
* `submit({ messages: [new AIMessage(...)] })`.
*
* Only the configured `messagesKey` is touched — in both the object form
* and the `[key, value][]` tuple form. Every other key, and any already
* plain (non-`BaseMessage`) entry, passes through untouched.
*/
function serializeUpdateMessages(update, messagesKey) {
if (Array.isArray(update)) return update.map((entry) => Array.isArray(entry) && entry[0] === messagesKey ? [entry[0], serializeMessageValue(entry[1])] : entry);
if (!(messagesKey in update)) return update;
return {
...update,
[messagesKey]: serializeMessageValue(update[messagesKey])
};
}
function serializeMessageValue(value) {
if (isBaseMessageInstance(value)) return toMessageDict(value);
if (Array.isArray(value)) return value.map((item) => isBaseMessageInstance(item) ? toMessageDict(item) : item);
return value;
}
function extractId(value) {
const id = value?.id;
return typeof id === "string" && id.length > 0 ? id : void 0;
}
/**
* Normalize a message-key value into an array of entries. Mirrors the
* server's `add_messages` coercion: a bare string or single message
* object is treated as a one-element list.
*/
function toEntryArray(value) {
if (Array.isArray(value)) return value;
return [value];
}
/**
* Build a message dict carrying `id` from an arbitrary input entry,
* without mutating the original.
*/
function toDispatchDict(entry, id) {
if (typeof entry === "string") return {
type: "human",
content: entry,
id
};
if (isBaseMessageInstance(entry)) return {
...toMessageDict(entry),
id
};
return {
...entry,
id
};
}
/**
* Prepare a raw submit input for optimistic dispatch.
*
* @param raw - Raw input passed to `submit()`. Must be a
* non-null, non-array object (caller guards this).
* @param messagesKey - State key holding the message array.
* @param mintId - Factory for stable client message ids.
* @returns The dispatch payload, optimistic messages, echoed ids, and
* the non-message portion of the input.
*/
function prepareOptimisticInput(raw, messagesKey, mintId) {
const dispatchInput = { ...raw };
const extraValues = {};
for (const key of Object.keys(raw)) if (key !== messagesKey) extraValues[key] = raw[key];
const echoedIds = [];
const messagesValue = raw[messagesKey];
if (messagesValue == null) return {
dispatchInput,
optimisticMessages: [],
echoedIds,
extraValues
};
const entries = toEntryArray(messagesValue);
const dispatchEntries = [];
const optimisticDicts = [];
for (const entry of entries) {
if (!(typeof entry === "string" || isBaseMessageInstance(entry) || entry != null && typeof entry === "object" && !Array.isArray(entry))) {
dispatchEntries.push(entry);
continue;
}
const id = extractId(entry) ?? mintId();
const dict = toDispatchDict(entry, id);
dispatchEntries.push(dict);
optimisticDicts.push(dict);
echoedIds.push(id);
}
dispatchInput[messagesKey] = dispatchEntries;
return {
dispatchInput,
optimisticMessages: ensureMessageInstances(optimisticDicts),
echoedIds,
extraValues
};
}
//#endregion
export { prepareOptimisticInput, serializeUpdateMessages };
//# sourceMappingURL=optimistic-input.js.map