@librechat/agents 3.1.66 → 3.1.67-dev.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/cjs/agents/AgentContext.cjs +23 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +16 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +91 -0
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs +162 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -0
- package/dist/cjs/hooks/executeHooks.cjs +276 -0
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -0
- package/dist/cjs/hooks/matchers.cjs +256 -0
- package/dist/cjs/hooks/matchers.cjs.map +1 -0
- package/dist/cjs/hooks/types.cjs +27 -0
- package/dist/cjs/hooks/types.cjs.map +1 -0
- package/dist/cjs/main.cjs +53 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +74 -12
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +111 -0
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +44 -0
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +175 -0
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -0
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +296 -0
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -0
- package/dist/cjs/tools/ReadFile.cjs +43 -0
- package/dist/cjs/tools/ReadFile.cjs.map +1 -0
- package/dist/cjs/tools/SkillTool.cjs +50 -0
- package/dist/cjs/tools/SkillTool.cjs.map +1 -0
- package/dist/cjs/tools/SubagentTool.cjs +92 -0
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +304 -140
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/skillCatalog.cjs +84 -0
- package/dist/cjs/tools/skillCatalog.cjs.map +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +511 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +23 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +15 -1
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +91 -0
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/hooks/HookRegistry.mjs +160 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -0
- package/dist/esm/hooks/executeHooks.mjs +273 -0
- package/dist/esm/hooks/executeHooks.mjs.map +1 -0
- package/dist/esm/hooks/matchers.mjs +251 -0
- package/dist/esm/hooks/matchers.mjs.map +1 -0
- package/dist/esm/hooks/types.mjs +25 -0
- package/dist/esm/hooks/types.mjs.map +1 -0
- package/dist/esm/main.mjs +12 -1
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +66 -4
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +111 -0
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +44 -0
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +169 -0
- package/dist/esm/tools/BashExecutor.mjs.map +1 -0
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +287 -0
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -0
- package/dist/esm/tools/ReadFile.mjs +38 -0
- package/dist/esm/tools/ReadFile.mjs.map +1 -0
- package/dist/esm/tools/SkillTool.mjs +45 -0
- package/dist/esm/tools/SkillTool.mjs.map +1 -0
- package/dist/esm/tools/SubagentTool.mjs +85 -0
- package/dist/esm/tools/SubagentTool.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +306 -142
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/skillCatalog.mjs +82 -0
- package/dist/esm/tools/skillCatalog.mjs.map +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +505 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -0
- package/dist/types/agents/AgentContext.d.ts +6 -0
- package/dist/types/common/enum.d.ts +10 -1
- package/dist/types/graphs/Graph.d.ts +2 -0
- package/dist/types/hooks/HookRegistry.d.ts +56 -0
- package/dist/types/hooks/executeHooks.d.ts +79 -0
- package/dist/types/hooks/index.d.ts +6 -0
- package/dist/types/hooks/matchers.d.ts +95 -0
- package/dist/types/hooks/types.d.ts +320 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/messages/format.d.ts +2 -1
- package/dist/types/run.d.ts +1 -0
- package/dist/types/summarization/node.d.ts +2 -0
- package/dist/types/tools/BashExecutor.d.ts +45 -0
- package/dist/types/tools/BashProgrammaticToolCalling.d.ts +72 -0
- package/dist/types/tools/ReadFile.d.ts +28 -0
- package/dist/types/tools/SkillTool.d.ts +40 -0
- package/dist/types/tools/SubagentTool.d.ts +36 -0
- package/dist/types/tools/ToolNode.d.ts +24 -2
- package/dist/types/tools/skillCatalog.d.ts +19 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +137 -0
- package/dist/types/tools/subagent/index.d.ts +2 -0
- package/dist/types/types/graph.d.ts +61 -2
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/llm.d.ts +14 -2
- package/dist/types/types/run.d.ts +20 -0
- package/dist/types/types/skill.d.ts +9 -0
- package/dist/types/types/tools.d.ts +38 -1
- package/package.json +5 -1
- package/src/agents/AgentContext.ts +26 -2
- package/src/common/enum.ts +15 -0
- package/src/graphs/Graph.ts +113 -0
- package/src/hooks/HookRegistry.ts +208 -0
- package/src/hooks/__tests__/HookRegistry.test.ts +190 -0
- package/src/hooks/__tests__/compactHooks.test.ts +214 -0
- package/src/hooks/__tests__/executeHooks.test.ts +1013 -0
- package/src/hooks/__tests__/integration.test.ts +337 -0
- package/src/hooks/__tests__/matchers.test.ts +238 -0
- package/src/hooks/__tests__/toolHooks.test.ts +669 -0
- package/src/hooks/executeHooks.ts +375 -0
- package/src/hooks/index.ts +57 -0
- package/src/hooks/matchers.ts +280 -0
- package/src/hooks/types.ts +404 -0
- package/src/index.ts +10 -0
- package/src/messages/format.ts +74 -4
- package/src/messages/formatAgentMessages.skills.test.ts +334 -0
- package/src/run.ts +126 -0
- package/src/scripts/multi-agent-subagent.ts +246 -0
- package/src/scripts/subagent-event-driven-debug.ts +190 -0
- package/src/scripts/subagent-tools-debug.ts +160 -0
- package/src/specs/subagent.test.ts +305 -0
- package/src/summarization/node.ts +53 -0
- package/src/tools/BashExecutor.ts +205 -0
- package/src/tools/BashProgrammaticToolCalling.ts +397 -0
- package/src/tools/ReadFile.ts +39 -0
- package/src/tools/SkillTool.ts +46 -0
- package/src/tools/SubagentTool.ts +100 -0
- package/src/tools/ToolNode.ts +391 -169
- package/src/tools/__tests__/ReadFile.test.ts +44 -0
- package/src/tools/__tests__/SkillTool.test.ts +442 -0
- package/src/tools/__tests__/SubagentExecutor.test.ts +1148 -0
- package/src/tools/__tests__/SubagentTool.test.ts +149 -0
- package/src/tools/__tests__/ToolNode.session.test.ts +12 -12
- package/src/tools/__tests__/skillCatalog.test.ts +161 -0
- package/src/tools/__tests__/subagentHooks.test.ts +215 -0
- package/src/tools/skillCatalog.ts +126 -0
- package/src/tools/subagent/SubagentExecutor.ts +676 -0
- package/src/tools/subagent/index.ts +13 -0
- package/src/types/graph.ts +80 -1
- package/src/types/index.ts +1 -0
- package/src/types/llm.ts +16 -2
- package/src/types/run.ts +20 -0
- package/src/types/skill.ts +11 -0
- package/src/types/tools.ts +41 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// src/hooks/__tests__/compactHooks.test.ts
|
|
2
|
+
import { HumanMessage, AIMessage } from '@langchain/core/messages';
|
|
3
|
+
import { FakeListChatModel } from '@langchain/core/utils/testing';
|
|
4
|
+
import { HookRegistry } from '../HookRegistry';
|
|
5
|
+
import { Run } from '@/run';
|
|
6
|
+
import * as providers from '@/llm/providers';
|
|
7
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
8
|
+
import { createTokenCounter } from '@/utils/tokens';
|
|
9
|
+
import { Providers, GraphEvents } from '@/common';
|
|
10
|
+
import type * as t from '@/types';
|
|
11
|
+
import type {
|
|
12
|
+
HookCallback,
|
|
13
|
+
PreCompactHookInput,
|
|
14
|
+
PreCompactHookOutput,
|
|
15
|
+
PostCompactHookInput,
|
|
16
|
+
PostCompactHookOutput,
|
|
17
|
+
} from '../types';
|
|
18
|
+
|
|
19
|
+
const SUMMARY_RESPONSE = '## Summary\nUser asked a question and got an answer.';
|
|
20
|
+
|
|
21
|
+
const callerConfig = {
|
|
22
|
+
configurable: { thread_id: 'compact-test' },
|
|
23
|
+
streamMode: 'values' as const,
|
|
24
|
+
version: 'v2' as const,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
let getChatModelClassSpy: jest.SpyInstance;
|
|
28
|
+
const originalGetChatModelClass = providers.getChatModelClass;
|
|
29
|
+
|
|
30
|
+
function mockSummarizationModel(): void {
|
|
31
|
+
getChatModelClassSpy = jest
|
|
32
|
+
.spyOn(providers, 'getChatModelClass')
|
|
33
|
+
.mockImplementation(((provider: Providers) => {
|
|
34
|
+
if (provider === Providers.OPENAI) {
|
|
35
|
+
return class extends FakeListChatModel {
|
|
36
|
+
constructor(
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
_options: any
|
|
39
|
+
) {
|
|
40
|
+
super({ responses: [SUMMARY_RESPONSE] });
|
|
41
|
+
}
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
} as any;
|
|
44
|
+
}
|
|
45
|
+
return originalGetChatModelClass(provider);
|
|
46
|
+
}) as typeof providers.getChatModelClass);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function buildConversation(): t.IState {
|
|
50
|
+
const messages: import('@langchain/core/messages').BaseMessage[] = [];
|
|
51
|
+
for (let i = 0; i < 20; i++) {
|
|
52
|
+
messages.push(new HumanMessage(`Question ${i}: ` + 'padding '.repeat(50)));
|
|
53
|
+
messages.push(new AIMessage(`Answer ${i}: ` + 'response '.repeat(50)));
|
|
54
|
+
}
|
|
55
|
+
return { messages };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function createCompactingRun(
|
|
59
|
+
tokenCounter: t.TokenCounter,
|
|
60
|
+
hooks?: HookRegistry,
|
|
61
|
+
runId = 'compact-run'
|
|
62
|
+
): Promise<Run<t.IState>> {
|
|
63
|
+
const conversation = buildConversation();
|
|
64
|
+
const indexTokenCountMap: Record<string, number> = {};
|
|
65
|
+
for (let i = 0; i < conversation.messages.length; i++) {
|
|
66
|
+
indexTokenCountMap[String(i)] = tokenCounter(conversation.messages[i]);
|
|
67
|
+
}
|
|
68
|
+
return Run.create<t.IState>({
|
|
69
|
+
runId,
|
|
70
|
+
graphConfig: {
|
|
71
|
+
type: 'standard',
|
|
72
|
+
llmConfig: {
|
|
73
|
+
provider: Providers.OPENAI,
|
|
74
|
+
streaming: true,
|
|
75
|
+
streamUsage: false,
|
|
76
|
+
},
|
|
77
|
+
instructions: 'Be concise.',
|
|
78
|
+
maxContextTokens: 200,
|
|
79
|
+
summarizationEnabled: true,
|
|
80
|
+
summarizationConfig: {
|
|
81
|
+
provider: Providers.OPENAI,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
returnContent: true,
|
|
85
|
+
skipCleanup: true,
|
|
86
|
+
customHandlers: {
|
|
87
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
88
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
89
|
+
},
|
|
90
|
+
hooks,
|
|
91
|
+
tokenCounter,
|
|
92
|
+
indexTokenCountMap,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe('Compaction hook integration', () => {
|
|
97
|
+
jest.setTimeout(30_000);
|
|
98
|
+
|
|
99
|
+
let tokenCounter: t.TokenCounter;
|
|
100
|
+
|
|
101
|
+
beforeAll(async () => {
|
|
102
|
+
tokenCounter = await createTokenCounter();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
mockSummarizationModel();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
afterEach(() => {
|
|
110
|
+
getChatModelClassSpy.mockRestore();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('PreCompact', () => {
|
|
114
|
+
it('fires with messagesBeforeCount and trigger', async () => {
|
|
115
|
+
const registry = new HookRegistry();
|
|
116
|
+
let captured: PreCompactHookInput | undefined;
|
|
117
|
+
const hook: HookCallback<'PreCompact'> = async (
|
|
118
|
+
input
|
|
119
|
+
): Promise<PreCompactHookOutput> => {
|
|
120
|
+
captured = input;
|
|
121
|
+
return {};
|
|
122
|
+
};
|
|
123
|
+
registry.register('PreCompact', { hooks: [hook] });
|
|
124
|
+
|
|
125
|
+
const run = await createCompactingRun(tokenCounter, registry);
|
|
126
|
+
run.Graph!.overrideTestModel(['Final answer after compaction.']);
|
|
127
|
+
const inputs = buildConversation();
|
|
128
|
+
await run.processStream(inputs, callerConfig);
|
|
129
|
+
|
|
130
|
+
expect(captured).toBeDefined();
|
|
131
|
+
expect(captured!.hook_event_name).toBe('PreCompact');
|
|
132
|
+
expect(captured!.messagesBeforeCount).toBeGreaterThan(0);
|
|
133
|
+
expect(captured!.runId).toBe('compact-run');
|
|
134
|
+
expect(captured!.threadId).toBe('compact-test');
|
|
135
|
+
expect(captured!.trigger).toBe('default');
|
|
136
|
+
expect(captured!.agentId).toBeDefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('PostCompact', () => {
|
|
141
|
+
it('fires with summary text after compaction', async () => {
|
|
142
|
+
const registry = new HookRegistry();
|
|
143
|
+
let captured: PostCompactHookInput | undefined;
|
|
144
|
+
const hook: HookCallback<'PostCompact'> = async (
|
|
145
|
+
input
|
|
146
|
+
): Promise<PostCompactHookOutput> => {
|
|
147
|
+
captured = input;
|
|
148
|
+
return {};
|
|
149
|
+
};
|
|
150
|
+
registry.register('PostCompact', { hooks: [hook] });
|
|
151
|
+
|
|
152
|
+
const run = await createCompactingRun(tokenCounter, registry);
|
|
153
|
+
run.Graph!.overrideTestModel(['Final answer after compaction.']);
|
|
154
|
+
const inputs = buildConversation();
|
|
155
|
+
await run.processStream(inputs, callerConfig);
|
|
156
|
+
|
|
157
|
+
expect(captured).toBeDefined();
|
|
158
|
+
expect(captured!.hook_event_name).toBe('PostCompact');
|
|
159
|
+
expect(captured!.threadId).toBe('compact-test');
|
|
160
|
+
expect(captured!.summary).toBe(SUMMARY_RESPONSE);
|
|
161
|
+
expect(captured!.messagesAfterCount).toBe(0);
|
|
162
|
+
expect(captured!.agentId).toBeDefined();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('error resilience', () => {
|
|
167
|
+
it('throwing PreCompact hook does not crash compaction', async () => {
|
|
168
|
+
const registry = new HookRegistry();
|
|
169
|
+
const throwingHook: HookCallback<
|
|
170
|
+
'PreCompact'
|
|
171
|
+
> = async (): Promise<PreCompactHookOutput> => {
|
|
172
|
+
throw new Error('pre hook crash');
|
|
173
|
+
};
|
|
174
|
+
registry.register('PreCompact', { hooks: [throwingHook] });
|
|
175
|
+
|
|
176
|
+
const run = await createCompactingRun(tokenCounter, registry);
|
|
177
|
+
run.Graph!.overrideTestModel(['Answer after compaction.']);
|
|
178
|
+
const inputs = buildConversation();
|
|
179
|
+
|
|
180
|
+
await expect(
|
|
181
|
+
run.processStream(inputs, callerConfig)
|
|
182
|
+
).resolves.not.toThrow();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('throwing PostCompact hook does not crash compaction', async () => {
|
|
186
|
+
const registry = new HookRegistry();
|
|
187
|
+
const throwingHook: HookCallback<
|
|
188
|
+
'PostCompact'
|
|
189
|
+
> = async (): Promise<PostCompactHookOutput> => {
|
|
190
|
+
throw new Error('post hook crash');
|
|
191
|
+
};
|
|
192
|
+
registry.register('PostCompact', { hooks: [throwingHook] });
|
|
193
|
+
|
|
194
|
+
const run = await createCompactingRun(tokenCounter, registry);
|
|
195
|
+
run.Graph!.overrideTestModel(['Answer after compaction.']);
|
|
196
|
+
const inputs = buildConversation();
|
|
197
|
+
|
|
198
|
+
await expect(
|
|
199
|
+
run.processStream(inputs, callerConfig)
|
|
200
|
+
).resolves.not.toThrow();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe('no-hooks baseline', () => {
|
|
205
|
+
it('summarization works identically without hooks', async () => {
|
|
206
|
+
const run = await createCompactingRun(tokenCounter);
|
|
207
|
+
run.Graph!.overrideTestModel(['Answer.']);
|
|
208
|
+
const inputs = buildConversation();
|
|
209
|
+
const result = await run.processStream(inputs, callerConfig);
|
|
210
|
+
|
|
211
|
+
expect(result).toBeDefined();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|