@ai-sdk/langchain 3.0.65 → 3.0.67
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/CHANGELOG.md +15 -0
- package/dist/index.js +147 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter.ts +5 -3
- package/src/types.ts +8 -4
- package/src/utils.ts +199 -49
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/langchain",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.67",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"ai": "7.0.
|
|
28
|
+
"ai": "7.0.67"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@langchain/core": "^1.1.46",
|
package/src/adapter.ts
CHANGED
|
@@ -458,14 +458,16 @@ export function toUIMessageStream<TState = unknown>(
|
|
|
458
458
|
messageSeen: new Map(),
|
|
459
459
|
messageNamespaces: new Map(),
|
|
460
460
|
messageConcat: new Map(),
|
|
461
|
+
messageIdsInCurrentStepByNamespace: new Map(),
|
|
461
462
|
emittedToolCalls: new Set<string>(),
|
|
463
|
+
emittedToolCallsInCurrentStepByNamespace: new Map(),
|
|
462
464
|
emittedToolInputs: new Set<string>(),
|
|
465
|
+
emittedToolInputsInCurrentStepByNamespace: new Map(),
|
|
463
466
|
emittedImages: new Set<string>(),
|
|
464
467
|
emittedReasoningIds: new Set<string>(),
|
|
465
468
|
messageReasoningIds: new Map(),
|
|
466
469
|
toolCallInfoByIndex: new Map(),
|
|
467
|
-
|
|
468
|
-
stepNamespace: null,
|
|
470
|
+
currentStepsByNamespace: new Map(),
|
|
469
471
|
emittedToolCallsByKey: new Map<string, string>(),
|
|
470
472
|
emittedSourceIds: new Set<string>(),
|
|
471
473
|
};
|
|
@@ -638,7 +640,7 @@ export function toUIMessageStream<TState = unknown>(
|
|
|
638
640
|
/**
|
|
639
641
|
* Emit finish-step if a step was started
|
|
640
642
|
*/
|
|
641
|
-
if (langGraphState.
|
|
643
|
+
if (langGraphState.currentStepsByNamespace.size > 0) {
|
|
642
644
|
controller.enqueue({ type: 'finish-step' });
|
|
643
645
|
}
|
|
644
646
|
if (sendFinish) {
|
package/src/types.ts
CHANGED
|
@@ -16,10 +16,16 @@ export interface LangGraphEventState {
|
|
|
16
16
|
messageNamespaces: Map<string, string[]>;
|
|
17
17
|
/** Accumulates message chunks for later reference */
|
|
18
18
|
messageConcat: Map<string, AIMessageChunk>;
|
|
19
|
+
/** Tracks message IDs observed in each namespace's current LangGraph step */
|
|
20
|
+
messageIdsInCurrentStepByNamespace: Map<string, Set<string>>;
|
|
19
21
|
/** Tracks which tool call IDs have emitted tool-input-start */
|
|
20
22
|
emittedToolCalls: Set<string>;
|
|
23
|
+
/** Tracks tool-input-start chunks emitted in each namespace's current step */
|
|
24
|
+
emittedToolCallsInCurrentStepByNamespace: Map<string, Set<string>>;
|
|
21
25
|
/** Tracks which tool call IDs have emitted complete tool inputs */
|
|
22
26
|
emittedToolInputs: Set<string>;
|
|
27
|
+
/** Tracks complete tool inputs emitted in each namespace's current step */
|
|
28
|
+
emittedToolInputsInCurrentStepByNamespace: Map<string, Set<string>>;
|
|
23
29
|
/** Maps image IDs to their message IDs (for chunks that don't include the ID) */
|
|
24
30
|
emittedImages: Set<string>;
|
|
25
31
|
/** Maps reasoning block IDs to their message IDs (for chunks that don't include the ID) */
|
|
@@ -28,10 +34,8 @@ export interface LangGraphEventState {
|
|
|
28
34
|
messageReasoningIds: Map<string, string>;
|
|
29
35
|
/** Maps message ID + tool call index to tool call info (for streaming chunks without ID) */
|
|
30
36
|
toolCallInfoByIndex: Map<string, Map<number, { id: string; name: string }>>;
|
|
31
|
-
/** Tracks
|
|
32
|
-
|
|
33
|
-
/** Namespace whose step counter drives the global UI step lifecycle */
|
|
34
|
-
stepNamespace: string | null;
|
|
37
|
+
/** Tracks each namespace's current LangGraph step */
|
|
38
|
+
currentStepsByNamespace: Map<string, number>;
|
|
35
39
|
/** Maps tool call key (name:argsJson) to tool call ID for HITL interrupt handling */
|
|
36
40
|
emittedToolCallsByKey: Map<string, string>;
|
|
37
41
|
/** Tracks source IDs already emitted to avoid duplicates across messages/values events */
|
package/src/utils.ts
CHANGED
|
@@ -1252,10 +1252,89 @@ function getLangGraphNamespaceKey(namespace: string[] | undefined): string {
|
|
|
1252
1252
|
return JSON.stringify(namespace ?? []);
|
|
1253
1253
|
}
|
|
1254
1254
|
|
|
1255
|
+
function getOrCreateNamespaceSet(
|
|
1256
|
+
setsByNamespace: Map<string, Set<string>>,
|
|
1257
|
+
namespace: string,
|
|
1258
|
+
): Set<string> {
|
|
1259
|
+
let values = setsByNamespace.get(namespace);
|
|
1260
|
+
if (!values) {
|
|
1261
|
+
values = new Set();
|
|
1262
|
+
setsByNamespace.set(namespace, values);
|
|
1263
|
+
}
|
|
1264
|
+
return values;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
function hasEmittedToolCallInCurrentStep(
|
|
1268
|
+
state: LangGraphEventState,
|
|
1269
|
+
toolCallId: string,
|
|
1270
|
+
namespace: string,
|
|
1271
|
+
): boolean {
|
|
1272
|
+
return !state.currentStepsByNamespace.has(namespace)
|
|
1273
|
+
? state.emittedToolCalls.has(toolCallId)
|
|
1274
|
+
: state.emittedToolCallsInCurrentStepByNamespace
|
|
1275
|
+
.get(namespace)
|
|
1276
|
+
?.has(toolCallId) === true;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
function markToolCallEmitted(
|
|
1280
|
+
state: LangGraphEventState,
|
|
1281
|
+
toolCallId: string,
|
|
1282
|
+
namespace: string,
|
|
1283
|
+
): void {
|
|
1284
|
+
state.emittedToolCalls.add(toolCallId);
|
|
1285
|
+
if (state.currentStepsByNamespace.has(namespace)) {
|
|
1286
|
+
getOrCreateNamespaceSet(
|
|
1287
|
+
state.emittedToolCallsInCurrentStepByNamespace,
|
|
1288
|
+
namespace,
|
|
1289
|
+
).add(toolCallId);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function hasEmittedToolInputInCurrentStep(
|
|
1294
|
+
state: LangGraphEventState,
|
|
1295
|
+
toolCallId: string,
|
|
1296
|
+
namespace: string,
|
|
1297
|
+
): boolean {
|
|
1298
|
+
return !state.currentStepsByNamespace.has(namespace)
|
|
1299
|
+
? state.emittedToolInputs.has(toolCallId)
|
|
1300
|
+
: state.emittedToolInputsInCurrentStepByNamespace
|
|
1301
|
+
.get(namespace)
|
|
1302
|
+
?.has(toolCallId) === true;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function markToolInputEmitted(
|
|
1306
|
+
state: LangGraphEventState,
|
|
1307
|
+
toolCallId: string,
|
|
1308
|
+
namespace: string,
|
|
1309
|
+
): void {
|
|
1310
|
+
state.emittedToolInputs.add(toolCallId);
|
|
1311
|
+
if (state.currentStepsByNamespace.has(namespace)) {
|
|
1312
|
+
getOrCreateNamespaceSet(
|
|
1313
|
+
state.emittedToolInputsInCurrentStepByNamespace,
|
|
1314
|
+
namespace,
|
|
1315
|
+
).add(toolCallId);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function findMessageCurrentStepNamespace(
|
|
1320
|
+
state: LangGraphEventState,
|
|
1321
|
+
messageId: string,
|
|
1322
|
+
): string | undefined {
|
|
1323
|
+
for (const [
|
|
1324
|
+
namespace,
|
|
1325
|
+
messageIds,
|
|
1326
|
+
] of state.messageIdsInCurrentStepByNamespace) {
|
|
1327
|
+
if (messageIds.has(messageId)) {
|
|
1328
|
+
return namespace;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return undefined;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1255
1334
|
/**
|
|
1256
|
-
* Ends and clears message state for
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1335
|
+
* Ends and clears message state for an advancing namespace. Returns whether
|
|
1336
|
+
* another namespace still has active text or reasoning that would be
|
|
1337
|
+
* invalidated by a global finish-step chunk.
|
|
1259
1338
|
*/
|
|
1260
1339
|
function closeStepNamespaceMessages(
|
|
1261
1340
|
state: LangGraphEventState,
|
|
@@ -1312,7 +1391,6 @@ export function processLangGraphEvent(
|
|
|
1312
1391
|
messageReasoningIds,
|
|
1313
1392
|
toolCallInfoByIndex,
|
|
1314
1393
|
emittedToolCallsByKey,
|
|
1315
|
-
emittedToolInputs,
|
|
1316
1394
|
} = state;
|
|
1317
1395
|
const [rawNamespace, type, data] = parseLangGraphEvent(event);
|
|
1318
1396
|
const namespace =
|
|
@@ -1320,6 +1398,7 @@ export function processLangGraphEvent(
|
|
|
1320
1398
|
rawNamespace.every(segment => typeof segment === 'string')
|
|
1321
1399
|
? rawNamespace
|
|
1322
1400
|
: undefined;
|
|
1401
|
+
const eventNamespace = getLangGraphNamespaceKey(namespace);
|
|
1323
1402
|
controller = createLangGraphNamespaceController(controller, state, namespace);
|
|
1324
1403
|
|
|
1325
1404
|
switch (type) {
|
|
@@ -1373,41 +1452,73 @@ export function processLangGraphEvent(
|
|
|
1373
1452
|
}
|
|
1374
1453
|
|
|
1375
1454
|
/**
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
1380
|
-
*
|
|
1381
|
-
* cursor. A finish-step chunk clears every active UI text/reasoning part,
|
|
1382
|
-
* so suppress the global boundary when another namespace is still active.
|
|
1455
|
+
* Each namespace has an independent LangGraph step counter. Advancing a
|
|
1456
|
+
* namespace starts a new reducer scope so provider-scoped tool call IDs
|
|
1457
|
+
* can be reused in that namespace. A finish-step chunk clears every
|
|
1458
|
+
* active UI text/reasoning part, so omit it when another namespace is
|
|
1459
|
+
* still active.
|
|
1383
1460
|
*/
|
|
1384
1461
|
const langgraphStep =
|
|
1385
1462
|
typeof metadata?.langgraph_step === 'number'
|
|
1386
1463
|
? metadata.langgraph_step
|
|
1387
1464
|
: null;
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1465
|
+
if (langgraphStep !== null) {
|
|
1466
|
+
const currentStep =
|
|
1467
|
+
state.currentStepsByNamespace.get(eventNamespace) ?? null;
|
|
1468
|
+
if (currentStep === null) {
|
|
1469
|
+
if (state.currentStepsByNamespace.size === 0) {
|
|
1470
|
+
controller.enqueue({ type: 'start-step' });
|
|
1471
|
+
}
|
|
1472
|
+
state.currentStepsByNamespace.set(eventNamespace, langgraphStep);
|
|
1473
|
+
state.messageIdsInCurrentStepByNamespace.set(
|
|
1474
|
+
eventNamespace,
|
|
1475
|
+
new Set(),
|
|
1476
|
+
);
|
|
1477
|
+
state.emittedToolCallsInCurrentStepByNamespace.set(
|
|
1478
|
+
eventNamespace,
|
|
1479
|
+
new Set(),
|
|
1480
|
+
);
|
|
1481
|
+
state.emittedToolInputsInCurrentStepByNamespace.set(
|
|
1482
|
+
eventNamespace,
|
|
1483
|
+
new Set(),
|
|
1484
|
+
);
|
|
1485
|
+
} else if (langgraphStep !== currentStep) {
|
|
1398
1486
|
const hasConcurrentMessageParts = closeStepNamespaceMessages(
|
|
1399
1487
|
state,
|
|
1400
|
-
|
|
1488
|
+
eventNamespace,
|
|
1401
1489
|
controller,
|
|
1402
1490
|
);
|
|
1403
1491
|
if (!hasConcurrentMessageParts) {
|
|
1404
1492
|
controller.enqueue({ type: 'finish-step' });
|
|
1405
|
-
controller.enqueue({ type: 'start-step' });
|
|
1406
1493
|
}
|
|
1407
|
-
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* A concurrent namespace prevents finish-step because it would close
|
|
1497
|
+
* that namespace's active text/reasoning parts. Still emit start-step
|
|
1498
|
+
* so tool calls in the advancing namespace have a distinct reducer
|
|
1499
|
+
* scope while the concurrent message lifecycle remains active.
|
|
1500
|
+
*/
|
|
1408
1501
|
controller.enqueue({ type: 'start-step' });
|
|
1502
|
+
state.currentStepsByNamespace.set(eventNamespace, langgraphStep);
|
|
1503
|
+
state.messageIdsInCurrentStepByNamespace.set(
|
|
1504
|
+
eventNamespace,
|
|
1505
|
+
new Set(),
|
|
1506
|
+
);
|
|
1507
|
+
state.emittedToolCallsInCurrentStepByNamespace.set(
|
|
1508
|
+
eventNamespace,
|
|
1509
|
+
new Set(),
|
|
1510
|
+
);
|
|
1511
|
+
state.emittedToolInputsInCurrentStepByNamespace.set(
|
|
1512
|
+
eventNamespace,
|
|
1513
|
+
new Set(),
|
|
1514
|
+
);
|
|
1409
1515
|
}
|
|
1410
|
-
|
|
1516
|
+
}
|
|
1517
|
+
if (state.currentStepsByNamespace.has(eventNamespace)) {
|
|
1518
|
+
getOrCreateNamespaceSet(
|
|
1519
|
+
state.messageIdsInCurrentStepByNamespace,
|
|
1520
|
+
eventNamespace,
|
|
1521
|
+
).add(msgId);
|
|
1411
1522
|
}
|
|
1412
1523
|
|
|
1413
1524
|
/**
|
|
@@ -1533,8 +1644,14 @@ export function processLangGraphEvent(
|
|
|
1533
1644
|
updatedSeen.tool ??= new Set();
|
|
1534
1645
|
updatedSeen.tool.add(toolCallId);
|
|
1535
1646
|
|
|
1536
|
-
if (
|
|
1537
|
-
|
|
1647
|
+
if (
|
|
1648
|
+
!hasEmittedToolCallInCurrentStep(
|
|
1649
|
+
state,
|
|
1650
|
+
toolCallId,
|
|
1651
|
+
eventNamespace,
|
|
1652
|
+
)
|
|
1653
|
+
) {
|
|
1654
|
+
markToolCallEmitted(state, toolCallId, eventNamespace);
|
|
1538
1655
|
controller.enqueue({
|
|
1539
1656
|
type: 'tool-input-start',
|
|
1540
1657
|
toolCallId: toolCallId,
|
|
@@ -1693,9 +1810,19 @@ export function processLangGraphEvent(
|
|
|
1693
1810
|
|
|
1694
1811
|
if (!toolCallId) return;
|
|
1695
1812
|
|
|
1696
|
-
const ensureToolInputLifecycle = (
|
|
1697
|
-
|
|
1698
|
-
|
|
1813
|
+
const ensureToolInputLifecycle = ({
|
|
1814
|
+
allowPreviousStep,
|
|
1815
|
+
}: {
|
|
1816
|
+
allowPreviousStep: boolean;
|
|
1817
|
+
}) => {
|
|
1818
|
+
if (
|
|
1819
|
+
!hasEmittedToolCallInCurrentStep(state, toolCallId, eventNamespace)
|
|
1820
|
+
) {
|
|
1821
|
+
if (allowPreviousStep && emittedToolCalls.has(toolCallId)) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
markToolCallEmitted(state, toolCallId, eventNamespace);
|
|
1699
1826
|
controller.enqueue({
|
|
1700
1827
|
type: 'tool-input-start',
|
|
1701
1828
|
toolCallId,
|
|
@@ -1704,8 +1831,10 @@ export function processLangGraphEvent(
|
|
|
1704
1831
|
});
|
|
1705
1832
|
}
|
|
1706
1833
|
|
|
1707
|
-
if (
|
|
1708
|
-
|
|
1834
|
+
if (
|
|
1835
|
+
!hasEmittedToolInputInCurrentStep(state, toolCallId, eventNamespace)
|
|
1836
|
+
) {
|
|
1837
|
+
markToolInputEmitted(state, toolCallId, eventNamespace);
|
|
1709
1838
|
controller.enqueue({
|
|
1710
1839
|
type: 'tool-input-available',
|
|
1711
1840
|
toolCallId,
|
|
@@ -1721,12 +1850,12 @@ export function processLangGraphEvent(
|
|
|
1721
1850
|
const toolCallKey = `${toolName}:${JSON.stringify(payload.input)}`;
|
|
1722
1851
|
emittedToolCallsByKey.set(toolCallKey, toolCallId);
|
|
1723
1852
|
|
|
1724
|
-
ensureToolInputLifecycle();
|
|
1853
|
+
ensureToolInputLifecycle({ allowPreviousStep: false });
|
|
1725
1854
|
break;
|
|
1726
1855
|
}
|
|
1727
1856
|
|
|
1728
1857
|
case 'on_tool_event': {
|
|
1729
|
-
ensureToolInputLifecycle();
|
|
1858
|
+
ensureToolInputLifecycle({ allowPreviousStep: true });
|
|
1730
1859
|
controller.enqueue({
|
|
1731
1860
|
type: 'tool-output-available',
|
|
1732
1861
|
toolCallId,
|
|
@@ -1737,7 +1866,7 @@ export function processLangGraphEvent(
|
|
|
1737
1866
|
}
|
|
1738
1867
|
|
|
1739
1868
|
case 'on_tool_end': {
|
|
1740
|
-
ensureToolInputLifecycle();
|
|
1869
|
+
ensureToolInputLifecycle({ allowPreviousStep: true });
|
|
1741
1870
|
controller.enqueue({
|
|
1742
1871
|
type: 'tool-output-available',
|
|
1743
1872
|
toolCallId,
|
|
@@ -1747,7 +1876,7 @@ export function processLangGraphEvent(
|
|
|
1747
1876
|
}
|
|
1748
1877
|
|
|
1749
1878
|
case 'on_tool_error': {
|
|
1750
|
-
ensureToolInputLifecycle();
|
|
1879
|
+
ensureToolInputLifecycle({ allowPreviousStep: true });
|
|
1751
1880
|
controller.enqueue({
|
|
1752
1881
|
type: 'tool-output-error',
|
|
1753
1882
|
toolCallId,
|
|
@@ -1765,6 +1894,9 @@ export function processLangGraphEvent(
|
|
|
1765
1894
|
* Finalize all pending message chunks
|
|
1766
1895
|
*/
|
|
1767
1896
|
for (const [id, seen] of messageSeen) {
|
|
1897
|
+
const messageNamespace = getLangGraphNamespaceKey(
|
|
1898
|
+
state.messageNamespaces.get(id),
|
|
1899
|
+
);
|
|
1768
1900
|
if (seen.text) controller.enqueue({ type: 'text-end', id });
|
|
1769
1901
|
if (seen.tool) {
|
|
1770
1902
|
for (const toolCallId of seen.tool) {
|
|
@@ -1774,12 +1906,18 @@ export function processLangGraphEvent(
|
|
|
1774
1906
|
);
|
|
1775
1907
|
|
|
1776
1908
|
if (toolCall) {
|
|
1777
|
-
|
|
1909
|
+
markToolCallEmitted(state, toolCallId, messageNamespace);
|
|
1778
1910
|
// Store mapping for HITL interrupt lookup
|
|
1779
1911
|
const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;
|
|
1780
1912
|
emittedToolCallsByKey.set(toolCallKey, toolCallId);
|
|
1781
|
-
if (
|
|
1782
|
-
|
|
1913
|
+
if (
|
|
1914
|
+
!hasEmittedToolInputInCurrentStep(
|
|
1915
|
+
state,
|
|
1916
|
+
toolCallId,
|
|
1917
|
+
messageNamespace,
|
|
1918
|
+
)
|
|
1919
|
+
) {
|
|
1920
|
+
markToolInputEmitted(state, toolCallId, messageNamespace);
|
|
1783
1921
|
controller.enqueue({
|
|
1784
1922
|
type: 'tool-input-available',
|
|
1785
1923
|
toolCallId,
|
|
@@ -1924,18 +2062,30 @@ export function processLangGraphEvent(
|
|
|
1924
2062
|
|
|
1925
2063
|
if (toolCalls && toolCalls.length > 0) {
|
|
1926
2064
|
for (const toolCall of toolCalls) {
|
|
2065
|
+
const messageNamespace = findMessageCurrentStepNamespace(
|
|
2066
|
+
state,
|
|
2067
|
+
msgId,
|
|
2068
|
+
);
|
|
2069
|
+
const lifecycleNamespace = messageNamespace ?? eventNamespace;
|
|
2070
|
+
const wasObservedInCurrentStep = messageNamespace !== undefined;
|
|
1927
2071
|
/**
|
|
1928
|
-
*
|
|
1929
|
-
*
|
|
1930
|
-
*
|
|
1931
|
-
*
|
|
2072
|
+
* Emit tool calls recovered from a message in the current step,
|
|
2073
|
+
* even when a prior step used the same provider-scoped ID.
|
|
2074
|
+
* Otherwise, preserve stream-wide suppression for historical
|
|
2075
|
+
* completed calls and values-only streams without step metadata.
|
|
1932
2076
|
*/
|
|
1933
2077
|
if (
|
|
1934
2078
|
toolCall.id &&
|
|
1935
|
-
!
|
|
1936
|
-
|
|
2079
|
+
!hasEmittedToolCallInCurrentStep(
|
|
2080
|
+
state,
|
|
2081
|
+
toolCall.id,
|
|
2082
|
+
lifecycleNamespace,
|
|
2083
|
+
) &&
|
|
2084
|
+
(wasObservedInCurrentStep ||
|
|
2085
|
+
(!emittedToolCalls.has(toolCall.id) &&
|
|
2086
|
+
!completedToolCallIds.has(toolCall.id)))
|
|
1937
2087
|
) {
|
|
1938
|
-
|
|
2088
|
+
markToolCallEmitted(state, toolCall.id, lifecycleNamespace);
|
|
1939
2089
|
// Store mapping for HITL interrupt lookup
|
|
1940
2090
|
const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;
|
|
1941
2091
|
emittedToolCallsByKey.set(toolCallKey, toolCall.id);
|
|
@@ -1950,7 +2100,7 @@ export function processLangGraphEvent(
|
|
|
1950
2100
|
toolName: toolCall.name,
|
|
1951
2101
|
dynamic: true,
|
|
1952
2102
|
});
|
|
1953
|
-
|
|
2103
|
+
markToolInputEmitted(state, toolCall.id, lifecycleNamespace);
|
|
1954
2104
|
controller.enqueue({
|
|
1955
2105
|
type: 'tool-input-available',
|
|
1956
2106
|
toolCallId: toolCall.id,
|
|
@@ -2076,7 +2226,7 @@ export function processLangGraphEvent(
|
|
|
2076
2226
|
* so the UI knows what tool is being called with proper lifecycle
|
|
2077
2227
|
*/
|
|
2078
2228
|
if (!emittedToolCalls.has(toolCallId)) {
|
|
2079
|
-
|
|
2229
|
+
markToolCallEmitted(state, toolCallId, eventNamespace);
|
|
2080
2230
|
emittedToolCallsByKey.set(toolCallKey, toolCallId);
|
|
2081
2231
|
controller.enqueue({
|
|
2082
2232
|
type: 'tool-input-start',
|
|
@@ -2084,7 +2234,7 @@ export function processLangGraphEvent(
|
|
|
2084
2234
|
toolName,
|
|
2085
2235
|
dynamic: true,
|
|
2086
2236
|
});
|
|
2087
|
-
|
|
2237
|
+
markToolInputEmitted(state, toolCallId, eventNamespace);
|
|
2088
2238
|
controller.enqueue({
|
|
2089
2239
|
type: 'tool-input-available',
|
|
2090
2240
|
toolCallId,
|