@librechat/agents 3.3.10 → 3.3.12
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 +248 -27
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +228 -16
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +13 -2
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +160 -43
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +190 -13
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/streamLimits.cjs +723 -0
- package/dist/cjs/llm/streamLimits.cjs.map +1 -0
- package/dist/cjs/main.cjs +12 -3
- package/dist/cjs/messages/core.cjs +592 -27
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/run.cjs +7 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +4 -1
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/stream.cjs +105 -14
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +157 -37
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +3 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +4 -3
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +5 -3
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +77 -4
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +3 -2
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/search/crw-scraper.cjs +7 -1
- package/dist/cjs/tools/search/crw-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/crw-search.cjs +3 -1
- package/dist/cjs/tools/search/crw-search.cjs.map +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs +7 -1
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs +7 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-search.cjs +3 -1
- package/dist/cjs/tools/search/keenable-search.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +26 -8
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +30 -10
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/serper-scraper.cjs +7 -1
- package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-scraper.cjs +7 -1
- package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-search.cjs +3 -1
- package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +17 -3
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +54 -3
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +2 -1
- package/dist/cjs/utils/misc.cjs +12 -0
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/cjs/utils/proxy.cjs +63 -0
- package/dist/cjs/utils/proxy.cjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +247 -26
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +228 -16
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +13 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +160 -43
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +192 -15
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/streamLimits.mjs +704 -0
- package/dist/esm/llm/streamLimits.mjs.map +1 -0
- package/dist/esm/main.mjs +8 -6
- package/dist/esm/messages/core.mjs +592 -28
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/run.mjs +7 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +4 -1
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/stream.mjs +105 -14
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +157 -37
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -2
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +4 -3
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +5 -3
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +77 -4
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +3 -2
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/search/crw-scraper.mjs +7 -1
- package/dist/esm/tools/search/crw-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/crw-search.mjs +3 -1
- package/dist/esm/tools/search/crw-search.mjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs +7 -1
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-scraper.mjs +7 -1
- package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-search.mjs +3 -1
- package/dist/esm/tools/search/keenable-search.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +26 -8
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +30 -10
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/serper-scraper.mjs +7 -1
- package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-scraper.mjs +7 -1
- package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-search.mjs +3 -1
- package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +17 -3
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +54 -3
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +2 -1
- package/dist/esm/utils/misc.mjs +12 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/esm/utils/proxy.mjs +62 -0
- package/dist/esm/utils/proxy.mjs.map +1 -0
- package/dist/types/graphs/Graph.d.ts +53 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +1 -0
- package/dist/types/llm/invoke.d.ts +26 -5
- package/dist/types/llm/openai/index.d.ts +3 -0
- package/dist/types/llm/streamLimits.d.ts +314 -0
- package/dist/types/messages/core.d.ts +11 -6
- package/dist/types/run.d.ts +1 -0
- package/dist/types/summarization/node.d.ts +27 -2
- package/dist/types/tools/BashExecutor.d.ts +2 -2
- package/dist/types/tools/CodeExecutor.d.ts +3 -3
- package/dist/types/tools/ToolNode.d.ts +11 -1
- package/dist/types/tools/search/crw-scraper.d.ts +2 -0
- package/dist/types/tools/search/firecrawl.d.ts +2 -0
- package/dist/types/tools/search/keenable-scraper.d.ts +2 -0
- package/dist/types/tools/search/rerankers.d.ts +9 -5
- package/dist/types/tools/search/serper-scraper.d.ts +2 -0
- package/dist/types/tools/search/tavily-scraper.d.ts +2 -0
- package/dist/types/tools/search/types.d.ts +28 -33
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +44 -0
- package/dist/types/types/graph.d.ts +7 -1
- package/dist/types/types/run.d.ts +46 -1
- package/dist/types/types/tools.d.ts +21 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/misc.d.ts +7 -0
- package/dist/types/utils/proxy.d.ts +31 -0
- package/package.json +2 -1
- package/src/__tests__/stream.eagerArgsDivergence.test.ts +158 -0
- package/src/__tests__/stream.eagerEventExecution.test.ts +1 -0
- package/src/__tests__/stream.streamLimits.test.ts +1982 -0
- package/src/graphs/Graph.ts +302 -27
- package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +234 -0
- package/src/index.ts +11 -0
- package/src/langfuseToolOutputTracing.ts +410 -14
- package/src/llm/bedrock/index.ts +22 -2
- package/src/llm/custom-chat-models.smoke.test.ts +747 -0
- package/src/llm/invoke.streamLimits.test.ts +142 -0
- package/src/llm/invoke.test.ts +187 -1
- package/src/llm/invoke.ts +231 -43
- package/src/llm/openai/cacheWriteTokens.test.ts +112 -0
- package/src/llm/openai/index.ts +348 -31
- package/src/llm/openai/llm.spec.ts +107 -6
- package/src/llm/streamLimits.test.ts +450 -0
- package/src/llm/streamLimits.ts +1158 -0
- package/src/messages/core.ts +1290 -42
- package/src/messages/formatAgentMessages.test.ts +2623 -0
- package/src/run.ts +4 -0
- package/src/session/AgentSession.ts +5 -0
- package/src/specs/langfuse-tool-output-tracing.test.ts +887 -0
- package/src/specs/preemptSeal.test.ts +374 -5
- package/src/stream.ts +141 -6
- package/src/summarization/__tests__/node.test.ts +269 -0
- package/src/summarization/chunkHandler.test.ts +196 -0
- package/src/summarization/node.ts +203 -6
- package/src/tools/BashExecutor.ts +4 -3
- package/src/tools/CodeExecutor.ts +5 -4
- package/src/tools/ProgrammaticToolCalling.ts +7 -5
- package/src/tools/ToolNode.ts +109 -6
- package/src/tools/ToolSearch.ts +4 -3
- package/src/tools/__tests__/BashExecutor.test.ts +2 -2
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +2 -4
- package/src/tools/__tests__/SubagentExecutor.test.ts +126 -0
- package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +389 -0
- package/src/tools/__tests__/ToolNode.streamLimits.test.ts +69 -0
- package/src/tools/search/crw-scraper.ts +6 -0
- package/src/tools/search/crw-search.ts +6 -1
- package/src/tools/search/firecrawl.ts +6 -0
- package/src/tools/search/http-agent.test.ts +133 -0
- package/src/tools/search/keenable-scraper.ts +6 -0
- package/src/tools/search/keenable-search.ts +6 -1
- package/src/tools/search/rerankers.ts +36 -10
- package/src/tools/search/search.ts +29 -11
- package/src/tools/search/serper-scraper.ts +6 -0
- package/src/tools/search/tavily-scraper.ts +6 -0
- package/src/tools/search/tavily-search.ts +2 -0
- package/src/tools/search/tool.ts +16 -0
- package/src/tools/search/types.ts +31 -33
- package/src/tools/subagent/SubagentExecutor.ts +96 -3
- package/src/types/graph.ts +7 -0
- package/src/types/run.ts +49 -1
- package/src/types/tools.ts +21 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/misc.ts +19 -0
- package/src/utils/proxy.test.ts +176 -0
- package/src/utils/proxy.ts +93 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { describe, it, expect } from '@jest/globals';
|
|
2
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
3
|
+
import type * as t from '@/types';
|
|
4
|
+
import { StreamLimitExceededError } from '@/llm/streamLimits';
|
|
5
|
+
import { Providers } from '@/common';
|
|
6
|
+
import { StandardGraph } from '../Graph';
|
|
7
|
+
|
|
8
|
+
const makeAgent = (agentId: string): t.AgentInputs => ({
|
|
9
|
+
agentId,
|
|
10
|
+
provider: Providers.OPENAI,
|
|
11
|
+
instructions: `You are ${agentId}.`,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const makeGraph = (): StandardGraph =>
|
|
15
|
+
new StandardGraph({
|
|
16
|
+
runId: 'run_1',
|
|
17
|
+
agents: [makeAgent('agent')],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const makeTrip = (): StreamLimitExceededError =>
|
|
21
|
+
new StreamLimitExceededError({
|
|
22
|
+
kind: 'tool_call_args',
|
|
23
|
+
limit: 10,
|
|
24
|
+
observed: 11,
|
|
25
|
+
toolName: 'db_query',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('run breaker lifecycle', () => {
|
|
29
|
+
it('replaces the breaker at every run start, even when un-aborted', () => {
|
|
30
|
+
const graph = makeGraph();
|
|
31
|
+
const previous = graph.breakerAbort;
|
|
32
|
+
expect(previous.signal.aborted).toBe(false);
|
|
33
|
+
|
|
34
|
+
graph.resetValues();
|
|
35
|
+
|
|
36
|
+
expect(graph.breakerAbort).not.toBe(previous);
|
|
37
|
+
/** A straggler from the failed run trips the controller it captured;
|
|
38
|
+
* the run starting now must not observe it. */
|
|
39
|
+
previous.abort(makeTrip());
|
|
40
|
+
expect(graph.breakerAbort.signal.aborted).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('keeps straggler accounting through cleanup and one reset, then sweeps it', () => {
|
|
44
|
+
const graph = makeGraph();
|
|
45
|
+
const epoch = graph.breakerEpoch;
|
|
46
|
+
graph.streamedToolCallArgTallies.set('gen:i:0', { bytes: 42, epoch });
|
|
47
|
+
graph.streamDeltaEventCounts.set('gen', { count: 7, epoch });
|
|
48
|
+
graph.streamLimitChargeCredits = new WeakMap();
|
|
49
|
+
|
|
50
|
+
/** Cleanup runs while sibling attempts can still be unwinding on the
|
|
51
|
+
* retained breaker; clearing here would hand a cancellation-ignoring
|
|
52
|
+
* provider's late chunks a fresh budget. */
|
|
53
|
+
graph.clearHeavyState();
|
|
54
|
+
expect(graph.streamedToolCallArgTallies.get('gen:i:0')?.bytes).toBe(42);
|
|
55
|
+
expect(graph.streamDeltaEventCounts.get('gen')?.count).toBe(7);
|
|
56
|
+
expect(graph.streamLimitChargeCredits).toBeDefined();
|
|
57
|
+
|
|
58
|
+
/** Producer loops of straggling attempts sit OUTSIDE the consumer-only
|
|
59
|
+
* epoch gate, so their entries must survive the next run start too —
|
|
60
|
+
* one grace reset keeps them on their original budgets. */
|
|
61
|
+
graph.resetValues();
|
|
62
|
+
expect(graph.streamedToolCallArgTallies.get('gen:i:0')?.bytes).toBe(42);
|
|
63
|
+
expect(graph.streamDeltaEventCounts.get('gen')?.count).toBe(7);
|
|
64
|
+
expect(graph.streamLimitChargeCredits).toBeUndefined();
|
|
65
|
+
|
|
66
|
+
/** A second reset sweeps entries from older epochs. */
|
|
67
|
+
graph.resetValues();
|
|
68
|
+
expect(graph.streamedToolCallArgTallies.size).toBe(0);
|
|
69
|
+
expect(graph.streamDeltaEventCounts.size).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('holds a leased producer straggler to its budget across two run resets', async () => {
|
|
73
|
+
const { attemptInvoke } = await import('@/llm/invoke');
|
|
74
|
+
const { resolveStreamLimits } = await import('@/llm/streamLimits');
|
|
75
|
+
const { AIMessageChunk, HumanMessage } = await import(
|
|
76
|
+
'@langchain/core/messages'
|
|
77
|
+
);
|
|
78
|
+
const graph = makeGraph();
|
|
79
|
+
graph.streamLimits = resolveStreamLimits({ maxToolCallArgBytes: 100 });
|
|
80
|
+
const chunkOf = (args: string): InstanceType<typeof AIMessageChunk> =>
|
|
81
|
+
new AIMessageChunk({
|
|
82
|
+
content: '',
|
|
83
|
+
tool_call_chunks: [
|
|
84
|
+
{
|
|
85
|
+
type: 'tool_call_chunk',
|
|
86
|
+
id: 'call_1',
|
|
87
|
+
name: 'writer',
|
|
88
|
+
args,
|
|
89
|
+
index: 0,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
let yields = 0;
|
|
94
|
+
const model = {
|
|
95
|
+
stream: async function* (): AsyncGenerator<
|
|
96
|
+
InstanceType<typeof AIMessageChunk>
|
|
97
|
+
> {
|
|
98
|
+
yields += 1;
|
|
99
|
+
yield chunkOf('x'.repeat(60));
|
|
100
|
+
/** Two prompt runs start and reset while this attempt is still
|
|
101
|
+
* draining. Its lease must keep the tally alive — reset counting
|
|
102
|
+
* cannot prove the attempt finished. */
|
|
103
|
+
graph.resetValues();
|
|
104
|
+
graph.resetValues();
|
|
105
|
+
yields += 1;
|
|
106
|
+
yield chunkOf('x'.repeat(60));
|
|
107
|
+
yields += 1;
|
|
108
|
+
yield chunkOf('x');
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
await expect(
|
|
113
|
+
attemptInvoke(
|
|
114
|
+
{
|
|
115
|
+
model: model as unknown as t.ChatModel,
|
|
116
|
+
messages: [new HumanMessage('hi')],
|
|
117
|
+
provider: Providers.OPENAI,
|
|
118
|
+
context: graph as Parameters<
|
|
119
|
+
typeof attemptInvoke
|
|
120
|
+
>[0]['context'],
|
|
121
|
+
onChunk: () => {
|
|
122
|
+
/* producer loop enforcement is under test */
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{ metadata: {} }
|
|
126
|
+
)
|
|
127
|
+
).rejects.toMatchObject({ kind: 'tool_call_args', limit: 100 });
|
|
128
|
+
expect(yields).toBe(2);
|
|
129
|
+
/** The attempt's finally released its lease and entries. */
|
|
130
|
+
expect(graph.activeStreamLimitGenerations?.size ?? 0).toBe(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('takes no attempt lease when every guard is disabled', async () => {
|
|
134
|
+
const { attemptInvoke } = await import('@/llm/invoke');
|
|
135
|
+
const { resolveStreamLimits } = await import('@/llm/streamLimits');
|
|
136
|
+
const { AIMessage, HumanMessage } = await import(
|
|
137
|
+
'@langchain/core/messages'
|
|
138
|
+
);
|
|
139
|
+
const graph = makeGraph();
|
|
140
|
+
graph.streamLimits = resolveStreamLimits({
|
|
141
|
+
maxToolCallArgBytes: 0,
|
|
142
|
+
maxToolCallArgBytesByTool: { writer: 0 },
|
|
143
|
+
});
|
|
144
|
+
const model = {
|
|
145
|
+
invoke: async (): Promise<InstanceType<typeof AIMessage>> =>
|
|
146
|
+
new AIMessage({ content: 'ok' }),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await attemptInvoke(
|
|
150
|
+
{
|
|
151
|
+
model: model as unknown as t.ChatModel,
|
|
152
|
+
messages: [new HumanMessage('hi')],
|
|
153
|
+
provider: Providers.OPENAI,
|
|
154
|
+
context: graph as Parameters<typeof attemptInvoke>[0]['context'],
|
|
155
|
+
},
|
|
156
|
+
{ metadata: {} }
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/** The lease only protects accounting entries; with no guard able to
|
|
160
|
+
* fire there are none, and per-attempt bookkeeping must not allocate. */
|
|
161
|
+
expect(graph.activeStreamLimitGenerations).toBeUndefined();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('holds a post-reset producer straggler to its original byte budget', async () => {
|
|
165
|
+
const { enforceStreamLimitsForWireChunk } = await import(
|
|
166
|
+
'@/llm/streamLimits'
|
|
167
|
+
);
|
|
168
|
+
const graph = makeGraph();
|
|
169
|
+
graph.streamLimits = {
|
|
170
|
+
maxToolCallArgBytes: 100,
|
|
171
|
+
maxDeltaEventsPerTurn: 0,
|
|
172
|
+
hasEnforceableToolCallArgLimit: true,
|
|
173
|
+
};
|
|
174
|
+
const metadata = {
|
|
175
|
+
langgraph_checkpoint_ns: '',
|
|
176
|
+
langgraph_node: 'agent',
|
|
177
|
+
langgraph_step: 1,
|
|
178
|
+
};
|
|
179
|
+
const chunkOf = (
|
|
180
|
+
args: string
|
|
181
|
+
): { tool_call_chunks: Array<Record<string, unknown>> } => ({
|
|
182
|
+
tool_call_chunks: [{ id: 'call_1', name: 'writer', args, index: 0 }],
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
enforceStreamLimitsForWireChunk({
|
|
186
|
+
graph,
|
|
187
|
+
metadata,
|
|
188
|
+
chunk: chunkOf('x'.repeat(60)) as Parameters<
|
|
189
|
+
typeof enforceStreamLimitsForWireChunk
|
|
190
|
+
>[0]['chunk'],
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/** The next run starts while this producer is still draining. Its next
|
|
194
|
+
* chunk must land on the ORIGINAL 60-byte tally and trip, not open a
|
|
195
|
+
* fresh allowance. */
|
|
196
|
+
graph.resetValues();
|
|
197
|
+
expect(() =>
|
|
198
|
+
enforceStreamLimitsForWireChunk({
|
|
199
|
+
graph,
|
|
200
|
+
metadata,
|
|
201
|
+
chunk: chunkOf('x'.repeat(60)) as Parameters<
|
|
202
|
+
typeof enforceStreamLimitsForWireChunk
|
|
203
|
+
>[0]['chunk'],
|
|
204
|
+
})
|
|
205
|
+
).toThrow(StreamLimitExceededError);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('rejects a model node at entry when the breaker has already tripped', async () => {
|
|
209
|
+
const graph = makeGraph();
|
|
210
|
+
const trip = makeTrip();
|
|
211
|
+
graph.breakerAbort.abort(trip);
|
|
212
|
+
|
|
213
|
+
const node = graph.createCallModel('agent');
|
|
214
|
+
await expect(
|
|
215
|
+
node(
|
|
216
|
+
{ messages: [] } as unknown as t.AgentSubgraphState,
|
|
217
|
+
{} as RunnableConfig
|
|
218
|
+
)
|
|
219
|
+
).rejects.toBe(trip);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('lets a model node proceed past entry when the breaker is live', async () => {
|
|
223
|
+
const graph = makeGraph();
|
|
224
|
+
const node = graph.createCallModel('agent');
|
|
225
|
+
/** With a live breaker the entry guard must not fire; the node then
|
|
226
|
+
* fails later, on the missing config, proving it got past the guard. */
|
|
227
|
+
await expect(
|
|
228
|
+
node(
|
|
229
|
+
{ messages: [] } as unknown as t.AgentSubgraphState,
|
|
230
|
+
undefined
|
|
231
|
+
)
|
|
232
|
+
).rejects.toThrow('No config provided');
|
|
233
|
+
});
|
|
234
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -82,3 +82,14 @@ export { initializeModel } from './llm/init';
|
|
|
82
82
|
export { attemptInvoke, tryFallbackProviders } from './llm/invoke';
|
|
83
83
|
export { canSealPreempt } from './llm/preempt';
|
|
84
84
|
export { isThinkingEnabled, getMaxOutputTokensKey } from './llm/request';
|
|
85
|
+
export {
|
|
86
|
+
DEFAULT_MAX_TOOL_CALL_ARG_BYTES,
|
|
87
|
+
StreamLimitExceededError,
|
|
88
|
+
resolveStreamLimits,
|
|
89
|
+
} from './llm/streamLimits';
|
|
90
|
+
export type {
|
|
91
|
+
StreamedToolCallArgTally,
|
|
92
|
+
ResolvedStreamLimits,
|
|
93
|
+
StreamLimitState,
|
|
94
|
+
StreamLimitKind,
|
|
95
|
+
} from './llm/streamLimits';
|