@langchain/langgraph-api 1.2.2 → 1.2.4
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/experimental/embed/protocol.mjs +86 -15
- package/dist/graph/load.d.mts +1 -1
- package/dist/graph/load.utils.d.mts +1 -1
- package/dist/protocol/service.d.mts +9 -1
- package/dist/protocol/service.mjs +65 -25
- package/package.json +7 -7
- package/dist/src/api/assistants.d.mts +0 -3
- package/dist/src/api/assistants.mjs +0 -194
- package/dist/src/api/meta.d.mts +0 -3
- package/dist/src/api/meta.mjs +0 -65
- package/dist/src/api/protocol.d.mts +0 -7
- package/dist/src/api/protocol.mjs +0 -157
- package/dist/src/api/runs.d.mts +0 -3
- package/dist/src/api/runs.mjs +0 -335
- package/dist/src/api/store.d.mts +0 -3
- package/dist/src/api/store.mjs +0 -111
- package/dist/src/api/threads.d.mts +0 -3
- package/dist/src/api/threads.mjs +0 -143
- package/dist/src/graph/load.utils.d.mts +0 -22
- package/dist/src/graph/load.utils.mjs +0 -59
- package/dist/src/protocol/service.d.mts +0 -101
- package/dist/src/protocol/service.mjs +0 -568
- package/dist/src/protocol/session/event-normalizers.d.mts +0 -52
- package/dist/src/protocol/session/index.d.mts +0 -261
- package/dist/src/protocol/session/index.mjs +0 -826
- package/dist/src/protocol/session/namespace.d.mts +0 -47
- package/dist/src/protocol/session/namespace.mjs +0 -62
- package/dist/src/protocol/types.d.mts +0 -121
- package/dist/src/protocol/types.mjs +0 -1
- package/dist/src/schemas.d.mts +0 -1552
- package/dist/src/semver/index.d.mts +0 -15
- package/dist/src/semver/index.mjs +0 -46
- package/dist/src/semver/satisfiesPeerRange.d.mts +0 -1
- package/dist/src/semver/satisfiesPeerRange.mjs +0 -19
- package/dist/src/state.d.mts +0 -3
- package/dist/src/state.mjs +0 -30
- package/dist/src/storage/context.d.mts +0 -3
- package/dist/src/storage/context.mjs +0 -11
- package/dist/src/storage/ops.mjs +0 -1281
- package/dist/src/stream.d.mts +0 -64
- package/dist/src/stream.mjs +0 -427
- package/dist/src/utils/hono.d.mts +0 -5
- package/dist/src/utils/hono.mjs +0 -24
- package/dist/src/utils/runnableConfig.d.mts +0 -3
- package/dist/src/utils/runnableConfig.mjs +0 -45
- package/dist/src/webhook.d.mts +0 -11
- package/dist/src/webhook.mjs +0 -30
package/dist/src/stream.d.mts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { BaseCheckpointSaver, LangGraphRunnableConfig, CheckpointMetadata, Interrupt, StateSnapshot } from "@langchain/langgraph";
|
|
2
|
-
import type { Pregel } from "@langchain/langgraph/pregel";
|
|
3
|
-
import type { SourceStreamEvent } from "./protocol/types.mjs";
|
|
4
|
-
import type { Checkpoint, Run, RunnableConfig } from "./storage/types.mjs";
|
|
5
|
-
interface DebugTask {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
result?: unknown;
|
|
9
|
-
error?: unknown;
|
|
10
|
-
interrupts: Interrupt[];
|
|
11
|
-
state?: RunnableConfig | StateSnapshot;
|
|
12
|
-
path?: [string, ...(string | number)[]];
|
|
13
|
-
}
|
|
14
|
-
interface DebugCheckpoint {
|
|
15
|
-
config: RunnableConfig;
|
|
16
|
-
parentConfig: RunnableConfig | undefined;
|
|
17
|
-
values: unknown;
|
|
18
|
-
metadata: CheckpointMetadata;
|
|
19
|
-
next: string[];
|
|
20
|
-
tasks: DebugTask[];
|
|
21
|
-
}
|
|
22
|
-
type Prettify<T> = {
|
|
23
|
-
[K in keyof T]: T[K];
|
|
24
|
-
} & {};
|
|
25
|
-
export type StreamCheckpoint = Prettify<Omit<DebugCheckpoint, "parentConfig"> & {
|
|
26
|
-
parent_config: DebugCheckpoint["parentConfig"];
|
|
27
|
-
}>;
|
|
28
|
-
export type StreamTaskResult = Prettify<Omit<DebugTask, "state"> & {
|
|
29
|
-
state?: StateSnapshot;
|
|
30
|
-
checkpoint?: Checkpoint;
|
|
31
|
-
}>;
|
|
32
|
-
export declare function streamState(run: Run, options: {
|
|
33
|
-
attempt: number;
|
|
34
|
-
getGraph: (graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
|
|
35
|
-
checkpointer?: BaseCheckpointSaver | null;
|
|
36
|
-
}) => Promise<Pregel<any, any, any, any, any>>;
|
|
37
|
-
onCheckpoint?: (checkpoint: StreamCheckpoint) => void;
|
|
38
|
-
onTaskResult?: (taskResult: StreamTaskResult) => void;
|
|
39
|
-
signal?: AbortSignal;
|
|
40
|
-
}): AsyncGenerator<SourceStreamEvent>;
|
|
41
|
-
/**
|
|
42
|
-
* Executes a graph run using `graph.streamEvents(..., { version: "v3" })`
|
|
43
|
-
* and maps the resulting `ProtocolEvent` objects into the `{ event, data }`
|
|
44
|
-
* shape consumed by both the legacy SSE path and the protocol v2 session.
|
|
45
|
-
*
|
|
46
|
-
* This path activates graph-level `streamTransformers` (registered via
|
|
47
|
-
* `.compile({ transformers })`) so that custom transformer output flows to
|
|
48
|
-
* clients automatically.
|
|
49
|
-
*
|
|
50
|
-
* @param run - The queued run to execute.
|
|
51
|
-
* @param options - Callbacks and graph-loading infrastructure.
|
|
52
|
-
* @returns Async generator of `{ event, data }` pairs.
|
|
53
|
-
*/
|
|
54
|
-
export declare function streamStateV2(run: Run, options: {
|
|
55
|
-
attempt: number;
|
|
56
|
-
graph: Pregel<any, any, any, any, any>;
|
|
57
|
-
getGraph: (graphId: string, config: LangGraphRunnableConfig | undefined, options?: {
|
|
58
|
-
checkpointer?: BaseCheckpointSaver | null;
|
|
59
|
-
}) => Promise<Pregel<any, any, any, any, any>>;
|
|
60
|
-
onCheckpoint?: (checkpoint: StreamCheckpoint) => void;
|
|
61
|
-
onTaskResult?: (taskResult: StreamTaskResult) => void;
|
|
62
|
-
signal?: AbortSignal;
|
|
63
|
-
}): AsyncGenerator<SourceStreamEvent>;
|
|
64
|
-
export {};
|
package/dist/src/stream.mjs
DELETED
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { isBaseMessage } from "@langchain/core/messages";
|
|
2
|
-
import { LangChainTracer } from "@langchain/core/tracers/tracer_langchain";
|
|
3
|
-
import { convertToProtocolEvent, STREAM_EVENTS_V3_MODES, } from "@langchain/langgraph/web";
|
|
4
|
-
import { Client as LangSmithClient, getDefaultProjectName } from "langsmith";
|
|
5
|
-
import { getLangGraphCommand } from "./command.mjs";
|
|
6
|
-
import { PROTOCOL_STREAM_RUN_KEY } from "./protocol/constants.mjs";
|
|
7
|
-
import { checkLangGraphSemver } from "./semver/index.mjs";
|
|
8
|
-
import { runnableConfigToCheckpoint, taskRunnableConfigToCheckpoint, } from "./utils/runnableConfig.mjs";
|
|
9
|
-
const isRunnableConfig = (config) => {
|
|
10
|
-
if (typeof config !== "object" || config == null)
|
|
11
|
-
return false;
|
|
12
|
-
return ("configurable" in config &&
|
|
13
|
-
typeof config.configurable === "object" &&
|
|
14
|
-
config.configurable != null);
|
|
15
|
-
};
|
|
16
|
-
function preprocessDebugCheckpointTask(task) {
|
|
17
|
-
if (!isRunnableConfig(task.state) ||
|
|
18
|
-
!taskRunnableConfigToCheckpoint(task.state)) {
|
|
19
|
-
return task;
|
|
20
|
-
}
|
|
21
|
-
const cloneTask = { ...task };
|
|
22
|
-
cloneTask.checkpoint = taskRunnableConfigToCheckpoint(task.state);
|
|
23
|
-
delete cloneTask.state;
|
|
24
|
-
return cloneTask;
|
|
25
|
-
}
|
|
26
|
-
const isConfigurablePresent = (config) => typeof config === "object" &&
|
|
27
|
-
config != null &&
|
|
28
|
-
"configurable" in config &&
|
|
29
|
-
typeof config.configurable === "object" &&
|
|
30
|
-
config.configurable != null;
|
|
31
|
-
const deleteInternalConfigurableFields = (config) => {
|
|
32
|
-
if (isConfigurablePresent(config)) {
|
|
33
|
-
const newConfig = {
|
|
34
|
-
...config,
|
|
35
|
-
configurable: Object.fromEntries(Object.entries(config.configurable).filter(([key]) => !key.startsWith("__"))),
|
|
36
|
-
};
|
|
37
|
-
delete newConfig.callbacks;
|
|
38
|
-
return newConfig;
|
|
39
|
-
}
|
|
40
|
-
return config;
|
|
41
|
-
};
|
|
42
|
-
function preprocessDebugCheckpoint(payload) {
|
|
43
|
-
const result = {
|
|
44
|
-
...payload,
|
|
45
|
-
checkpoint: runnableConfigToCheckpoint(payload["config"]),
|
|
46
|
-
parent_checkpoint: runnableConfigToCheckpoint(payload["parentConfig"]),
|
|
47
|
-
tasks: payload["tasks"].map(preprocessDebugCheckpointTask),
|
|
48
|
-
};
|
|
49
|
-
// Handle LangGraph JS pascalCase vs snake_case
|
|
50
|
-
// TODO: use stream to LangGraph.JS
|
|
51
|
-
result.parent_config = payload["parentConfig"];
|
|
52
|
-
delete result.parentConfig;
|
|
53
|
-
result.config = deleteInternalConfigurableFields(result.config);
|
|
54
|
-
result.parent_config = deleteInternalConfigurableFields(result.parent_config);
|
|
55
|
-
return result;
|
|
56
|
-
}
|
|
57
|
-
let LANGGRAPH_VERSION;
|
|
58
|
-
export async function* streamState(run, options) {
|
|
59
|
-
const kwargs = run.kwargs;
|
|
60
|
-
const graphId = kwargs.config?.configurable?.graph_id;
|
|
61
|
-
if (!graphId || typeof graphId !== "string") {
|
|
62
|
-
throw new Error("Invalid or missing graph_id");
|
|
63
|
-
}
|
|
64
|
-
const graph = await options.getGraph(graphId, kwargs.config, {
|
|
65
|
-
checkpointer: kwargs.temporary ? null : undefined,
|
|
66
|
-
});
|
|
67
|
-
// Only v2 protocol entrypoints opt into `streamStateV2`.
|
|
68
|
-
// Legacy run/stream endpoints stay on the existing `streamEvents`
|
|
69
|
-
// path even if a graph defines stream transformers, so they do not
|
|
70
|
-
// emit protocol-framed events on non-protocol transports.
|
|
71
|
-
const isProtocolV2Run = kwargs[PROTOCOL_STREAM_RUN_KEY] === true;
|
|
72
|
-
if (isProtocolV2Run) {
|
|
73
|
-
yield* streamStateV2(run, { ...options, graph });
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const userStreamMode = kwargs.stream_mode ?? [];
|
|
77
|
-
const libStreamMode = new Set(userStreamMode.filter((mode) => mode !== "events" && mode !== "messages-tuple") ?? []);
|
|
78
|
-
if (userStreamMode.includes("messages-tuple")) {
|
|
79
|
-
libStreamMode.add("messages");
|
|
80
|
-
}
|
|
81
|
-
if (userStreamMode.includes("messages")) {
|
|
82
|
-
libStreamMode.add("values");
|
|
83
|
-
}
|
|
84
|
-
if (!libStreamMode.has("debug"))
|
|
85
|
-
libStreamMode.add("debug");
|
|
86
|
-
yield {
|
|
87
|
-
event: "metadata",
|
|
88
|
-
data: { run_id: run.run_id, attempt: options.attempt },
|
|
89
|
-
};
|
|
90
|
-
if (!LANGGRAPH_VERSION) {
|
|
91
|
-
const version = await checkLangGraphSemver();
|
|
92
|
-
LANGGRAPH_VERSION = version.find((v) => v.name === "@langchain/langgraph");
|
|
93
|
-
}
|
|
94
|
-
const metadata = {
|
|
95
|
-
...kwargs.config?.metadata,
|
|
96
|
-
run_attempt: options.attempt,
|
|
97
|
-
langgraph_version: LANGGRAPH_VERSION?.version ?? "0.0.0",
|
|
98
|
-
langgraph_plan: "developer",
|
|
99
|
-
langgraph_host: "self-hosted",
|
|
100
|
-
langgraph_api_url: process.env.LANGGRAPH_API_URL ?? undefined,
|
|
101
|
-
};
|
|
102
|
-
const tracer = run.kwargs?.config?.configurable?.langsmith_project
|
|
103
|
-
? new LangChainTracer({
|
|
104
|
-
replicas: [
|
|
105
|
-
[
|
|
106
|
-
run.kwargs?.config?.configurable?.langsmith_project,
|
|
107
|
-
{
|
|
108
|
-
reference_example_id: run.kwargs?.config?.configurable?.langsmith_example_id,
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
[getDefaultProjectName(), undefined],
|
|
112
|
-
],
|
|
113
|
-
})
|
|
114
|
-
: undefined;
|
|
115
|
-
const events = graph.streamEvents(kwargs.command != null
|
|
116
|
-
? getLangGraphCommand(kwargs.command)
|
|
117
|
-
: (kwargs.input ?? null), {
|
|
118
|
-
version: "v2",
|
|
119
|
-
interruptAfter: kwargs.interrupt_after,
|
|
120
|
-
interruptBefore: kwargs.interrupt_before,
|
|
121
|
-
tags: kwargs.config?.tags,
|
|
122
|
-
context: kwargs.context,
|
|
123
|
-
configurable: kwargs.config?.configurable,
|
|
124
|
-
recursionLimit: kwargs.config?.recursion_limit,
|
|
125
|
-
subgraphs: kwargs.subgraphs,
|
|
126
|
-
metadata,
|
|
127
|
-
runId: run.run_id,
|
|
128
|
-
streamMode: [...libStreamMode],
|
|
129
|
-
signal: options?.signal,
|
|
130
|
-
...(tracer && { callbacks: [tracer] }),
|
|
131
|
-
});
|
|
132
|
-
const messages = {};
|
|
133
|
-
const completedIds = new Set();
|
|
134
|
-
for await (const event of events) {
|
|
135
|
-
if (event.tags?.includes("langsmith:hidden"))
|
|
136
|
-
continue;
|
|
137
|
-
if (event.event === "on_chain_stream" &&
|
|
138
|
-
(kwargs.subgraphs || event.run_id === run.run_id)) {
|
|
139
|
-
// Pregel's stream tuple is `[ns, mode, payload, meta?]` (4th element
|
|
140
|
-
// is the optional `StreamChunkMeta`, preserved when streaming with
|
|
141
|
-
// `subgraphs: true`). The meta carries the lightweight checkpoint
|
|
142
|
-
// envelope attached by `_emitValuesWithCheckpointMeta`, which we
|
|
143
|
-
// forward as a companion `checkpoints` source event below.
|
|
144
|
-
const rawTuple = (kwargs.subgraphs ? event.data.chunk : [null, ...event.data.chunk]);
|
|
145
|
-
const [ns, mode, chunk] = rawTuple;
|
|
146
|
-
const chunkMeta = rawTuple[3];
|
|
147
|
-
let data = chunk;
|
|
148
|
-
if (mode === "debug") {
|
|
149
|
-
const debugChunk = chunk;
|
|
150
|
-
if (debugChunk.type === "checkpoint") {
|
|
151
|
-
const debugCheckpoint = preprocessDebugCheckpoint(debugChunk.payload);
|
|
152
|
-
options?.onCheckpoint?.(debugCheckpoint);
|
|
153
|
-
data = { ...debugChunk, payload: debugCheckpoint };
|
|
154
|
-
}
|
|
155
|
-
else if (debugChunk.type === "task_result") {
|
|
156
|
-
const debugResult = preprocessDebugCheckpointTask(debugChunk.payload);
|
|
157
|
-
options?.onTaskResult?.(debugResult);
|
|
158
|
-
data = { ...debugChunk, payload: debugResult };
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else if (mode === "checkpoints") {
|
|
162
|
-
const debugCheckpoint = preprocessDebugCheckpoint(chunk);
|
|
163
|
-
options?.onCheckpoint?.(debugCheckpoint);
|
|
164
|
-
data = debugCheckpoint;
|
|
165
|
-
}
|
|
166
|
-
else if (mode === "tasks") {
|
|
167
|
-
const debugTask = preprocessDebugCheckpointTask(chunk);
|
|
168
|
-
if ("result" in debugTask || "error" in debugTask) {
|
|
169
|
-
options?.onTaskResult?.(debugTask);
|
|
170
|
-
}
|
|
171
|
-
data = debugTask;
|
|
172
|
-
}
|
|
173
|
-
// Emit the lightweight checkpoint envelope as a dedicated
|
|
174
|
-
// `checkpoints` source event immediately BEFORE the companion
|
|
175
|
-
// `values` event so clients subscribed to both channels have the
|
|
176
|
-
// envelope buffered by the time the values payload arrives
|
|
177
|
-
// (`useMessageMetadata(msg.id).parentCheckpointId` for fork /
|
|
178
|
-
// edit flows). Clients that only want fork / time-travel metadata
|
|
179
|
-
// subscribe to `checkpoints` alone and avoid the full-state
|
|
180
|
-
// payload.
|
|
181
|
-
if (mode === "values" && chunkMeta?.checkpoint != null) {
|
|
182
|
-
const sseEvent = kwargs.subgraphs && ns?.length
|
|
183
|
-
? `checkpoints|${ns.join("|")}`
|
|
184
|
-
: "checkpoints";
|
|
185
|
-
yield { event: sseEvent, data: chunkMeta.checkpoint };
|
|
186
|
-
}
|
|
187
|
-
if (mode === "messages") {
|
|
188
|
-
if (userStreamMode.includes("messages-tuple")) {
|
|
189
|
-
if (kwargs.subgraphs && ns?.length) {
|
|
190
|
-
yield { event: `messages|${ns.join("|")}`, data };
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
yield { event: "messages", data };
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
else if (userStreamMode.includes(mode)) {
|
|
198
|
-
const sseEvent = kwargs.subgraphs && ns?.length ? `${mode}|${ns.join("|")}` : mode;
|
|
199
|
-
yield { event: sseEvent, data };
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
else if (userStreamMode.includes("events")) {
|
|
203
|
-
yield { event: "events", data: event };
|
|
204
|
-
}
|
|
205
|
-
// TODO: we still rely on old messages mode based of streamMode=values
|
|
206
|
-
// In order to fully switch to library messages mode, we need to do ensure that
|
|
207
|
-
// `StreamMessagesHandler` sends the final message, which requires the following:
|
|
208
|
-
// - handleLLMEnd does not send the final message b/c handleLLMNewToken sets the this.emittedChatModelRunIds[runId] flag. Python does not do that
|
|
209
|
-
// - handleLLMEnd receives the final message as BaseMessageChunk rather than BaseMessage, which from the outside will become indistinguishable.
|
|
210
|
-
// - handleLLMEnd should not dedupe the message
|
|
211
|
-
// - Don't think there's an utility that would convert a BaseMessageChunk to a BaseMessage?
|
|
212
|
-
if (userStreamMode.includes("messages")) {
|
|
213
|
-
if (event.event === "on_chain_stream" &&
|
|
214
|
-
(kwargs.subgraphs || event.run_id === run.run_id)) {
|
|
215
|
-
const newMessages = [];
|
|
216
|
-
const [_, chunk] = event.data.chunk;
|
|
217
|
-
let chunkMessages = [];
|
|
218
|
-
if (typeof chunk === "object" &&
|
|
219
|
-
chunk != null &&
|
|
220
|
-
"messages" in chunk &&
|
|
221
|
-
!isBaseMessage(chunk)) {
|
|
222
|
-
chunkMessages = chunk?.messages;
|
|
223
|
-
}
|
|
224
|
-
if (!Array.isArray(chunkMessages)) {
|
|
225
|
-
chunkMessages = [chunkMessages];
|
|
226
|
-
}
|
|
227
|
-
for (const message of chunkMessages) {
|
|
228
|
-
if (!message.id || completedIds.has(message.id))
|
|
229
|
-
continue;
|
|
230
|
-
completedIds.add(message.id);
|
|
231
|
-
newMessages.push(message);
|
|
232
|
-
}
|
|
233
|
-
if (newMessages.length > 0) {
|
|
234
|
-
yield { event: "messages/complete", data: newMessages };
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
else if (event.event === "on_chat_model_stream" &&
|
|
238
|
-
!event.tags?.includes("nostream")) {
|
|
239
|
-
const message = event.data.chunk;
|
|
240
|
-
if (!message.id)
|
|
241
|
-
continue;
|
|
242
|
-
if (messages[message.id] == null) {
|
|
243
|
-
messages[message.id] = message;
|
|
244
|
-
yield {
|
|
245
|
-
event: "messages/metadata",
|
|
246
|
-
data: { [message.id]: { metadata: event.metadata } },
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
messages[message.id] = messages[message.id].concat(message);
|
|
251
|
-
}
|
|
252
|
-
yield { event: "messages/partial", data: [messages[message.id]] };
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
if (kwargs.feedback_keys) {
|
|
257
|
-
const client = new LangSmithClient();
|
|
258
|
-
const data = Object.fromEntries(await Promise.all(kwargs.feedback_keys.map(async (feedback) => {
|
|
259
|
-
const { url } = await client.createPresignedFeedbackToken(run.run_id, feedback);
|
|
260
|
-
return [feedback, url];
|
|
261
|
-
})));
|
|
262
|
-
yield { event: "feedback", data };
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
function isUnsupportedStreamEventsV3Error(error) {
|
|
266
|
-
return (error instanceof Error &&
|
|
267
|
-
error.message.includes('Only versions "v1" and "v2" of the schema are currently supported'));
|
|
268
|
-
}
|
|
269
|
-
async function* fallbackProtocolStreamFromGraphStream(graph, input, options) {
|
|
270
|
-
let seq = 0;
|
|
271
|
-
const stream = await graph.stream(input, options);
|
|
272
|
-
for await (const tuple of stream) {
|
|
273
|
-
const [namespace, mode, payload, meta] = tuple;
|
|
274
|
-
const events = convertToProtocolEvent({
|
|
275
|
-
namespace: namespace ?? [],
|
|
276
|
-
mode,
|
|
277
|
-
payload,
|
|
278
|
-
seq,
|
|
279
|
-
meta: meta,
|
|
280
|
-
});
|
|
281
|
-
seq += events.length;
|
|
282
|
-
for (const event of events) {
|
|
283
|
-
yield event;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Executes a graph run using `graph.streamEvents(..., { version: "v3" })`
|
|
289
|
-
* and maps the resulting `ProtocolEvent` objects into the `{ event, data }`
|
|
290
|
-
* shape consumed by both the legacy SSE path and the protocol v2 session.
|
|
291
|
-
*
|
|
292
|
-
* This path activates graph-level `streamTransformers` (registered via
|
|
293
|
-
* `.compile({ transformers })`) so that custom transformer output flows to
|
|
294
|
-
* clients automatically.
|
|
295
|
-
*
|
|
296
|
-
* @param run - The queued run to execute.
|
|
297
|
-
* @param options - Callbacks and graph-loading infrastructure.
|
|
298
|
-
* @returns Async generator of `{ event, data }` pairs.
|
|
299
|
-
*/
|
|
300
|
-
export async function* streamStateV2(run, options) {
|
|
301
|
-
const kwargs = run.kwargs;
|
|
302
|
-
const graph = options.graph;
|
|
303
|
-
yield {
|
|
304
|
-
event: "metadata",
|
|
305
|
-
data: { run_id: run.run_id, attempt: options.attempt },
|
|
306
|
-
};
|
|
307
|
-
if (!LANGGRAPH_VERSION) {
|
|
308
|
-
const version = await checkLangGraphSemver();
|
|
309
|
-
LANGGRAPH_VERSION = version.find((v) => v.name === "@langchain/langgraph");
|
|
310
|
-
}
|
|
311
|
-
const metadata = {
|
|
312
|
-
...kwargs.config?.metadata,
|
|
313
|
-
run_attempt: options.attempt,
|
|
314
|
-
langgraph_version: LANGGRAPH_VERSION?.version ?? "0.0.0",
|
|
315
|
-
langgraph_plan: "developer",
|
|
316
|
-
langgraph_host: "self-hosted",
|
|
317
|
-
langgraph_api_url: process.env.LANGGRAPH_API_URL ?? undefined,
|
|
318
|
-
};
|
|
319
|
-
const tracer = run.kwargs?.config?.configurable?.langsmith_project
|
|
320
|
-
? new LangChainTracer({
|
|
321
|
-
replicas: [
|
|
322
|
-
[
|
|
323
|
-
run.kwargs?.config?.configurable?.langsmith_project,
|
|
324
|
-
{
|
|
325
|
-
reference_example_id: run.kwargs?.config?.configurable?.langsmith_example_id,
|
|
326
|
-
},
|
|
327
|
-
],
|
|
328
|
-
[getDefaultProjectName(), undefined],
|
|
329
|
-
],
|
|
330
|
-
})
|
|
331
|
-
: undefined;
|
|
332
|
-
const graphInput = kwargs.command != null
|
|
333
|
-
? getLangGraphCommand(kwargs.command)
|
|
334
|
-
: (kwargs.input ?? null);
|
|
335
|
-
const graphOptions = {
|
|
336
|
-
version: "v3",
|
|
337
|
-
interruptAfter: kwargs.interrupt_after,
|
|
338
|
-
interruptBefore: kwargs.interrupt_before,
|
|
339
|
-
tags: kwargs.config?.tags,
|
|
340
|
-
context: kwargs.context,
|
|
341
|
-
configurable: kwargs.config?.configurable,
|
|
342
|
-
recursionLimit: kwargs.config?.recursion_limit,
|
|
343
|
-
metadata: { ls_integration: "langgraph", ...metadata },
|
|
344
|
-
runId: run.run_id,
|
|
345
|
-
signal: options?.signal,
|
|
346
|
-
...(tracer && { callbacks: [tracer] }),
|
|
347
|
-
};
|
|
348
|
-
let graphRun;
|
|
349
|
-
try {
|
|
350
|
-
graphRun = await graph.streamEvents(graphInput, graphOptions);
|
|
351
|
-
}
|
|
352
|
-
catch (error) {
|
|
353
|
-
if (!isUnsupportedStreamEventsV3Error(error)) {
|
|
354
|
-
throw error;
|
|
355
|
-
}
|
|
356
|
-
graphRun = fallbackProtocolStreamFromGraphStream(graph, graphInput, {
|
|
357
|
-
...graphOptions,
|
|
358
|
-
streamMode: STREAM_EVENTS_V3_MODES,
|
|
359
|
-
subgraphs: true,
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
for await (const event of graphRun) {
|
|
363
|
-
const ns = event.params.namespace;
|
|
364
|
-
const mode = event.method;
|
|
365
|
-
const data = event.params.data;
|
|
366
|
-
if (mode === "debug") {
|
|
367
|
-
const debugChunk = data;
|
|
368
|
-
if (debugChunk.type === "checkpoint") {
|
|
369
|
-
const debugCheckpoint = preprocessDebugCheckpoint(debugChunk.payload);
|
|
370
|
-
options?.onCheckpoint?.(debugCheckpoint);
|
|
371
|
-
const sseEvent = ns.length > 0 ? `${mode}|${ns.join("|")}` : mode;
|
|
372
|
-
yield {
|
|
373
|
-
event: sseEvent,
|
|
374
|
-
data: { ...debugChunk, payload: debugCheckpoint },
|
|
375
|
-
};
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
else if (debugChunk.type === "task_result") {
|
|
379
|
-
const debugResult = preprocessDebugCheckpointTask(debugChunk.payload);
|
|
380
|
-
options?.onTaskResult?.(debugResult);
|
|
381
|
-
const sseEvent = ns.length > 0 ? `${mode}|${ns.join("|")}` : mode;
|
|
382
|
-
yield {
|
|
383
|
-
event: sseEvent,
|
|
384
|
-
data: { ...debugChunk, payload: debugResult },
|
|
385
|
-
};
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
else if (mode === "tasks") {
|
|
390
|
-
const debugTask = preprocessDebugCheckpointTask(data);
|
|
391
|
-
if ("result" in debugTask || "error" in debugTask) {
|
|
392
|
-
options?.onTaskResult?.(debugTask);
|
|
393
|
-
}
|
|
394
|
-
const sseEvent = ns.length > 0 ? `${mode}|${ns.join("|")}` : mode;
|
|
395
|
-
yield { event: sseEvent, data: debugTask };
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const sseEvent = ns.length > 0 ? `${mode}|${ns.join("|")}` : mode;
|
|
399
|
-
/**
|
|
400
|
-
* These modes have already been converted to their protocol shape by
|
|
401
|
-
* core's `convertToProtocolEvent`, so the session can skip
|
|
402
|
-
* re-normalization. Other modes (values, debug, tasks) still
|
|
403
|
-
* require API-specific processing (interrupt stripping, state
|
|
404
|
-
* message normalization, checkpoint preprocessing). `checkpoints`
|
|
405
|
-
* is emitted by core as a standalone protocol event whose `data` is
|
|
406
|
-
* already the lightweight envelope; the session frames it on the
|
|
407
|
-
* dedicated `checkpoints` channel. `lifecycle` events are
|
|
408
|
-
* synthesized by core's `LifecycleTransformer` and forwarded
|
|
409
|
-
* verbatim by the session.
|
|
410
|
-
*/
|
|
411
|
-
const normalized = mode === "tools" ||
|
|
412
|
-
mode === "updates" ||
|
|
413
|
-
mode === "custom" ||
|
|
414
|
-
mode === "messages" ||
|
|
415
|
-
mode === "checkpoints" ||
|
|
416
|
-
mode === "lifecycle";
|
|
417
|
-
yield { event: sseEvent, data, normalized };
|
|
418
|
-
}
|
|
419
|
-
if (kwargs.feedback_keys) {
|
|
420
|
-
const client = new LangSmithClient();
|
|
421
|
-
const feedbackData = Object.fromEntries(await Promise.all(kwargs.feedback_keys.map(async (feedback) => {
|
|
422
|
-
const { url } = await client.createPresignedFeedbackToken(run.run_id, feedback);
|
|
423
|
-
return [feedback, url];
|
|
424
|
-
})));
|
|
425
|
-
yield { event: "feedback", data: feedbackData };
|
|
426
|
-
}
|
|
427
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Context } from "hono";
|
|
2
|
-
import { StreamingApi } from "hono/utils/stream";
|
|
3
|
-
export declare function jsonExtra<T>(c: Context, object: T): Response & import("hono").TypedResponse<string, import("hono/utils/http-status").ContentfulStatusCode, "body">;
|
|
4
|
-
export declare function waitKeepAlive(c: Context, promise: Promise<unknown>): Response;
|
|
5
|
-
export declare const getDisconnectAbortSignal: (c: Context, stream: StreamingApi) => AbortSignal;
|
package/dist/src/utils/hono.mjs
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { serialiseAsDict } from "./serde.mjs";
|
|
2
|
-
import { stream } from "hono/streaming";
|
|
3
|
-
export function jsonExtra(c, object) {
|
|
4
|
-
c.header("Content-Type", "application/json");
|
|
5
|
-
return c.body(serialiseAsDict(object));
|
|
6
|
-
}
|
|
7
|
-
export function waitKeepAlive(c, promise) {
|
|
8
|
-
return stream(c, async (stream) => {
|
|
9
|
-
// keep sending newlines until we resolved the chunk
|
|
10
|
-
let keepAlive = Promise.resolve();
|
|
11
|
-
const timer = setInterval(() => {
|
|
12
|
-
keepAlive = keepAlive.then(() => stream.write("\n"));
|
|
13
|
-
}, 1000);
|
|
14
|
-
const result = await promise;
|
|
15
|
-
clearInterval(timer);
|
|
16
|
-
await keepAlive;
|
|
17
|
-
await stream.write(serialiseAsDict(result));
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
export const getDisconnectAbortSignal = (c, stream) => {
|
|
21
|
-
// https://github.com/honojs/hono/issues/1770
|
|
22
|
-
stream.onAbort(() => { });
|
|
23
|
-
return c.req.raw.signal;
|
|
24
|
-
};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { Checkpoint, RunnableConfig } from "../storage/types.mjs";
|
|
2
|
-
export declare const runnableConfigToCheckpoint: (config: RunnableConfig | null | undefined) => Checkpoint | null;
|
|
3
|
-
export declare const taskRunnableConfigToCheckpoint: (config: RunnableConfig | null | undefined) => Partial<Checkpoint> | null;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v3";
|
|
2
|
-
const ConfigSchema = z.object({
|
|
3
|
-
configurable: z.object({
|
|
4
|
-
thread_id: z.string(),
|
|
5
|
-
checkpoint_id: z.string(),
|
|
6
|
-
checkpoint_ns: z.string().nullish(),
|
|
7
|
-
checkpoint_map: z.record(z.string(), z.unknown()).nullish(),
|
|
8
|
-
}),
|
|
9
|
-
});
|
|
10
|
-
export const runnableConfigToCheckpoint = (config) => {
|
|
11
|
-
if (!config || !config.configurable || !config.configurable.thread_id) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
const parsed = ConfigSchema.safeParse(config);
|
|
15
|
-
if (!parsed.success)
|
|
16
|
-
return null;
|
|
17
|
-
return {
|
|
18
|
-
thread_id: parsed.data.configurable.thread_id,
|
|
19
|
-
checkpoint_id: parsed.data.configurable.checkpoint_id,
|
|
20
|
-
checkpoint_ns: parsed.data.configurable.checkpoint_ns || "",
|
|
21
|
-
checkpoint_map: parsed.data.configurable.checkpoint_map || null,
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
const TaskConfigSchema = z.object({
|
|
25
|
-
configurable: z.object({
|
|
26
|
-
thread_id: z.string(),
|
|
27
|
-
checkpoint_id: z.string().nullish(),
|
|
28
|
-
checkpoint_ns: z.string().nullish(),
|
|
29
|
-
checkpoint_map: z.record(z.string(), z.unknown()).nullish(),
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
export const taskRunnableConfigToCheckpoint = (config) => {
|
|
33
|
-
if (!config || !config.configurable || !config.configurable.thread_id) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
const parsed = TaskConfigSchema.safeParse(config);
|
|
37
|
-
if (!parsed.success)
|
|
38
|
-
return null;
|
|
39
|
-
return {
|
|
40
|
-
thread_id: parsed.data.configurable.thread_id,
|
|
41
|
-
checkpoint_id: parsed.data.configurable.checkpoint_id || null,
|
|
42
|
-
checkpoint_ns: parsed.data.configurable.checkpoint_ns || "",
|
|
43
|
-
checkpoint_map: parsed.data.configurable.checkpoint_map || null,
|
|
44
|
-
};
|
|
45
|
-
};
|
package/dist/src/webhook.d.mts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Run } from "./storage/types.mjs";
|
|
2
|
-
import type { StreamCheckpoint } from "./stream.mjs";
|
|
3
|
-
export declare function callWebhook(result: {
|
|
4
|
-
checkpoint: StreamCheckpoint | undefined;
|
|
5
|
-
status: string | undefined;
|
|
6
|
-
exception: Error | undefined;
|
|
7
|
-
run: Run;
|
|
8
|
-
webhook: string;
|
|
9
|
-
run_started_at: Date;
|
|
10
|
-
run_ended_at: Date | undefined;
|
|
11
|
-
}): Promise<void>;
|
package/dist/src/webhook.mjs
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { serializeError } from "./utils/serde.mjs";
|
|
2
|
-
import { getLoopbackFetch } from "./loopback.mjs";
|
|
3
|
-
export async function callWebhook(result) {
|
|
4
|
-
const payload = {
|
|
5
|
-
...result.run,
|
|
6
|
-
status: result.status,
|
|
7
|
-
run_started_at: result.run_started_at.toISOString(),
|
|
8
|
-
run_ended_at: result.run_ended_at?.toISOString(),
|
|
9
|
-
webhook_sent_at: new Date().toISOString(),
|
|
10
|
-
values: result.checkpoint?.values,
|
|
11
|
-
...(result.exception
|
|
12
|
-
? { error: serializeError(result.exception).message }
|
|
13
|
-
: undefined),
|
|
14
|
-
};
|
|
15
|
-
if (result.webhook.startsWith("/")) {
|
|
16
|
-
const fetch = getLoopbackFetch();
|
|
17
|
-
if (!fetch)
|
|
18
|
-
throw new Error("Loopback fetch is not bound");
|
|
19
|
-
await fetch(result.webhook, {
|
|
20
|
-
method: "POST",
|
|
21
|
-
body: JSON.stringify(payload),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
await fetch(result.webhook, {
|
|
26
|
-
method: "POST",
|
|
27
|
-
body: JSON.stringify(payload),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|