@librechat/agents 3.2.0 → 3.2.2
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/cjs/graphs/Graph.cjs +154 -67
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +3 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +93 -7
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/stream.cjs +10 -8
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +155 -68
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +94 -8
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/stream.mjs +10 -8
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +246 -104
- package/src/graphs/__tests__/Graph.reasoning.test.ts +747 -0
- package/src/index.ts +1 -0
- package/src/messages/core.ts +126 -11
- package/src/messages/formatAgentMessages.test.ts +122 -0
- package/src/specs/deepseek.simple.test.ts +8 -3
- package/src/specs/moonshot.simple.test.ts +8 -3
- package/src/splitStream.test.ts +64 -0
- package/src/stream.ts +12 -10
|
@@ -11,7 +11,7 @@ import { partitionAndMarkAnthropicToolCache, makeIsDeferred } from '../messages/
|
|
|
11
11
|
import { formatContentStrings } from '../messages/content.mjs';
|
|
12
12
|
import { extractToolDiscoveries } from '../messages/tools.mjs';
|
|
13
13
|
import { messagesStateReducer } from '../messages/reducer.mjs';
|
|
14
|
-
import { GraphNodeKeys, ContentTypes, Providers,
|
|
14
|
+
import { GraphNodeKeys, ContentTypes, Providers, GraphEvents, StepTypes } from '../common/enum.mjs';
|
|
15
15
|
import { resetIfNotEmpty, joinKeys } from '../utils/graph.mjs';
|
|
16
16
|
import { isAnthropicLike, isOpenAILike, isGoogleLike } from '../utils/llm.mjs';
|
|
17
17
|
import '../stream.mjs';
|
|
@@ -64,6 +64,112 @@ const CALIBRATION_VARIANCE_THRESHOLD = 0.15;
|
|
|
64
64
|
function getHandlerDispatchedEventKey(eventName, stepId) {
|
|
65
65
|
return `${eventName}:${stepId}`;
|
|
66
66
|
}
|
|
67
|
+
function getReasoningText(value) {
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
return value !== '' ? value : undefined;
|
|
70
|
+
}
|
|
71
|
+
const summaryText = value?.summary
|
|
72
|
+
?.map((summary) => summary.text ?? '')
|
|
73
|
+
.filter((text) => text !== '')
|
|
74
|
+
.join('');
|
|
75
|
+
return summaryText != null && summaryText !== '' ? summaryText : undefined;
|
|
76
|
+
}
|
|
77
|
+
function getReasoningDetailsText(value) {
|
|
78
|
+
if (!Array.isArray(value)) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const reasoningText = value
|
|
82
|
+
.filter((detail) => detail.type === 'reasoning.text')
|
|
83
|
+
.map((detail) => detail.text ?? '')
|
|
84
|
+
.filter((text) => text !== '')
|
|
85
|
+
.join('');
|
|
86
|
+
return reasoningText !== '' ? reasoningText : undefined;
|
|
87
|
+
}
|
|
88
|
+
function getResponseReasoningContent({ responseMessage, reasoningKey, }) {
|
|
89
|
+
const additionalKwargs = responseMessage?.additional_kwargs;
|
|
90
|
+
if (additionalKwargs == null) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const keyedReasoning = getReasoningText(additionalKwargs[reasoningKey]);
|
|
94
|
+
if (keyedReasoning != null) {
|
|
95
|
+
return keyedReasoning;
|
|
96
|
+
}
|
|
97
|
+
const reasoningContent = getReasoningText(additionalKwargs.reasoning_content);
|
|
98
|
+
if (reasoningContent != null) {
|
|
99
|
+
return reasoningContent;
|
|
100
|
+
}
|
|
101
|
+
const reasoning = getReasoningText(additionalKwargs.reasoning);
|
|
102
|
+
if (reasoning != null) {
|
|
103
|
+
return reasoning;
|
|
104
|
+
}
|
|
105
|
+
return getReasoningDetailsText(additionalKwargs.reasoning_details);
|
|
106
|
+
}
|
|
107
|
+
function getTextMessageDeltaContent(content) {
|
|
108
|
+
if (content == null) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
if (typeof content === 'string') {
|
|
112
|
+
return content !== ''
|
|
113
|
+
? [{ type: ContentTypes.TEXT, text: content }]
|
|
114
|
+
: undefined;
|
|
115
|
+
}
|
|
116
|
+
if (content.length === 0) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
if (!content.every((contentPart) => typeof contentPart === 'object' &&
|
|
120
|
+
'type' in contentPart &&
|
|
121
|
+
typeof contentPart.type === 'string' &&
|
|
122
|
+
contentPart.type.startsWith('text'))) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return content;
|
|
126
|
+
}
|
|
127
|
+
async function dispatchTextMessageContent({ graph, stepKey, content, metadata, }) {
|
|
128
|
+
const messageId = getMessageId(stepKey, graph) ?? '';
|
|
129
|
+
if (!messageId) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
await graph.dispatchRunStep(stepKey, {
|
|
133
|
+
type: StepTypes.MESSAGE_CREATION,
|
|
134
|
+
message_creation: { message_id: messageId },
|
|
135
|
+
}, metadata);
|
|
136
|
+
const stepId = graph.getStepIdByKey(stepKey);
|
|
137
|
+
await graph.dispatchMessageDelta(stepId, { content }, metadata);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
async function dispatchReasoningContent({ graph, agentContext, reasoningContent, metadata, }) {
|
|
141
|
+
const previousTokenType = agentContext.currentTokenType;
|
|
142
|
+
const previousTokenTypeSwitch = agentContext.tokenTypeSwitch;
|
|
143
|
+
const previousTransitionCount = agentContext.reasoningTransitionCount;
|
|
144
|
+
agentContext.currentTokenType = ContentTypes.THINK;
|
|
145
|
+
agentContext.tokenTypeSwitch = 'reasoning';
|
|
146
|
+
const stepKey = graph.getStepKey(metadata);
|
|
147
|
+
const messageId = getMessageId(stepKey, graph) ?? '';
|
|
148
|
+
if (!messageId) {
|
|
149
|
+
agentContext.currentTokenType = previousTokenType;
|
|
150
|
+
agentContext.tokenTypeSwitch = previousTokenTypeSwitch;
|
|
151
|
+
agentContext.reasoningTransitionCount = previousTransitionCount;
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
await graph.dispatchRunStep(stepKey, {
|
|
155
|
+
type: StepTypes.MESSAGE_CREATION,
|
|
156
|
+
message_creation: { message_id: messageId },
|
|
157
|
+
}, metadata);
|
|
158
|
+
const stepId = graph.getStepIdByKey(stepKey);
|
|
159
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
160
|
+
content: [{ type: ContentTypes.THINK, think: reasoningContent }],
|
|
161
|
+
}, metadata);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
function markPostReasoningContent(agentContext) {
|
|
165
|
+
if (agentContext.tokenTypeSwitch !== 'reasoning' ||
|
|
166
|
+
agentContext.currentTokenType === ContentTypes.TEXT) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
170
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
171
|
+
agentContext.reasoningTransitionCount++;
|
|
172
|
+
}
|
|
67
173
|
class Graph {
|
|
68
174
|
messageStepHasToolCalls = new Map();
|
|
69
175
|
messageIdsByStepKey = new Map();
|
|
@@ -1072,80 +1178,61 @@ class StandardGraph extends Graph {
|
|
|
1072
1178
|
const toolCalls = responseMessage
|
|
1073
1179
|
?.tool_calls;
|
|
1074
1180
|
const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
|
|
1181
|
+
const metadata = config.metadata;
|
|
1182
|
+
const responseReasoningContent = getResponseReasoningContent({
|
|
1183
|
+
responseMessage: responseMessage,
|
|
1184
|
+
reasoningKey: agentContext.reasoningKey,
|
|
1185
|
+
});
|
|
1186
|
+
const textMessageContent = getTextMessageDeltaContent(responseMessage?.content);
|
|
1075
1187
|
if (hasToolCalls) {
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
if (typeof content === 'string') {
|
|
1097
|
-
await this.dispatchMessageDelta(stepId, {
|
|
1098
|
-
content: [{ type: ContentTypes.TEXT, text: content }],
|
|
1099
|
-
}, metadata);
|
|
1100
|
-
}
|
|
1101
|
-
else if (Array.isArray(content) &&
|
|
1102
|
-
content.every((c) => typeof c === 'object' &&
|
|
1103
|
-
'type' in c &&
|
|
1104
|
-
typeof c.type === 'string' &&
|
|
1105
|
-
c.type.startsWith('text'))) {
|
|
1106
|
-
await this.dispatchMessageDelta(stepId, {
|
|
1107
|
-
content: content,
|
|
1108
|
-
}, metadata);
|
|
1109
|
-
}
|
|
1188
|
+
const dispatchedReasoning = responseReasoningContent != null &&
|
|
1189
|
+
(await dispatchReasoningContent({
|
|
1190
|
+
graph: this,
|
|
1191
|
+
agentContext,
|
|
1192
|
+
reasoningContent: responseReasoningContent,
|
|
1193
|
+
metadata,
|
|
1194
|
+
}));
|
|
1195
|
+
if (dispatchedReasoning) {
|
|
1196
|
+
markPostReasoningContent(agentContext);
|
|
1197
|
+
}
|
|
1198
|
+
if (textMessageContent != null) {
|
|
1199
|
+
const stepKey = this.getStepKey(metadata);
|
|
1200
|
+
const dispatchedText = await dispatchTextMessageContent({
|
|
1201
|
+
graph: this,
|
|
1202
|
+
stepKey,
|
|
1203
|
+
content: textMessageContent,
|
|
1204
|
+
metadata,
|
|
1205
|
+
});
|
|
1206
|
+
if (dispatchedText) {
|
|
1207
|
+
markPostReasoningContent(agentContext);
|
|
1110
1208
|
}
|
|
1111
1209
|
}
|
|
1112
1210
|
await handleToolCalls(toolCalls, metadata, this);
|
|
1113
1211
|
}
|
|
1114
1212
|
/**
|
|
1115
|
-
* When streaming
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1213
|
+
* When streaming events are unavailable, ChatModelStreamHandler never
|
|
1214
|
+
* fires. Dispatch final reasoning/text content here. getMessageId makes
|
|
1215
|
+
* this a no-op when the streaming path already handled the same step.
|
|
1118
1216
|
*/
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}, metadata);
|
|
1139
|
-
}
|
|
1140
|
-
else if (Array.isArray(content) &&
|
|
1141
|
-
content.every((c) => typeof c === 'object' &&
|
|
1142
|
-
'type' in c &&
|
|
1143
|
-
typeof c.type === 'string' &&
|
|
1144
|
-
c.type.startsWith('text'))) {
|
|
1145
|
-
await this.dispatchMessageDelta(stepId, {
|
|
1146
|
-
content: content,
|
|
1147
|
-
}, metadata);
|
|
1148
|
-
}
|
|
1217
|
+
if (!hasToolCalls && responseMessage != null) {
|
|
1218
|
+
const dispatchedReasoning = responseReasoningContent != null &&
|
|
1219
|
+
(await dispatchReasoningContent({
|
|
1220
|
+
graph: this,
|
|
1221
|
+
agentContext,
|
|
1222
|
+
reasoningContent: responseReasoningContent,
|
|
1223
|
+
metadata,
|
|
1224
|
+
}));
|
|
1225
|
+
if (dispatchedReasoning && textMessageContent != null) {
|
|
1226
|
+
markPostReasoningContent(agentContext);
|
|
1227
|
+
}
|
|
1228
|
+
if (textMessageContent != null) {
|
|
1229
|
+
const stepKey = this.getStepKey(metadata);
|
|
1230
|
+
await dispatchTextMessageContent({
|
|
1231
|
+
graph: this,
|
|
1232
|
+
stepKey,
|
|
1233
|
+
content: textMessageContent,
|
|
1234
|
+
metadata,
|
|
1235
|
+
});
|
|
1149
1236
|
}
|
|
1150
1237
|
}
|
|
1151
1238
|
const invokeElapsed = ((Date.now() - invokeStart) / 1000).toFixed(2);
|