@vybestack/llxprt-code-core 0.1.16-nightly.250805.82080ee4 → 0.1.17
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/src/config/config.js +19 -9
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +63 -0
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +6 -1
- package/dist/src/core/coreToolScheduler.js +96 -61
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +142 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +9 -0
- package/dist/src/core/geminiChat.js +118 -0
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +1 -0
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/ide/detect-ide.js +6 -3
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/ide-installer.d.ts +0 -1
- package/dist/src/ide/ide-installer.js +5 -7
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/ide/ide-installer.test.js +1 -24
- package/dist/src/ide/ide-installer.test.js.map +1 -1
- package/dist/src/providers/integration/multi-provider.integration.test.js +1 -1
- package/dist/src/providers/integration/multi-provider.integration.test.js.map +1 -1
- package/dist/src/tools/glob.js +9 -1
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +1 -0
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.js +49 -10
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +3 -0
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.js +9 -1
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.js +1 -0
- package/dist/src/tools/ls.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +1 -1
- package/dist/src/tools/mcp-client.js +29 -17
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/read-many-files.js +135 -3
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +280 -0
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.js +11 -2
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.multibyte.test.js +1 -0
- package/dist/src/tools/shell.multibyte.test.js.map +1 -1
- package/dist/src/tools/shell.test.js +3 -0
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +5 -0
- package/dist/src/tools/tool-registry.js +24 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +49 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/types/modelParams.d.ts +12 -0
- package/dist/src/utils/paths.d.ts +11 -2
- package/dist/src/utils/paths.js +24 -7
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.d.ts +6 -0
- package/dist/src/utils/paths.test.js +153 -0
- package/dist/src/utils/paths.test.js.map +1 -0
- package/dist/src/utils/toolOutputLimiter.d.ts +34 -0
- package/dist/src/utils/toolOutputLimiter.js +115 -0
- package/dist/src/utils/toolOutputLimiter.js.map +1 -0
- package/dist/src/utils/toolOutputLimiter.test.d.ts +6 -0
- package/dist/src/utils/toolOutputLimiter.test.js +164 -0
- package/dist/src/utils/toolOutputLimiter.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// Default limits
|
|
7
|
+
export const DEFAULT_MAX_TOKENS = 50000;
|
|
8
|
+
export const DEFAULT_TRUNCATE_MODE = 'warn';
|
|
9
|
+
// Simple token estimation - roughly 4 characters per token
|
|
10
|
+
export function estimateTokens(text) {
|
|
11
|
+
return Math.ceil(text.length / 4);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get output limit configuration from ephemeral settings
|
|
15
|
+
*/
|
|
16
|
+
export function getOutputLimits(config) {
|
|
17
|
+
const ephemeralSettings = config.getEphemeralSettings();
|
|
18
|
+
return {
|
|
19
|
+
maxTokens: ephemeralSettings['tool-output-max-tokens'] ??
|
|
20
|
+
DEFAULT_MAX_TOKENS,
|
|
21
|
+
truncateMode: ephemeralSettings['tool-output-truncate-mode'] ?? DEFAULT_TRUNCATE_MODE,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if content exceeds token limit and handle according to truncate mode
|
|
26
|
+
*/
|
|
27
|
+
export function limitOutputTokens(content, config, toolName) {
|
|
28
|
+
const limits = getOutputLimits(config);
|
|
29
|
+
const tokens = estimateTokens(content);
|
|
30
|
+
if (!limits.maxTokens || tokens <= limits.maxTokens) {
|
|
31
|
+
return {
|
|
32
|
+
content,
|
|
33
|
+
wasTruncated: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Content exceeds limit
|
|
37
|
+
const originalTokens = tokens;
|
|
38
|
+
if (limits.truncateMode === 'warn') {
|
|
39
|
+
// Return empty content with warning message
|
|
40
|
+
return {
|
|
41
|
+
content: '',
|
|
42
|
+
wasTruncated: true,
|
|
43
|
+
originalTokens,
|
|
44
|
+
message: `${toolName} output exceeded token limit (${originalTokens} > ${limits.maxTokens}). Please use more specific patterns to reduce output size.`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
else if (limits.truncateMode === 'truncate') {
|
|
48
|
+
// Truncate content to fit within limit
|
|
49
|
+
const maxChars = limits.maxTokens * 4; // Rough estimate
|
|
50
|
+
const truncatedContent = content.substring(0, maxChars);
|
|
51
|
+
return {
|
|
52
|
+
content: truncatedContent + '\n\n[Output truncated due to token limit]',
|
|
53
|
+
wasTruncated: true,
|
|
54
|
+
originalTokens,
|
|
55
|
+
message: `Output truncated from ${originalTokens} to ${limits.maxTokens} tokens`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// 'sample' mode - for line-based content, sample evenly
|
|
60
|
+
const lines = content.split('\n');
|
|
61
|
+
if (lines.length > 1) {
|
|
62
|
+
const targetLines = Math.floor(limits.maxTokens / 10); // Rough estimate of tokens per line
|
|
63
|
+
const step = Math.ceil(lines.length / targetLines);
|
|
64
|
+
const sampledLines = [];
|
|
65
|
+
for (let i = 0; i < lines.length; i += step) {
|
|
66
|
+
sampledLines.push(lines[i]);
|
|
67
|
+
if (estimateTokens(sampledLines.join('\n')) > limits.maxTokens * 0.9) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
content: sampledLines.join('\n') +
|
|
73
|
+
`\n\n[Sampled ${sampledLines.length} of ${lines.length} lines due to token limit]`,
|
|
74
|
+
wasTruncated: true,
|
|
75
|
+
originalTokens,
|
|
76
|
+
message: `Output sampled to fit within ${limits.maxTokens} token limit`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Single line or non-line content, fall back to truncate
|
|
81
|
+
const maxChars = limits.maxTokens * 4; // Rough estimate
|
|
82
|
+
const truncatedContent = content.substring(0, maxChars);
|
|
83
|
+
return {
|
|
84
|
+
content: truncatedContent + '\n\n[Output truncated due to token limit]',
|
|
85
|
+
wasTruncated: true,
|
|
86
|
+
originalTokens,
|
|
87
|
+
message: `Output truncated from ${originalTokens} to ${limits.maxTokens} tokens`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Format output with truncation handling
|
|
94
|
+
*/
|
|
95
|
+
export function formatLimitedOutput(result) {
|
|
96
|
+
if (!result.wasTruncated) {
|
|
97
|
+
return {
|
|
98
|
+
llmContent: result.content,
|
|
99
|
+
returnDisplay: result.content,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (result.message && !result.content) {
|
|
103
|
+
// Warn mode - no content
|
|
104
|
+
return {
|
|
105
|
+
llmContent: result.message,
|
|
106
|
+
returnDisplay: `## Token Limit Exceeded\n\n${result.message}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Truncate or sample mode
|
|
110
|
+
return {
|
|
111
|
+
llmContent: result.content,
|
|
112
|
+
returnDisplay: result.content + (result.message ? `\n\n## Note\n${result.message}` : ''),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=toolOutputLimiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolOutputLimiter.js","sourceRoot":"","sources":["../../../src/utils/toolOutputLimiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,iBAAiB;AACjB,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,iBAAiB,GAAG,MAAM,CAAC,oBAAoB,EAAE,CAAC;IAExD,OAAO;QACL,SAAS,EACN,iBAAiB,CAAC,wBAAwB,CAAwB;YACnE,kBAAkB;QACpB,YAAY,EACT,iBAAiB,CAAC,2BAA2B,CAIhC,IAAI,qBAAqB;KAC1C,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,MAAc,EACd,QAAgB;IAEhB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,OAAO;YACL,OAAO;YACP,YAAY,EAAE,KAAK;SACpB,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,MAAM,cAAc,GAAG,MAAM,CAAC;IAE9B,IAAI,MAAM,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;QACnC,4CAA4C;QAC5C,OAAO;YACL,OAAO,EAAE,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,cAAc;YACd,OAAO,EAAE,GAAG,QAAQ,iCAAiC,cAAc,MAAM,MAAM,CAAC,SAAS,6DAA6D;SACvJ,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QAC9C,uCAAuC;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,iBAAiB;QACxD,MAAM,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAExD,OAAO;YACL,OAAO,EAAE,gBAAgB,GAAG,2CAA2C;YACvE,YAAY,EAAE,IAAI;YAClB,cAAc;YACd,OAAO,EAAE,yBAAyB,cAAc,OAAO,MAAM,CAAC,SAAS,SAAS;SACjF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,wDAAwD;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,oCAAoC;YAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC;YACnD,MAAM,YAAY,GAAa,EAAE,CAAC;YAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC5C,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5B,IAAI,cAAc,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;oBACrE,MAAM;gBACR,CAAC;YACH,CAAC;YAED,OAAO;gBACL,OAAO,EACL,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;oBACvB,gBAAgB,YAAY,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,4BAA4B;gBACpF,YAAY,EAAE,IAAI;gBAClB,cAAc;gBACd,OAAO,EAAE,gCAAgC,MAAM,CAAC,SAAS,cAAc;aACxE,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,yDAAyD;YACzD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,iBAAiB;YACxD,MAAM,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAExD,OAAO;gBACL,OAAO,EAAE,gBAAgB,GAAG,2CAA2C;gBACvE,YAAY,EAAE,IAAI;gBAClB,cAAc;gBACd,OAAO,EAAE,yBAAyB,cAAc,OAAO,MAAM,CAAC,SAAS,SAAS;aACjF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAuB;IAIzD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,OAAO;YAC1B,aAAa,EAAE,MAAM,CAAC,OAAO;SAC9B,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,yBAAyB;QACzB,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,OAAO;YAC1B,aAAa,EAAE,8BAA8B,MAAM,CAAC,OAAO,EAAE;SAC9D,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,OAAO;QAC1B,aAAa,EACX,MAAM,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
+
import { estimateTokens, getOutputLimits, limitOutputTokens, formatLimitedOutput, DEFAULT_MAX_TOKENS, DEFAULT_TRUNCATE_MODE, } from './toolOutputLimiter.js';
|
|
8
|
+
describe('toolOutputLimiter', () => {
|
|
9
|
+
let mockConfig;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
mockConfig = {
|
|
12
|
+
getEphemeralSettings: vi.fn().mockReturnValue({}),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
describe('estimateTokens', () => {
|
|
16
|
+
it('should estimate tokens as roughly 1/4 of characters', () => {
|
|
17
|
+
expect(estimateTokens('hello')).toBe(2); // 5 chars / 4 = 1.25, ceil = 2
|
|
18
|
+
expect(estimateTokens('hello world')).toBe(3); // 11 chars / 4 = 2.75, ceil = 3
|
|
19
|
+
expect(estimateTokens('')).toBe(0);
|
|
20
|
+
expect(estimateTokens('a'.repeat(100))).toBe(25); // 100 / 4 = 25
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('getOutputLimits', () => {
|
|
24
|
+
it('should return default values when no settings are provided', () => {
|
|
25
|
+
const limits = getOutputLimits(mockConfig);
|
|
26
|
+
expect(limits).toEqual({
|
|
27
|
+
maxTokens: DEFAULT_MAX_TOKENS,
|
|
28
|
+
truncateMode: DEFAULT_TRUNCATE_MODE,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
it('should return configured values from ephemeral settings', () => {
|
|
32
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
33
|
+
'tool-output-max-tokens': 75000,
|
|
34
|
+
'tool-output-truncate-mode': 'truncate',
|
|
35
|
+
});
|
|
36
|
+
const limits = getOutputLimits(mockConfig);
|
|
37
|
+
expect(limits).toEqual({
|
|
38
|
+
maxTokens: 75000,
|
|
39
|
+
truncateMode: 'truncate',
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it('should handle partial settings', () => {
|
|
43
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
44
|
+
'tool-output-max-tokens': 100000,
|
|
45
|
+
// truncateMode not set
|
|
46
|
+
});
|
|
47
|
+
const limits = getOutputLimits(mockConfig);
|
|
48
|
+
expect(limits).toEqual({
|
|
49
|
+
maxTokens: 100000,
|
|
50
|
+
truncateMode: DEFAULT_TRUNCATE_MODE,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('limitOutputTokens', () => {
|
|
55
|
+
it('should not truncate content within limits', () => {
|
|
56
|
+
const content = 'This is a short message';
|
|
57
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
58
|
+
expect(result).toEqual({
|
|
59
|
+
content,
|
|
60
|
+
wasTruncated: false,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('should warn when content exceeds limit in warn mode', () => {
|
|
64
|
+
const content = 'a'.repeat(250000); // Way over default 50k token limit
|
|
65
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
66
|
+
'tool-output-truncate-mode': 'warn',
|
|
67
|
+
});
|
|
68
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
69
|
+
expect(result.wasTruncated).toBe(true);
|
|
70
|
+
expect(result.content).toBe('');
|
|
71
|
+
expect(result.message).toContain('test-tool output exceeded token limit');
|
|
72
|
+
expect(result.message).toContain('62500 > 50000');
|
|
73
|
+
});
|
|
74
|
+
it('should truncate content in truncate mode', () => {
|
|
75
|
+
const content = 'a'.repeat(250000); // Way over default 50k token limit
|
|
76
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
77
|
+
'tool-output-truncate-mode': 'truncate',
|
|
78
|
+
});
|
|
79
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
80
|
+
expect(result.wasTruncated).toBe(true);
|
|
81
|
+
expect(result.content.length).toBeLessThan(content.length);
|
|
82
|
+
expect(result.content).toContain('[Output truncated due to token limit]');
|
|
83
|
+
expect(result.originalTokens).toBe(62500);
|
|
84
|
+
});
|
|
85
|
+
it('should sample lines in sample mode', () => {
|
|
86
|
+
const lines = Array.from({ length: 1000 }, (_, i) => `Line ${i}`);
|
|
87
|
+
const content = lines.join('\n');
|
|
88
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
89
|
+
'tool-output-truncate-mode': 'sample',
|
|
90
|
+
'tool-output-max-tokens': 1000, // Very small limit
|
|
91
|
+
});
|
|
92
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
93
|
+
expect(result.wasTruncated).toBe(true);
|
|
94
|
+
expect(result.content).toContain('[Sampled');
|
|
95
|
+
expect(result.content).toContain('of 1000 lines due to token limit]');
|
|
96
|
+
expect(result.content.split('\n').length).toBeLessThan(1000);
|
|
97
|
+
});
|
|
98
|
+
it('should handle single line content in sample mode', () => {
|
|
99
|
+
const content = 'a'.repeat(250000); // Single line, way over limit
|
|
100
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
101
|
+
'tool-output-truncate-mode': 'sample',
|
|
102
|
+
});
|
|
103
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
104
|
+
// Should fall back to truncate behavior for single lines
|
|
105
|
+
expect(result.wasTruncated).toBe(true);
|
|
106
|
+
expect(result.content.length).toBeLessThan(content.length);
|
|
107
|
+
});
|
|
108
|
+
it('should respect custom max tokens setting', () => {
|
|
109
|
+
const content = 'a'.repeat(1000); // 250 tokens
|
|
110
|
+
mockConfig.getEphemeralSettings.mockReturnValue({
|
|
111
|
+
'tool-output-max-tokens': 100,
|
|
112
|
+
'tool-output-truncate-mode': 'warn',
|
|
113
|
+
});
|
|
114
|
+
const result = limitOutputTokens(content, mockConfig, 'test-tool');
|
|
115
|
+
expect(result.wasTruncated).toBe(true);
|
|
116
|
+
expect(result.message).toContain('250 > 100');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('formatLimitedOutput', () => {
|
|
120
|
+
it('should pass through non-truncated content', () => {
|
|
121
|
+
const result = formatLimitedOutput({
|
|
122
|
+
content: 'Normal content',
|
|
123
|
+
wasTruncated: false,
|
|
124
|
+
});
|
|
125
|
+
expect(result).toEqual({
|
|
126
|
+
llmContent: 'Normal content',
|
|
127
|
+
returnDisplay: 'Normal content',
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('should format warn mode output', () => {
|
|
131
|
+
const result = formatLimitedOutput({
|
|
132
|
+
content: '',
|
|
133
|
+
wasTruncated: true,
|
|
134
|
+
message: 'Tool output exceeded limit',
|
|
135
|
+
});
|
|
136
|
+
expect(result).toEqual({
|
|
137
|
+
llmContent: 'Tool output exceeded limit',
|
|
138
|
+
returnDisplay: '## Token Limit Exceeded\n\nTool output exceeded limit',
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
it('should format truncated output with message', () => {
|
|
142
|
+
const result = formatLimitedOutput({
|
|
143
|
+
content: 'Truncated content...',
|
|
144
|
+
wasTruncated: true,
|
|
145
|
+
message: 'Output was truncated',
|
|
146
|
+
});
|
|
147
|
+
expect(result).toEqual({
|
|
148
|
+
llmContent: 'Truncated content...',
|
|
149
|
+
returnDisplay: 'Truncated content...\n\n## Note\nOutput was truncated',
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
it('should handle truncated output without message', () => {
|
|
153
|
+
const result = formatLimitedOutput({
|
|
154
|
+
content: 'Truncated content...',
|
|
155
|
+
wasTruncated: true,
|
|
156
|
+
});
|
|
157
|
+
expect(result).toEqual({
|
|
158
|
+
llmContent: 'Truncated content...',
|
|
159
|
+
returnDisplay: 'Truncated content...',
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
//# sourceMappingURL=toolOutputLimiter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolOutputLimiter.test.js","sourceRoot":"","sources":["../../../src/utils/toolOutputLimiter.test.ts"],"names":[],"mappings":"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"}
|