@librechat/agents 3.1.90 → 3.1.91
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/agents/AgentContext.cjs +9 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +46 -14
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +234 -0
- package/dist/cjs/langfuse.cjs.map +1 -0
- package/dist/cjs/main.cjs +25 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/run.cjs +44 -27
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +10 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +380 -0
- package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +997 -0
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +575 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +165 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -0
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +17 -5
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +110 -6
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +9 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +46 -14
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +226 -0
- package/dist/esm/langfuse.mjs.map +1 -0
- package/dist/esm/main.mjs +5 -1
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/run.mjs +44 -27
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +10 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +378 -0
- package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +994 -0
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +566 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +155 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -0
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +17 -6
- package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +111 -7
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +4 -1
- package/dist/types/graphs/Graph.d.ts +6 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/langfuse.d.ts +48 -0
- package/dist/types/tools/cloudflare/CloudflareBridgeRuntime.d.ts +23 -0
- package/dist/types/tools/cloudflare/CloudflareProgrammaticToolCalling.d.ts +4 -0
- package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +21 -0
- package/dist/types/tools/cloudflare/CloudflareSandboxTools.d.ts +22 -0
- package/dist/types/tools/cloudflare/index.d.ts +4 -0
- package/dist/types/tools/local/LocalExecutionEngine.d.ts +1 -0
- package/dist/types/types/graph.d.ts +8 -0
- package/dist/types/types/tools.d.ts +118 -2
- package/package.json +4 -4
- package/src/__tests__/stream.eagerEventExecution.test.ts +66 -0
- package/src/agents/AgentContext.ts +13 -3
- package/src/graphs/Graph.ts +53 -16
- package/src/index.ts +1 -0
- package/src/langfuse.ts +358 -0
- package/src/run.ts +60 -38
- package/src/specs/langfuse-config.test.ts +57 -0
- package/src/specs/langfuse-metadata.test.ts +19 -1
- package/src/stream.ts +13 -3
- package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +537 -0
- package/src/tools/cloudflare/CloudflareBridgeRuntime.ts +480 -0
- package/src/tools/cloudflare/CloudflareProgrammaticToolCalling.ts +1162 -0
- package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +744 -0
- package/src/tools/cloudflare/CloudflareSandboxTools.ts +225 -0
- package/src/tools/cloudflare/index.ts +4 -0
- package/src/tools/local/LocalExecutionEngine.ts +20 -4
- package/src/tools/local/resolveLocalExecutionTools.ts +169 -7
- package/src/types/graph.ts +9 -0
- package/src/types/tools.ts +141 -2
package/src/run.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/run.ts
|
|
2
2
|
import './instrumentation';
|
|
3
|
-
import { CallbackHandler } from '@langfuse/langchain';
|
|
4
3
|
import { PromptTemplate } from '@langchain/core/prompts';
|
|
5
4
|
import { RunnableLambda } from '@langchain/core/runnables';
|
|
6
5
|
import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
|
|
@@ -31,7 +30,14 @@ import { initializeModel } from '@/llm/init';
|
|
|
31
30
|
import { HandlerRegistry } from '@/events';
|
|
32
31
|
import { executeHooks } from '@/hooks';
|
|
33
32
|
import { isOpenAILike } from '@/utils/llm';
|
|
34
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
createLegacyLangfuseHandler,
|
|
35
|
+
createLangfuseHandler,
|
|
36
|
+
disposeLangfuseHandler,
|
|
37
|
+
hasExplicitLangfuseConfig,
|
|
38
|
+
hasLangfuseEnvConfig,
|
|
39
|
+
isLangfuseCallbackHandler,
|
|
40
|
+
} from '@/langfuse';
|
|
35
41
|
import type { HookRegistry } from '@/hooks';
|
|
36
42
|
|
|
37
43
|
export const defaultOmitOptions = new Set([
|
|
@@ -607,9 +613,8 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
607
613
|
.concat(customHandler);
|
|
608
614
|
|
|
609
615
|
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
isPresent(process.env.LANGFUSE_BASE_URL)
|
|
616
|
+
hasLangfuseEnvConfig() &&
|
|
617
|
+
!hasExplicitLangfuseConfig(this.Graph.agentContexts.values())
|
|
613
618
|
) {
|
|
614
619
|
const userId = config.configurable?.user_id;
|
|
615
620
|
const sessionId = config.configurable?.thread_id;
|
|
@@ -621,7 +626,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
621
626
|
parentMessageId: config.configurable?.requestBody?.parentMessageId,
|
|
622
627
|
agentName: primaryContext?.name,
|
|
623
628
|
};
|
|
624
|
-
const handler =
|
|
629
|
+
const handler = createLegacyLangfuseHandler({
|
|
625
630
|
userId,
|
|
626
631
|
sessionId,
|
|
627
632
|
traceMetadata,
|
|
@@ -1134,12 +1139,8 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1134
1139
|
titleMethod = TitleMethod.COMPLETION,
|
|
1135
1140
|
titlePromptTemplate,
|
|
1136
1141
|
}: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
isPresent(process.env.LANGFUSE_SECRET_KEY) &&
|
|
1140
|
-
isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&
|
|
1141
|
-
isPresent(process.env.LANGFUSE_BASE_URL)
|
|
1142
|
-
) {
|
|
1142
|
+
let titleLangfuseHandler: unknown;
|
|
1143
|
+
if (chainOptions != null) {
|
|
1143
1144
|
const userId = chainOptions.configurable?.user_id;
|
|
1144
1145
|
const sessionId = chainOptions.configurable?.thread_id;
|
|
1145
1146
|
const titleContext = this.Graph?.agentContexts.get(
|
|
@@ -1149,14 +1150,31 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1149
1150
|
messageId: 'title-' + this.id,
|
|
1150
1151
|
agentName: titleContext?.name,
|
|
1151
1152
|
};
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1153
|
+
const hasExplicitLangfuse =
|
|
1154
|
+
this.Graph != null &&
|
|
1155
|
+
hasExplicitLangfuseConfig(this.Graph.agentContexts.values());
|
|
1156
|
+
if (titleContext?.langfuse != null) {
|
|
1157
|
+
titleLangfuseHandler = createLangfuseHandler({
|
|
1158
|
+
langfuse: titleContext.langfuse,
|
|
1159
|
+
userId,
|
|
1160
|
+
sessionId,
|
|
1161
|
+
traceMetadata,
|
|
1162
|
+
});
|
|
1163
|
+
} else if (hasLangfuseEnvConfig() && !hasExplicitLangfuse) {
|
|
1164
|
+
titleLangfuseHandler = createLegacyLangfuseHandler({
|
|
1165
|
+
userId,
|
|
1166
|
+
sessionId,
|
|
1167
|
+
traceMetadata,
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
if (titleLangfuseHandler != null) {
|
|
1172
|
+
chainOptions.callbacks = (
|
|
1173
|
+
(chainOptions.callbacks as t.ProvidedCallbacks) ?? []
|
|
1174
|
+
).concat([
|
|
1175
|
+
titleLangfuseHandler as NonNullable<t.ProvidedCallbacks>[number],
|
|
1176
|
+
]);
|
|
1177
|
+
}
|
|
1160
1178
|
}
|
|
1161
1179
|
|
|
1162
1180
|
const convoTemplate = PromptTemplate.fromTemplate(
|
|
@@ -1221,24 +1239,28 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1221
1239
|
});
|
|
1222
1240
|
|
|
1223
1241
|
try {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
+
try {
|
|
1243
|
+
return await fullChain.invoke(
|
|
1244
|
+
{ input: inputText, output: response },
|
|
1245
|
+
invokeConfig
|
|
1246
|
+
);
|
|
1247
|
+
} catch (_e) {
|
|
1248
|
+
// Fallback: strip callbacks to avoid EventStream tracer errors in certain environments
|
|
1249
|
+
// but preserve Langfuse tracing if it exists.
|
|
1250
|
+
const langfuseHandler = (
|
|
1251
|
+
invokeConfig.callbacks as t.ProvidedCallbacks
|
|
1252
|
+
)?.find(isLangfuseCallbackHandler);
|
|
1253
|
+
const { callbacks: _cb, ...rest } = invokeConfig;
|
|
1254
|
+
const safeConfig = Object.assign({}, rest, {
|
|
1255
|
+
callbacks: langfuseHandler ? [langfuseHandler] : [],
|
|
1256
|
+
});
|
|
1257
|
+
return await fullChain.invoke(
|
|
1258
|
+
{ input: inputText, output: response },
|
|
1259
|
+
safeConfig as Partial<RunnableConfig>
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
} finally {
|
|
1263
|
+
await disposeLangfuseHandler(titleLangfuseHandler);
|
|
1242
1264
|
}
|
|
1243
1265
|
}
|
|
1244
1266
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { LangfuseSpanProcessor } from '@langfuse/otel';
|
|
2
|
+
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
import { createLangfuseHandler } from '@/langfuse';
|
|
4
|
+
|
|
5
|
+
jest.mock('@langfuse/otel', () => ({
|
|
6
|
+
LangfuseSpanProcessor: jest.fn().mockImplementation(() => ({})),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
jest.mock('@opentelemetry/sdk-trace-base', () => ({
|
|
10
|
+
BasicTracerProvider: jest.fn().mockImplementation(() => ({
|
|
11
|
+
forceFlush: jest.fn(),
|
|
12
|
+
getTracer: jest.fn(),
|
|
13
|
+
shutdown: jest.fn(),
|
|
14
|
+
})),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('createLangfuseHandler', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('creates a handler when keys are provided and baseUrl is omitted', () => {
|
|
23
|
+
const handler = createLangfuseHandler({
|
|
24
|
+
langfuse: {
|
|
25
|
+
enabled: true,
|
|
26
|
+
publicKey: 'pk-test',
|
|
27
|
+
secretKey: 'sk-test',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(handler).toBeDefined();
|
|
32
|
+
expect(LangfuseSpanProcessor).toHaveBeenCalledWith(
|
|
33
|
+
expect.objectContaining({
|
|
34
|
+
publicKey: 'pk-test',
|
|
35
|
+
secretKey: 'sk-test',
|
|
36
|
+
exportMode: 'immediate',
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
expect(
|
|
40
|
+
(LangfuseSpanProcessor as jest.Mock).mock.calls[0][0].baseUrl
|
|
41
|
+
).toBeUndefined();
|
|
42
|
+
expect(BasicTracerProvider).toHaveBeenCalledTimes(1);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('does not create a handler when a required key is missing', () => {
|
|
46
|
+
const handler = createLangfuseHandler({
|
|
47
|
+
langfuse: {
|
|
48
|
+
enabled: true,
|
|
49
|
+
publicKey: 'pk-test',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(handler).toBeUndefined();
|
|
54
|
+
expect(LangfuseSpanProcessor).not.toHaveBeenCalled();
|
|
55
|
+
expect(BasicTracerProvider).not.toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -10,7 +10,10 @@ const MockedCallbackHandler = CallbackHandler as jest.MockedClass<
|
|
|
10
10
|
typeof CallbackHandler
|
|
11
11
|
>;
|
|
12
12
|
|
|
13
|
-
async function createTestRun(
|
|
13
|
+
async function createTestRun(
|
|
14
|
+
agentName?: string,
|
|
15
|
+
agentOverrides: Record<string, unknown> = {}
|
|
16
|
+
): Promise<Run<never>> {
|
|
14
17
|
const run = await Run.create({
|
|
15
18
|
runId: 'test-run-id',
|
|
16
19
|
graphConfig: {
|
|
@@ -22,6 +25,7 @@ async function createTestRun(agentName?: string): Promise<Run<never>> {
|
|
|
22
25
|
provider: Providers.OPENAI,
|
|
23
26
|
clientOptions: { model: 'gpt-4' },
|
|
24
27
|
tools: [],
|
|
28
|
+
...agentOverrides,
|
|
25
29
|
},
|
|
26
30
|
],
|
|
27
31
|
},
|
|
@@ -88,4 +92,18 @@ describe('Langfuse trace metadata includes agentName', () => {
|
|
|
88
92
|
|
|
89
93
|
expect(MockedCallbackHandler).not.toHaveBeenCalled();
|
|
90
94
|
});
|
|
95
|
+
|
|
96
|
+
it('does not create the legacy CallbackHandler when explicit agent config is supplied', async () => {
|
|
97
|
+
const run = await createTestRun('DWAINE', {
|
|
98
|
+
langfuse: {
|
|
99
|
+
enabled: false,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
await run.processStream(
|
|
103
|
+
{ messages: [] },
|
|
104
|
+
{ configurable: { thread_id: 't1', user_id: 'u1' }, version: 'v2' }
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(MockedCallbackHandler).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
91
109
|
});
|
package/src/stream.ts
CHANGED
|
@@ -136,10 +136,19 @@ function isDirectGraphTool(
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function isDirectLocalTool(name: string, graph: StandardGraph): boolean {
|
|
139
|
-
|
|
139
|
+
const toolExecution = graph.toolExecution;
|
|
140
|
+
const engine = toolExecution?.engine;
|
|
141
|
+
if (
|
|
142
|
+
toolExecution == null ||
|
|
143
|
+
(engine !== 'local' && engine !== 'cloudflare-sandbox')
|
|
144
|
+
) {
|
|
140
145
|
return false;
|
|
141
146
|
}
|
|
142
|
-
|
|
147
|
+
const includeCodingTools =
|
|
148
|
+
engine === 'cloudflare-sandbox'
|
|
149
|
+
? toolExecution.cloudflare?.includeCodingTools
|
|
150
|
+
: toolExecution.local?.includeCodingTools;
|
|
151
|
+
if (includeCodingTools === false) {
|
|
143
152
|
return CODE_EXECUTION_TOOLS.has(name);
|
|
144
153
|
}
|
|
145
154
|
return LOCAL_CODING_BUNDLE_NAME_SET.has(name);
|
|
@@ -270,7 +279,8 @@ function hasPotentialDirectToolInStreamContext(args: {
|
|
|
270
279
|
agentContext?: AgentContext;
|
|
271
280
|
}): boolean {
|
|
272
281
|
const { graph, agentContext } = args;
|
|
273
|
-
|
|
282
|
+
const engine = graph.toolExecution?.engine;
|
|
283
|
+
if (engine === 'local' || engine === 'cloudflare-sandbox') {
|
|
274
284
|
return true;
|
|
275
285
|
}
|
|
276
286
|
if ((agentContext?.graphTools?.length ?? 0) > 0) {
|