@librechat/agents 3.1.73 → 3.1.75-dev.0
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/README.md +66 -0
- package/dist/cjs/agents/AgentContext.cjs +146 -57
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +13 -3
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +145 -52
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +25 -15
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +84 -70
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +1 -1
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +213 -3
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +2 -1
- package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +5 -4
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +468 -647
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +1 -448
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +57 -175
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +5 -3
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +39 -4
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +7 -6
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +7 -6
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/langchain.cjs +26 -0
- package/dist/cjs/messages/langchain.cjs.map +1 -0
- package/dist/cjs/messages/prune.cjs +7 -6
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +21 -11
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +37 -10
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +16 -11
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +147 -58
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +13 -3
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +146 -54
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +25 -15
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +84 -71
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +1 -1
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +214 -4
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs +2 -1
- package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +5 -4
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +469 -648
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +4 -449
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +57 -175
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +5 -3
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/messages/cache.mjs +39 -4
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +7 -6
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +7 -6
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/langchain.mjs +23 -0
- package/dist/esm/messages/langchain.mjs.map +1 -0
- package/dist/esm/messages/prune.mjs +7 -6
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +22 -12
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +37 -11
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +17 -12
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +29 -4
- package/dist/types/agents/__tests__/promptCacheLiveHelpers.d.ts +46 -0
- package/dist/types/llm/anthropic/index.d.ts +22 -9
- package/dist/types/llm/anthropic/types.d.ts +5 -1
- package/dist/types/llm/anthropic/utils/message_outputs.d.ts +13 -6
- package/dist/types/llm/anthropic/utils/output_parsers.d.ts +1 -1
- package/dist/types/llm/openai/index.d.ts +21 -24
- package/dist/types/llm/openrouter/index.d.ts +11 -9
- package/dist/types/llm/vertexai/index.d.ts +1 -0
- package/dist/types/messages/cache.d.ts +4 -1
- package/dist/types/messages/langchain.d.ts +27 -0
- package/dist/types/tools/CodeExecutor.d.ts +6 -0
- package/dist/types/types/graph.d.ts +26 -38
- package/dist/types/types/llm.d.ts +3 -3
- package/dist/types/types/run.d.ts +2 -0
- package/dist/types/types/stream.d.ts +1 -1
- package/dist/types/types/tools.d.ts +9 -0
- package/package.json +17 -16
- package/src/agents/AgentContext.ts +189 -71
- package/src/agents/__tests__/AgentContext.anthropic.live.test.ts +116 -0
- package/src/agents/__tests__/AgentContext.bedrock.live.test.ts +149 -0
- package/src/agents/__tests__/AgentContext.test.ts +333 -2
- package/src/agents/__tests__/promptCacheLiveHelpers.ts +165 -0
- package/src/graphs/Graph.ts +24 -4
- package/src/graphs/__tests__/composition.smoke.test.ts +188 -0
- package/src/llm/anthropic/index.ts +252 -84
- package/src/llm/anthropic/llm.spec.ts +751 -102
- package/src/llm/anthropic/types.ts +9 -1
- package/src/llm/anthropic/utils/message_inputs.ts +43 -20
- package/src/llm/anthropic/utils/message_outputs.ts +119 -101
- package/src/llm/anthropic/utils/server-tool-inputs.test.ts +77 -0
- package/src/llm/bedrock/index.ts +2 -2
- package/src/llm/bedrock/llm.spec.ts +341 -0
- package/src/llm/bedrock/utils/message_inputs.ts +303 -4
- package/src/llm/bedrock/utils/message_outputs.ts +2 -1
- package/src/llm/custom-chat-models.smoke.test.ts +662 -0
- package/src/llm/google/llm.spec.ts +339 -57
- package/src/llm/google/utils/common.ts +53 -48
- package/src/llm/openai/contentBlocks.test.ts +346 -0
- package/src/llm/openai/index.ts +736 -837
- package/src/llm/openai/utils/index.ts +84 -64
- package/src/llm/openrouter/index.ts +124 -247
- package/src/llm/openrouter/reasoning.test.ts +8 -1
- package/src/llm/vertexai/index.ts +11 -5
- package/src/llm/vertexai/llm.spec.ts +28 -1
- package/src/messages/cache.test.ts +106 -4
- package/src/messages/cache.ts +57 -5
- package/src/messages/core.ts +16 -9
- package/src/messages/format.ts +9 -6
- package/src/messages/langchain.ts +39 -0
- package/src/messages/prune.ts +12 -8
- package/src/scripts/caching.ts +2 -3
- package/src/specs/anthropic.simple.test.ts +61 -0
- package/src/specs/summarization.test.ts +58 -61
- package/src/tools/BashExecutor.ts +37 -13
- package/src/tools/CodeExecutor.ts +55 -11
- package/src/tools/ProgrammaticToolCalling.ts +29 -14
- package/src/tools/ToolNode.ts +5 -1
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +60 -0
- package/src/types/graph.ts +35 -88
- package/src/types/llm.ts +3 -3
- package/src/types/run.ts +2 -0
- package/src/types/stream.ts +1 -1
- package/src/types/tools.ts +9 -0
- package/src/utils/llmConfig.ts +1 -6
|
@@ -3,17 +3,23 @@ import fetch, { RequestInit } from 'node-fetch';
|
|
|
3
3
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
4
4
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
5
5
|
import type * as t from '@/types';
|
|
6
|
-
import {
|
|
6
|
+
import { getCodeBaseURL, renderFileSection } from './CodeExecutor';
|
|
7
7
|
import { Constants } from '@/common';
|
|
8
8
|
|
|
9
9
|
config();
|
|
10
10
|
|
|
11
|
-
const imageMessage = 'Image is already displayed to the user';
|
|
12
11
|
const otherMessage = 'File is already downloaded by the user';
|
|
12
|
+
const inheritedFileMessage =
|
|
13
|
+
'Available as an input — already known to the user';
|
|
13
14
|
const accessMessage =
|
|
14
15
|
'Note: Files from previous executions are automatically available and can be modified.';
|
|
15
16
|
const emptyOutputMessage =
|
|
16
17
|
'stdout: Empty. Ensure you\'re writing output explicitly.\n';
|
|
18
|
+
const inheritedFilesHeader =
|
|
19
|
+
'Available files (inputs, not generated by this execution):';
|
|
20
|
+
const generatedFilesHeader = 'Generated files:';
|
|
21
|
+
const inheritedNote =
|
|
22
|
+
'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
|
|
17
23
|
|
|
18
24
|
const baseEndpoint = getCodeBaseURL();
|
|
19
25
|
const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
|
|
@@ -198,20 +204,38 @@ function createBashExecutionTool(
|
|
|
198
204
|
}
|
|
199
205
|
if (result.stderr) formattedOutput += `stderr:\n${result.stderr}\n`;
|
|
200
206
|
if (result.files && result.files.length > 0) {
|
|
201
|
-
|
|
207
|
+
/* Split inherited (read-only / unchanged-input passthroughs from
|
|
208
|
+
* codeapi) from genuine generated outputs. The LLM was previously
|
|
209
|
+
* shown skill files under "Generated files:" with the message
|
|
210
|
+
* "File is already downloaded by the user", which led it to
|
|
211
|
+
* (a) believe it had just produced files it merely referenced
|
|
212
|
+
* and (b) sometimes invent paths like /mnt/user-data/uploads/
|
|
213
|
+
* trying to find the "originals". Labeling them as inputs makes
|
|
214
|
+
* the mental model accurate. */
|
|
215
|
+
const inheritedFiles = result.files.filter(
|
|
216
|
+
(f) => f.inherited === true
|
|
217
|
+
);
|
|
218
|
+
const generatedFiles = result.files.filter(
|
|
219
|
+
(f) => f.inherited !== true
|
|
220
|
+
);
|
|
202
221
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
222
|
+
formattedOutput += renderFileSection(
|
|
223
|
+
generatedFilesHeader,
|
|
224
|
+
generatedFiles,
|
|
225
|
+
otherMessage
|
|
226
|
+
);
|
|
227
|
+
formattedOutput += renderFileSection(
|
|
228
|
+
inheritedFilesHeader,
|
|
229
|
+
inheritedFiles,
|
|
230
|
+
inheritedFileMessage
|
|
231
|
+
);
|
|
208
232
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
233
|
+
if (generatedFiles.length > 0) {
|
|
234
|
+
formattedOutput += `\n\n${accessMessage}`;
|
|
235
|
+
}
|
|
236
|
+
if (inheritedFiles.length > 0) {
|
|
237
|
+
formattedOutput += `\n\n${inheritedNote}`;
|
|
212
238
|
}
|
|
213
|
-
|
|
214
|
-
formattedOutput += `\n\n${accessMessage}`;
|
|
215
239
|
return [
|
|
216
240
|
formattedOutput.trim(),
|
|
217
241
|
{
|
|
@@ -15,10 +15,41 @@ export const getCodeBaseURL = (): string =>
|
|
|
15
15
|
|
|
16
16
|
const imageMessage = 'Image is already displayed to the user';
|
|
17
17
|
const otherMessage = 'File is already downloaded by the user';
|
|
18
|
+
const inheritedFileMessage =
|
|
19
|
+
'Available as an input — already known to the user';
|
|
18
20
|
const accessMessage =
|
|
19
21
|
'Note: Files from previous executions are automatically available and can be modified.';
|
|
20
22
|
const emptyOutputMessage =
|
|
21
23
|
'stdout: Empty. Ensure you\'re writing output explicitly.\n';
|
|
24
|
+
const inheritedFilesHeader =
|
|
25
|
+
'Available files (inputs, not generated by this execution):';
|
|
26
|
+
const generatedFilesHeader = 'Generated files:';
|
|
27
|
+
const inheritedNote =
|
|
28
|
+
'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Renders one section of the post-execution file listing. Used by the
|
|
32
|
+
* code/bash tool formatters to keep generated outputs and inherited
|
|
33
|
+
* inputs visually separated. See BashExecutor for full docs.
|
|
34
|
+
*/
|
|
35
|
+
export function renderFileSection(
|
|
36
|
+
header: string,
|
|
37
|
+
files: t.FileRefs,
|
|
38
|
+
defaultMessage: string
|
|
39
|
+
): string {
|
|
40
|
+
if (files.length === 0) return '';
|
|
41
|
+
let out = `${header}\n`;
|
|
42
|
+
for (let i = 0; i < files.length; i++) {
|
|
43
|
+
const file = files[i];
|
|
44
|
+
const isImage = imageExtRegex.test(file.name);
|
|
45
|
+
out += `- /mnt/data/${file.name} | ${isImage ? imageMessage : defaultMessage}`;
|
|
46
|
+
if (i < files.length - 1) {
|
|
47
|
+
out += files.length <= 3 ? ', ' : ',\n';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
out += '\n';
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
22
53
|
|
|
23
54
|
const SUPPORTED_LANGUAGES = [
|
|
24
55
|
'py',
|
|
@@ -196,20 +227,33 @@ function createCodeExecutionTool(
|
|
|
196
227
|
}
|
|
197
228
|
if (result.stderr) formattedOutput += `stderr:\n${result.stderr}\n`;
|
|
198
229
|
if (result.files && result.files.length > 0) {
|
|
199
|
-
|
|
230
|
+
/* See BashExecutor for the rationale: split inherited (read-only
|
|
231
|
+
* passthrough) inputs from real generated outputs so the LLM
|
|
232
|
+
* doesn't conflate skill files with newly-produced artifacts. */
|
|
233
|
+
const inheritedFiles = result.files.filter(
|
|
234
|
+
(f) => f.inherited === true
|
|
235
|
+
);
|
|
236
|
+
const generatedFiles = result.files.filter(
|
|
237
|
+
(f) => f.inherited !== true
|
|
238
|
+
);
|
|
200
239
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
240
|
+
formattedOutput += renderFileSection(
|
|
241
|
+
generatedFilesHeader,
|
|
242
|
+
generatedFiles,
|
|
243
|
+
otherMessage
|
|
244
|
+
);
|
|
245
|
+
formattedOutput += renderFileSection(
|
|
246
|
+
inheritedFilesHeader,
|
|
247
|
+
inheritedFiles,
|
|
248
|
+
inheritedFileMessage
|
|
249
|
+
);
|
|
206
250
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
251
|
+
if (generatedFiles.length > 0) {
|
|
252
|
+
formattedOutput += `\n\n${accessMessage}`;
|
|
253
|
+
}
|
|
254
|
+
if (inheritedFiles.length > 0) {
|
|
255
|
+
formattedOutput += `\n\n${inheritedNote}`;
|
|
210
256
|
}
|
|
211
|
-
|
|
212
|
-
formattedOutput += `\n\n${accessMessage}`;
|
|
213
257
|
return [
|
|
214
258
|
formattedOutput.trim(),
|
|
215
259
|
{
|
|
@@ -5,7 +5,7 @@ import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
|
5
5
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
6
6
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
7
7
|
import type * as t from '@/types';
|
|
8
|
-
import {
|
|
8
|
+
import { getCodeBaseURL, renderFileSection } from './CodeExecutor';
|
|
9
9
|
import { Constants } from '@/common';
|
|
10
10
|
|
|
11
11
|
config();
|
|
@@ -14,8 +14,14 @@ config();
|
|
|
14
14
|
// Constants
|
|
15
15
|
// ============================================================================
|
|
16
16
|
|
|
17
|
-
const imageMessage = 'Image is already displayed to the user';
|
|
18
17
|
const otherMessage = 'File is already downloaded by the user';
|
|
18
|
+
const inheritedFileMessage =
|
|
19
|
+
'Available as an input — already known to the user';
|
|
20
|
+
const inheritedFilesHeader =
|
|
21
|
+
'Available files (inputs, not generated by this execution):';
|
|
22
|
+
const generatedFilesHeader = 'Generated files:';
|
|
23
|
+
const inheritedNote =
|
|
24
|
+
'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
|
|
19
25
|
const accessMessage =
|
|
20
26
|
'Note: Files from previous executions are automatically available and can be modified.';
|
|
21
27
|
const emptyOutputMessage =
|
|
@@ -552,20 +558,29 @@ export function formatCompletedResponse(
|
|
|
552
558
|
}
|
|
553
559
|
|
|
554
560
|
if (response.files && response.files.length > 0) {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
561
|
+
/* See BashExecutor for the rationale: split inherited (read-only
|
|
562
|
+
* passthrough) inputs from real generated outputs so the LLM doesn't
|
|
563
|
+
* conflate skill files with newly-produced artifacts. */
|
|
564
|
+
const inheritedFiles = response.files.filter((f) => f.inherited === true);
|
|
565
|
+
const generatedFiles = response.files.filter((f) => f.inherited !== true);
|
|
566
|
+
|
|
567
|
+
formatted += renderFileSection(
|
|
568
|
+
generatedFilesHeader,
|
|
569
|
+
generatedFiles,
|
|
570
|
+
otherMessage
|
|
571
|
+
);
|
|
572
|
+
formatted += renderFileSection(
|
|
573
|
+
inheritedFilesHeader,
|
|
574
|
+
inheritedFiles,
|
|
575
|
+
inheritedFileMessage
|
|
576
|
+
);
|
|
562
577
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
578
|
+
if (generatedFiles.length > 0) {
|
|
579
|
+
formatted += `\n\n${accessMessage}`;
|
|
580
|
+
}
|
|
581
|
+
if (inheritedFiles.length > 0) {
|
|
582
|
+
formatted += `\n\n${inheritedNote}`;
|
|
566
583
|
}
|
|
567
|
-
|
|
568
|
-
formatted += `\n\n${accessMessage}`;
|
|
569
584
|
}
|
|
570
585
|
|
|
571
586
|
return [
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from '@/utils/truncation';
|
|
34
34
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
35
35
|
import { executeHooks } from '@/hooks';
|
|
36
|
+
import { toLangChainContent } from '@/messages/langchain';
|
|
36
37
|
import { Constants, GraphEvents, CODE_EXECUTION_TOOLS } from '@/common';
|
|
37
38
|
import {
|
|
38
39
|
buildReferenceKey,
|
|
@@ -1282,7 +1283,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1282
1283
|
if (msg.skillName != null) additional_kwargs.skillName = msg.skillName;
|
|
1283
1284
|
|
|
1284
1285
|
converted.push(
|
|
1285
|
-
new HumanMessage({
|
|
1286
|
+
new HumanMessage({
|
|
1287
|
+
content: toLangChainContent(msg.content),
|
|
1288
|
+
additional_kwargs,
|
|
1289
|
+
})
|
|
1286
1290
|
);
|
|
1287
1291
|
}
|
|
1288
1292
|
return converted;
|
|
@@ -664,6 +664,66 @@ for member in team:
|
|
|
664
664
|
expect(output).toContain('chart.png');
|
|
665
665
|
expect(output).toContain('Image is already displayed to the user');
|
|
666
666
|
});
|
|
667
|
+
|
|
668
|
+
it('splits inherited inputs from generated outputs into distinct sections', () => {
|
|
669
|
+
const response: t.ProgrammaticExecutionResponse = {
|
|
670
|
+
status: 'completed',
|
|
671
|
+
stdout: 'analysis done\n',
|
|
672
|
+
stderr: '',
|
|
673
|
+
files: [
|
|
674
|
+
{ id: 'g1', name: 'report.pdf' },
|
|
675
|
+
{ id: 'i1', name: 'pptx/SKILL.md', inherited: true },
|
|
676
|
+
{ id: 'i2', name: 'pptx/scripts/clean.py', inherited: true },
|
|
677
|
+
{ id: 'g2', name: 'chart.png' },
|
|
678
|
+
],
|
|
679
|
+
session_id: 'sess_abc123',
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
const [output, artifact] = formatCompletedResponse(response);
|
|
683
|
+
|
|
684
|
+
/* Generated section lists only outputs the run produced. */
|
|
685
|
+
const generatedIdx = output.indexOf('Generated files:');
|
|
686
|
+
const inheritedIdx = output.indexOf('Available files (inputs');
|
|
687
|
+
expect(generatedIdx).toBeGreaterThan(-1);
|
|
688
|
+
expect(inheritedIdx).toBeGreaterThan(generatedIdx);
|
|
689
|
+
|
|
690
|
+
/* Slice each section so we can assert membership without
|
|
691
|
+
* cross-talk between the two listings. */
|
|
692
|
+
const generatedSection = output.slice(generatedIdx, inheritedIdx);
|
|
693
|
+
const inheritedSection = output.slice(inheritedIdx);
|
|
694
|
+
|
|
695
|
+
expect(generatedSection).toContain('report.pdf');
|
|
696
|
+
expect(generatedSection).toContain('chart.png');
|
|
697
|
+
expect(generatedSection).not.toContain('SKILL.md');
|
|
698
|
+
|
|
699
|
+
expect(inheritedSection).toContain('pptx/SKILL.md');
|
|
700
|
+
expect(inheritedSection).toContain('pptx/scripts/clean.py');
|
|
701
|
+
expect(inheritedSection).toContain('Available as an input');
|
|
702
|
+
|
|
703
|
+
/* The artifact still carries every file so the host can still
|
|
704
|
+
* thread per-file ids through to subsequent calls. */
|
|
705
|
+
expect(artifact.files).toHaveLength(4);
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
it('omits the Generated files header when every entry is inherited', () => {
|
|
709
|
+
const response: t.ProgrammaticExecutionResponse = {
|
|
710
|
+
status: 'completed',
|
|
711
|
+
stdout: 'cat: ok\n',
|
|
712
|
+
stderr: '',
|
|
713
|
+
files: [
|
|
714
|
+
{ id: 'i1', name: 'pptx/SKILL.md', inherited: true },
|
|
715
|
+
{ id: 'i2', name: 'pptx/editing.md', inherited: true },
|
|
716
|
+
],
|
|
717
|
+
session_id: 'sess_abc123',
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
const [output] = formatCompletedResponse(response);
|
|
721
|
+
|
|
722
|
+
expect(output).not.toContain('Generated files:');
|
|
723
|
+
expect(output).toContain('Available files (inputs');
|
|
724
|
+
expect(output).toContain('pptx/SKILL.md');
|
|
725
|
+
expect(output).toContain('pptx/editing.md');
|
|
726
|
+
});
|
|
667
727
|
});
|
|
668
728
|
|
|
669
729
|
describe('createProgrammaticToolCallingTool - Manual Invocation', () => {
|
package/src/types/graph.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
// src/types/graph.ts
|
|
2
|
-
import type {
|
|
3
|
-
START,
|
|
4
|
-
StateType,
|
|
5
|
-
UpdateType,
|
|
6
|
-
StateGraph,
|
|
7
|
-
StateGraphArgs,
|
|
8
|
-
StateDefinition,
|
|
9
|
-
CompiledStateGraph,
|
|
10
|
-
BinaryOperatorAggregate,
|
|
11
|
-
} from '@langchain/langgraph';
|
|
2
|
+
import type { START, StateGraph, StateGraphArgs } from '@langchain/langgraph';
|
|
12
3
|
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
|
13
4
|
import type {
|
|
14
5
|
BaseMessage,
|
|
@@ -129,76 +120,40 @@ export type Workflow<
|
|
|
129
120
|
N extends string = string,
|
|
130
121
|
> = StateGraph<T, U, N>;
|
|
131
122
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
U extends Partial<T> = Partial<T>,
|
|
135
|
-
N extends string = string,
|
|
136
|
-
> = CompiledStateGraph<T, U, N>;
|
|
137
|
-
|
|
138
|
-
export type CompiledStateWorkflow = CompiledStateGraph<
|
|
139
|
-
StateType<{
|
|
140
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
141
|
-
}>,
|
|
142
|
-
UpdateType<{
|
|
143
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
144
|
-
}>,
|
|
145
|
-
string,
|
|
146
|
-
{
|
|
147
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
151
|
-
},
|
|
152
|
-
StateDefinition
|
|
123
|
+
type LangChainEventStreamCallbackHandlerInput = NonNullable<
|
|
124
|
+
Parameters<Runnable['streamEvents']>[2]
|
|
153
125
|
>;
|
|
154
126
|
|
|
155
|
-
export type
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
162
|
-
agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
163
|
-
}>,
|
|
164
|
-
string,
|
|
165
|
-
{
|
|
166
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
167
|
-
agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
171
|
-
agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
172
|
-
},
|
|
173
|
-
StateDefinition
|
|
174
|
-
>;
|
|
127
|
+
export type EventStreamCallbackHandlerInput =
|
|
128
|
+
LangChainEventStreamCallbackHandlerInput & {
|
|
129
|
+
autoClose?: boolean;
|
|
130
|
+
raiseError?: boolean;
|
|
131
|
+
ignoreCustomEvent?: boolean;
|
|
132
|
+
};
|
|
175
133
|
|
|
176
|
-
export type
|
|
134
|
+
export type WorkflowValuesStreamConfig = RunnableConfig & {
|
|
135
|
+
streamMode: 'values';
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* LangGraph stream output is mode-dependent (`values`, `updates`, SSE, etc.).
|
|
140
|
+
* Keep the base Runnable stream output as unknown and narrow at callsites that
|
|
141
|
+
* choose a concrete streamMode.
|
|
142
|
+
*/
|
|
143
|
+
export type CompiledWorkflow<
|
|
144
|
+
TInput extends BaseGraphState = BaseGraphState,
|
|
145
|
+
TOutput extends BaseGraphState = TInput,
|
|
146
|
+
> = Omit<Runnable<TInput, unknown>, 'invoke'> & {
|
|
147
|
+
invoke(input: TInput, config?: RunnableConfig): Promise<TOutput>;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export type CompiledStateWorkflow = CompiledWorkflow;
|
|
151
|
+
|
|
152
|
+
export type CompiledMultiAgentWorkflow = CompiledWorkflow<MultiAgentGraphState>;
|
|
153
|
+
|
|
154
|
+
export type CompiledAgentWorfklow = CompiledWorkflow<
|
|
177
155
|
AgentSubgraphState,
|
|
178
|
-
|
|
179
|
-
'__start__' | `agent=${string}` | `tools=${string}` | `summarize=${string}`,
|
|
180
|
-
{
|
|
181
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
182
|
-
summarizationRequest: BinaryOperatorAggregate<
|
|
183
|
-
SummarizationNodeInput | undefined,
|
|
184
|
-
SummarizationNodeInput | undefined
|
|
185
|
-
>;
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
189
|
-
summarizationRequest: BinaryOperatorAggregate<
|
|
190
|
-
SummarizationNodeInput | undefined,
|
|
191
|
-
SummarizationNodeInput | undefined
|
|
192
|
-
>;
|
|
193
|
-
},
|
|
194
|
-
StateDefinition,
|
|
195
|
-
{
|
|
196
|
-
[x: `agent=${string}`]: Partial<BaseGraphState>;
|
|
197
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
198
|
-
[x: `tools=${string}`]: any;
|
|
199
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
200
|
-
[x: `summarize=${string}`]: any;
|
|
201
|
-
}
|
|
156
|
+
AgentSubgraphState
|
|
202
157
|
>;
|
|
203
158
|
|
|
204
159
|
export type SystemRunnable =
|
|
@@ -214,21 +169,11 @@ export type SystemRunnable =
|
|
|
214
169
|
* These are intentionally untyped to avoid coupling to library internals.
|
|
215
170
|
*/
|
|
216
171
|
export type CompileOptions = {
|
|
217
|
-
|
|
218
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
219
|
-
checkpointer?: any;
|
|
172
|
+
checkpointer?: unknown;
|
|
220
173
|
interruptBefore?: string[];
|
|
221
174
|
interruptAfter?: string[];
|
|
222
175
|
};
|
|
223
176
|
|
|
224
|
-
export type EventStreamCallbackHandlerInput =
|
|
225
|
-
Parameters<CompiledWorkflow['streamEvents']>[2] extends Omit<
|
|
226
|
-
infer T,
|
|
227
|
-
'autoClose'
|
|
228
|
-
>
|
|
229
|
-
? T
|
|
230
|
-
: never;
|
|
231
|
-
|
|
232
177
|
export type StreamChunk =
|
|
233
178
|
| (ChatGenerationChunk & {
|
|
234
179
|
message: AIMessageChunk;
|
|
@@ -471,10 +416,12 @@ export interface AgentInputs {
|
|
|
471
416
|
toolMap?: ToolMap;
|
|
472
417
|
tools?: GraphTools;
|
|
473
418
|
provider: Providers;
|
|
419
|
+
/** Stable/cacheable system instructions. */
|
|
474
420
|
instructions?: string;
|
|
475
421
|
streamBuffer?: number;
|
|
476
422
|
maxContextTokens?: number;
|
|
477
423
|
clientOptions?: ClientOptions;
|
|
424
|
+
/** Dynamic system tail appended after stable instructions without provider cache markers. */
|
|
478
425
|
additional_instructions?: string;
|
|
479
426
|
reasoningKey?: 'reasoning_content' | 'reasoning';
|
|
480
427
|
/** Format content blocks as strings (for legacy compatibility i.e. Ollama/Azure Serverless) */
|
|
@@ -500,7 +447,7 @@ export interface AgentInputs {
|
|
|
500
447
|
summarizationEnabled?: boolean;
|
|
501
448
|
summarizationConfig?: SummarizationConfig;
|
|
502
449
|
/** Cross-run summary from a previous run, forwarded from formatAgentMessages.
|
|
503
|
-
* Injected into the system
|
|
450
|
+
* Injected into the dynamic system tail via AgentContext. */
|
|
504
451
|
initialSummary?: { text: string; tokenCount: number };
|
|
505
452
|
contextPruningConfig?: ContextPruningConfig;
|
|
506
453
|
maxToolResultChars?: number;
|
package/src/types/llm.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
} from '@langchain/openai';
|
|
13
13
|
import type { GoogleGenerativeAIChatInput } from '@langchain/google-genai';
|
|
14
14
|
import type { ChatVertexAIInput } from '@langchain/google-vertexai';
|
|
15
|
-
import type {
|
|
15
|
+
import type { ChatDeepSeekInput } from '@langchain/deepseek';
|
|
16
16
|
import type { ChatOpenRouterCallOptions } from '@/llm/openrouter';
|
|
17
17
|
import type { ChatBedrockConverseInput } from '@langchain/aws';
|
|
18
18
|
import type { ChatMistralAIInput } from '@langchain/mistralai';
|
|
@@ -70,7 +70,7 @@ export type AnthropicReasoning = {
|
|
|
70
70
|
export type GoogleThinkingConfig = {
|
|
71
71
|
thinkingBudget?: number;
|
|
72
72
|
includeThoughts?: boolean;
|
|
73
|
-
thinkingLevel?:
|
|
73
|
+
thinkingLevel?: 'THINKING_LEVEL_UNSPECIFIED' | 'LOW' | 'MEDIUM' | 'HIGH';
|
|
74
74
|
};
|
|
75
75
|
export type OpenAIClientOptions = ChatOpenAIFields;
|
|
76
76
|
export type AnthropicClientOptions = Omit<AnthropicInput, 'thinking'> & {
|
|
@@ -93,7 +93,7 @@ export type GoogleClientOptions = GoogleGenerativeAIChatInput & {
|
|
|
93
93
|
customHeaders?: RequestOptions['customHeaders'];
|
|
94
94
|
thinkingConfig?: GoogleThinkingConfig;
|
|
95
95
|
};
|
|
96
|
-
export type DeepSeekClientOptions =
|
|
96
|
+
export type DeepSeekClientOptions = Partial<ChatDeepSeekInput>;
|
|
97
97
|
export type XAIClientOptions = ChatXAIInput;
|
|
98
98
|
|
|
99
99
|
export type ClientOptions =
|
package/src/types/run.ts
CHANGED
|
@@ -75,7 +75,9 @@ export interface AgentStateChannels {
|
|
|
75
75
|
messages: BaseMessage[];
|
|
76
76
|
next: string;
|
|
77
77
|
[key: string]: unknown;
|
|
78
|
+
/** Stable/cacheable system instructions. */
|
|
78
79
|
instructions?: string;
|
|
80
|
+
/** Dynamic system tail appended after stable instructions. */
|
|
79
81
|
additional_instructions?: string;
|
|
80
82
|
}
|
|
81
83
|
|
package/src/types/stream.ts
CHANGED
package/src/types/tools.ts
CHANGED
|
@@ -113,6 +113,15 @@ export type FileRef = {
|
|
|
113
113
|
path?: string;
|
|
114
114
|
/** Session ID this file belongs to (for multi-session file tracking) */
|
|
115
115
|
session_id?: string;
|
|
116
|
+
/**
|
|
117
|
+
* `true` when the codeapi sandbox echoed this entry as an unchanged
|
|
118
|
+
* passthrough of an input the caller already owns (skill files,
|
|
119
|
+
* downloaded inputs whose hash matched the baseline, inherited
|
|
120
|
+
* `.dirkeep` markers). The tool-result formatter renders these as
|
|
121
|
+
* "Available files" rather than "Generated files" so the LLM doesn't
|
|
122
|
+
* conflate infrastructure inputs with newly-produced outputs.
|
|
123
|
+
*/
|
|
124
|
+
inherited?: true;
|
|
116
125
|
};
|
|
117
126
|
|
|
118
127
|
export type FileRefs = FileRef[];
|
package/src/utils/llmConfig.ts
CHANGED
|
@@ -56,9 +56,7 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
|
|
|
56
56
|
provider: Providers.OPENROUTER,
|
|
57
57
|
streaming: true,
|
|
58
58
|
streamUsage: true,
|
|
59
|
-
|
|
60
|
-
// model: 'moonshotai/kimi-k2-thinking',
|
|
61
|
-
model: 'google/gemini-3-pro-preview',
|
|
59
|
+
model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-4o-mini',
|
|
62
60
|
apiKey: process.env.OPENROUTER_API_KEY,
|
|
63
61
|
configuration: {
|
|
64
62
|
baseURL: process.env.OPENROUTER_BASE_URL,
|
|
@@ -67,9 +65,6 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
|
|
|
67
65
|
'X-Title': 'LibreChat',
|
|
68
66
|
},
|
|
69
67
|
},
|
|
70
|
-
reasoning: {
|
|
71
|
-
max_tokens: 8000,
|
|
72
|
-
},
|
|
73
68
|
modelKwargs: {
|
|
74
69
|
max_tokens: 10000,
|
|
75
70
|
},
|