@tstdl/base 0.92.14 → 0.92.16
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/ai/ai-session.d.ts +5 -12
- package/ai/ai-session.js +5 -26
- package/ai/ai.service.d.ts +4 -2
- package/ai/ai.service.js +65 -31
- package/ai/types.d.ts +4 -1
- package/authentication/server/authentication.service.d.ts +3 -4
- package/authentication/server/helper.d.ts +1 -1
- package/package.json +2 -2
- package/rpc/rpc.js +2 -1
- package/serializer/handlers/binary.d.ts +1 -1
- package/utils/binary.d.ts +3 -4
- package/utils/binary.js +1 -2
- package/utils/type-guards.d.ts +1 -1
package/ai/ai-session.d.ts
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { Content, ContentPart, GenerationOptions, GenerationRequest, GenerationResult, SchemaFunctionDeclarations, SchemaFunctionDeclarationsResult } from './types.js';
|
|
1
|
+
import type { OneOrMany } from '../types.js';
|
|
2
|
+
import type { AiService, CallFunctionsOptions, SpecializedGenerationResult } from './ai.service.js';
|
|
3
|
+
import type { Content, GenerationRequest, GenerationResult, SchemaFunctionDeclarations, SchemaFunctionDeclarationsResult } from './types.js';
|
|
5
4
|
export declare class AiSession {
|
|
6
5
|
#private;
|
|
7
6
|
readonly contents: Content[];
|
|
8
7
|
constructor(aiService: AiService);
|
|
9
8
|
addContent(content: OneOrMany<Content>): void;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
maximumNumberOfTags?: number;
|
|
13
|
-
}): Promise<SpecializedGenerationResult<AnalyzeContentResult<T>>>;
|
|
14
|
-
classify<T extends Enumeration>(parts: OneOrMany<ContentPart>, types: T, options?: GenerationOptions & Pick<GenerationRequest, 'model'>): Promise<SpecializedGenerationResult<ClassificationResult<T>>>;
|
|
15
|
-
extractData<T>(parts: OneOrMany<ContentPart>, schema: SchemaTestable<T>, options?: GenerationOptions & Pick<GenerationRequest, 'model'>): Promise<SpecializedGenerationResult<T>>;
|
|
16
|
-
callFunctions<const T extends SchemaFunctionDeclarations>(functions: T, content: Content | [Content, ...Content[]], options?: Pick<GenerationRequest, 'model' | 'systemInstruction'> & GenerationOptions): Promise<SpecializedGenerationResult<SchemaFunctionDeclarationsResult<T>[]>>;
|
|
17
|
-
generate(content: Content | [Content, ...Content[]], request?: TypedOmit<GenerationRequest, 'contents'>): Promise<GenerationResult>;
|
|
9
|
+
callFunctions<const T extends SchemaFunctionDeclarations>(options: CallFunctionsOptions<T>): Promise<SpecializedGenerationResult<SchemaFunctionDeclarationsResult<T>[]>>;
|
|
10
|
+
generate(request: GenerationRequest): Promise<GenerationResult>;
|
|
18
11
|
}
|
package/ai/ai-session.js
CHANGED
|
@@ -8,35 +8,14 @@ export class AiSession {
|
|
|
8
8
|
addContent(content) {
|
|
9
9
|
this.contents.push(...toArray(content));
|
|
10
10
|
}
|
|
11
|
-
async
|
|
12
|
-
|
|
13
|
-
this.contents.
|
|
14
|
-
const result = await this.#aiService.analyzeContent(parts, types, options);
|
|
11
|
+
async callFunctions(options) {
|
|
12
|
+
this.contents.push(...toArray(options.contents));
|
|
13
|
+
const result = await this.#aiService.callFunctions({ ...options, contents: this.contents });
|
|
15
14
|
this.contents.push(result.raw.content);
|
|
16
15
|
return result;
|
|
17
16
|
}
|
|
18
|
-
async
|
|
19
|
-
|
|
20
|
-
this.contents.push(...newContents);
|
|
21
|
-
const result = await this.#aiService.classify(parts, types, options);
|
|
22
|
-
this.contents.push(result.raw.content);
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
async extractData(parts, schema, options) {
|
|
26
|
-
const newContents = this.#aiService.getExtractDataConents(parts);
|
|
27
|
-
this.contents.push(...newContents);
|
|
28
|
-
const result = await this.#aiService.extractData(parts, schema, options);
|
|
29
|
-
this.contents.push(result.raw.content);
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
async callFunctions(functions, content, options) {
|
|
33
|
-
this.contents.push(...toArray(content));
|
|
34
|
-
const result = await this.#aiService.callFunctions(functions, this.contents, options);
|
|
35
|
-
this.contents.push(result.raw.content);
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
async generate(content, request) {
|
|
39
|
-
this.contents.push(...toArray(content));
|
|
17
|
+
async generate(request) {
|
|
18
|
+
this.contents.push(...toArray(request.contents));
|
|
40
19
|
const result = await this.#aiService.generate({ ...request, contents: this.contents });
|
|
41
20
|
this.contents.push(result.content);
|
|
42
21
|
return result;
|
package/ai/ai.service.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import '../polyfills.js';
|
|
2
1
|
import { Resolvable, type resolveArgumentType } from '../injector/interfaces.js';
|
|
3
2
|
import { OneOrMany, SchemaTestable } from '../schema/index.js';
|
|
4
3
|
import { Enumeration as EnumerationType, EnumerationValue } from '../types.js';
|
|
@@ -24,6 +23,9 @@ export type AnalyzeContentResult<T extends EnumerationType> = {
|
|
|
24
23
|
documentTypes: ClassificationResult<T>[];
|
|
25
24
|
tags: string[];
|
|
26
25
|
};
|
|
26
|
+
export type CallFunctionsOptions<T extends SchemaFunctionDeclarations> = Pick<GenerationRequest, 'contents' | 'model' | 'systemInstruction'> & GenerationOptions & {
|
|
27
|
+
functions: T;
|
|
28
|
+
};
|
|
27
29
|
export declare class AiService implements Resolvable<AiServiceArgument> {
|
|
28
30
|
#private;
|
|
29
31
|
readonly defaultModel: AiModel;
|
|
@@ -40,7 +42,7 @@ export declare class AiService implements Resolvable<AiServiceArgument> {
|
|
|
40
42
|
maximumNumberOfTags?: number;
|
|
41
43
|
}): Promise<SpecializedGenerationResult<AnalyzeContentResult<T>>>;
|
|
42
44
|
getAnalyzeContentConents(parts: OneOrMany<ContentPart>): Content[];
|
|
43
|
-
callFunctions<const T extends SchemaFunctionDeclarations>(
|
|
45
|
+
callFunctions<const T extends SchemaFunctionDeclarations>(options: CallFunctionsOptions<T>): Promise<SpecializedGenerationResult<SchemaFunctionDeclarationsResult<T>[]>>;
|
|
44
46
|
generate(request: GenerationRequest): Promise<GenerationResult>;
|
|
45
47
|
private convertContents;
|
|
46
48
|
private convertContent;
|
package/ai/ai.service.js
CHANGED
|
@@ -4,8 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import '
|
|
8
|
-
import { FunctionCallingMode as GoogleFunctionCallingMode, GoogleGenerativeAI } from '@google/generative-ai';
|
|
7
|
+
import { FinishReason, FunctionCallingMode as GoogleFunctionCallingMode, GoogleGenerativeAI } from '@google/generative-ai';
|
|
9
8
|
import { NotSupportedError } from '../errors/not-supported.error.js';
|
|
10
9
|
import { Singleton } from '../injector/decorators.js';
|
|
11
10
|
import { inject, injectArgument } from '../injector/inject.js';
|
|
@@ -47,7 +46,7 @@ let AiService = class AiService {
|
|
|
47
46
|
model: options?.model,
|
|
48
47
|
generationOptions: {
|
|
49
48
|
maxOutputTokens: 1048,
|
|
50
|
-
temperature: 0.
|
|
49
|
+
temperature: 0.25,
|
|
51
50
|
...options
|
|
52
51
|
},
|
|
53
52
|
generationSchema,
|
|
@@ -72,7 +71,7 @@ let AiService = class AiService {
|
|
|
72
71
|
const generation = await this.generate({
|
|
73
72
|
model: options?.model,
|
|
74
73
|
generationOptions: {
|
|
75
|
-
temperature: 0.
|
|
74
|
+
temperature: 0.25,
|
|
76
75
|
...options
|
|
77
76
|
},
|
|
78
77
|
generationSchema: schema,
|
|
@@ -108,7 +107,7 @@ Carefully read and analyze the provided document. Identify relevant information
|
|
|
108
107
|
const generation = await this.generate({
|
|
109
108
|
generationOptions: {
|
|
110
109
|
maxOutputTokens: 2048,
|
|
111
|
-
temperature: 0.
|
|
110
|
+
temperature: 0.25,
|
|
112
111
|
...options
|
|
113
112
|
},
|
|
114
113
|
generationSchema: schema,
|
|
@@ -136,22 +135,21 @@ Always output the content and tags in ${options?.targetLanguage ?? 'the same lan
|
|
|
136
135
|
]
|
|
137
136
|
}];
|
|
138
137
|
}
|
|
139
|
-
async callFunctions(
|
|
138
|
+
async callFunctions(options) {
|
|
140
139
|
const generation = await this.generate({
|
|
141
|
-
model: options
|
|
140
|
+
model: options.model,
|
|
142
141
|
generationOptions: {
|
|
143
|
-
|
|
144
|
-
temperature: 0.5,
|
|
142
|
+
temperature: 0.25,
|
|
145
143
|
...options
|
|
146
144
|
},
|
|
147
|
-
systemInstruction: options
|
|
148
|
-
functions,
|
|
145
|
+
systemInstruction: options.systemInstruction,
|
|
146
|
+
functions: options.functions,
|
|
149
147
|
functionCallingMode: 'force',
|
|
150
|
-
contents
|
|
148
|
+
contents: options.contents
|
|
151
149
|
});
|
|
152
150
|
const result = [];
|
|
153
151
|
for (const call of generation.functionCalls) {
|
|
154
|
-
const fn = assertDefinedPass(functions[call.name], 'Function in response not declared.');
|
|
152
|
+
const fn = assertDefinedPass(options.functions[call.name], 'Function in response not declared.');
|
|
155
153
|
const parameters = fn.parameters.parse(call.parameters);
|
|
156
154
|
const handlerResult = isSchemaFunctionDeclarationWithHandler(fn) ? await fn.handler(parameters) : undefined;
|
|
157
155
|
result.push({ functionName: call.name, parameters: parameters, handlerResult: handlerResult });
|
|
@@ -162,36 +160,72 @@ Always output the content and tags in ${options?.targetLanguage ?? 'the same lan
|
|
|
162
160
|
};
|
|
163
161
|
}
|
|
164
162
|
async generate(request) {
|
|
165
|
-
const googleContent = this.convertContents(request.contents);
|
|
166
163
|
const googleFunctionDeclarations = isDefined(request.functions) ? this.convertFunctions(request.functions) : undefined;
|
|
167
|
-
const generationConfig =
|
|
168
|
-
|
|
169
|
-
: request.generationOptions
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
const
|
|
164
|
+
const generationConfig = {
|
|
165
|
+
maxOutputTokens: request.generationOptions?.maxOutputTokens,
|
|
166
|
+
temperature: request.generationOptions?.temperature,
|
|
167
|
+
topP: request.generationOptions?.topP,
|
|
168
|
+
topK: request.generationOptions?.topK,
|
|
169
|
+
responseMimeType: isDefined(request.generationSchema) ? 'application/json' : undefined,
|
|
170
|
+
responseSchema: isDefined(request.generationSchema) ? convertToOpenApiSchema(request.generationSchema) : undefined,
|
|
171
|
+
presencePenalty: request.generationOptions?.presencePenalty,
|
|
172
|
+
frequencyPenalty: request.generationOptions?.frequencyPenalty
|
|
173
|
+
};
|
|
174
|
+
const googleContent = this.convertContents(request.contents);
|
|
175
|
+
const generationContent = { role: 'model', parts: [] };
|
|
176
|
+
const maxTotalOutputTokens = request.generationOptions?.maxOutputTokens ?? 8192;
|
|
177
|
+
let iterations = 0;
|
|
178
|
+
let totalPromptTokens = 0;
|
|
179
|
+
let totalOutputTokens = 0;
|
|
180
|
+
let candidate;
|
|
181
|
+
while (totalOutputTokens < maxTotalOutputTokens) {
|
|
182
|
+
const generation = await this.getModel(request.model ?? this.defaultModel).generateContent({
|
|
183
|
+
generationConfig: {
|
|
184
|
+
...generationConfig,
|
|
185
|
+
maxOutputTokens: Math.min(8192, maxTotalOutputTokens - totalOutputTokens)
|
|
186
|
+
},
|
|
187
|
+
systemInstruction: request.systemInstruction,
|
|
188
|
+
tools: isDefined(googleFunctionDeclarations) ? [{ functionDeclarations: googleFunctionDeclarations }] : undefined,
|
|
189
|
+
toolConfig: isDefined(request.functionCallingMode)
|
|
190
|
+
? { functionCallingConfig: { mode: functionCallingModeMap[request.functionCallingMode] } }
|
|
191
|
+
: undefined,
|
|
192
|
+
contents: googleContent
|
|
193
|
+
});
|
|
194
|
+
iterations++;
|
|
195
|
+
candidate = generation.response.candidates.at(0);
|
|
196
|
+
// On first generation only
|
|
197
|
+
if (generationContent.parts.length == 0) {
|
|
198
|
+
googleContent.push(generationContent);
|
|
199
|
+
}
|
|
200
|
+
generationContent.parts.push(...candidate.content.parts);
|
|
201
|
+
totalPromptTokens += generation.response.usageMetadata.promptTokenCount;
|
|
202
|
+
totalOutputTokens += generation.response.usageMetadata.candidatesTokenCount;
|
|
203
|
+
if (candidate.finishReason != FinishReason.MAX_TOKENS) {
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const content = this.convertGoogleContent(generationContent);
|
|
180
208
|
const textParts = content.parts.filter((part) => hasOwnProperty(part, 'text')).map((part) => part.text);
|
|
181
209
|
const functionCallParts = content.parts.filter((part) => hasOwnProperty(part, 'functionCall')).map((part) => part.functionCall);
|
|
182
210
|
return {
|
|
183
211
|
content,
|
|
184
212
|
text: textParts.length > 0 ? textParts.join('') : null,
|
|
185
213
|
functionCalls: functionCallParts,
|
|
214
|
+
finishReason: candidate.finishReason == FinishReason.MAX_TOKENS
|
|
215
|
+
? 'maxTokens'
|
|
216
|
+
: candidate.finishReason == FinishReason.STOP
|
|
217
|
+
? 'stop'
|
|
218
|
+
: 'unknown',
|
|
186
219
|
usage: {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
220
|
+
iterations,
|
|
221
|
+
prompt: totalPromptTokens,
|
|
222
|
+
output: totalOutputTokens,
|
|
223
|
+
total: totalPromptTokens + totalOutputTokens
|
|
190
224
|
}
|
|
191
225
|
};
|
|
192
226
|
}
|
|
193
227
|
convertContents(contents) {
|
|
194
|
-
return contents.map((content) => this.convertContent(content));
|
|
228
|
+
return toArray(contents).map((content) => this.convertContent(content));
|
|
195
229
|
}
|
|
196
230
|
convertContent(content) {
|
|
197
231
|
return {
|
package/ai/types.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export type Content = {
|
|
|
49
49
|
parts: readonly ContentPart[];
|
|
50
50
|
};
|
|
51
51
|
export type FunctionCallingMode = 'auto' | 'force' | 'none';
|
|
52
|
+
export type FinishReason = 'stop' | 'maxTokens' | 'unknown';
|
|
52
53
|
export type AiModel = LiteralUnion<'gemini-2.0-flash-exp' | 'gemini-exp-1206' | 'gemini-2.0-flash-thinking-exp-1219', string>;
|
|
53
54
|
export type GenerationOptions = {
|
|
54
55
|
maxOutputTokens?: number;
|
|
@@ -61,13 +62,14 @@ export type GenerationOptions = {
|
|
|
61
62
|
export type GenerationRequest = {
|
|
62
63
|
model?: AiModel;
|
|
63
64
|
systemInstruction?: string;
|
|
64
|
-
contents: readonly Content[];
|
|
65
|
+
contents: Content | readonly Content[];
|
|
65
66
|
functions?: SchemaFunctionDeclarations;
|
|
66
67
|
functionCallingMode?: FunctionCallingMode;
|
|
67
68
|
generationSchema?: SchemaTestable;
|
|
68
69
|
generationOptions?: GenerationOptions;
|
|
69
70
|
};
|
|
70
71
|
export type GenerationUsage = {
|
|
72
|
+
iterations: number;
|
|
71
73
|
prompt: number;
|
|
72
74
|
output: number;
|
|
73
75
|
total: number;
|
|
@@ -76,6 +78,7 @@ export type GenerationResult = {
|
|
|
76
78
|
content: Content;
|
|
77
79
|
text: string | null;
|
|
78
80
|
functionCalls: FunctionCall[];
|
|
81
|
+
finishReason: FinishReason;
|
|
79
82
|
usage: GenerationUsage;
|
|
80
83
|
};
|
|
81
84
|
export declare function declareFunctions<T extends SchemaFunctionDeclarations>(declarations: T): T;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { Record } from '../../types.js';
|
|
1
|
+
import { AfterResolve, afterResolve } from '../../injector/index.js';
|
|
2
|
+
import type { BinaryData, Record } from '../../types.js';
|
|
4
3
|
import type { RefreshToken, SecretCheckResult, SecretResetToken, Token } from '../models/index.js';
|
|
5
|
-
import
|
|
4
|
+
import { SecretTestResult } from './authentication-secret-requirements.validator.js';
|
|
6
5
|
export type CreateTokenData<AdditionalTokenPayload extends Record> = {
|
|
7
6
|
tokenVersion?: number;
|
|
8
7
|
jwtId?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.92.
|
|
3
|
+
"version": "0.92.16",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"tsx": "^4.19.2",
|
|
145
145
|
"typedoc": "0.27",
|
|
146
146
|
"typedoc-plugin-missing-exports": "3.1",
|
|
147
|
-
"typescript": "5.
|
|
147
|
+
"typescript": "5.7"
|
|
148
148
|
},
|
|
149
149
|
"peerDependencies": {
|
|
150
150
|
"@elastic/elasticsearch": "^8.17",
|
package/rpc/rpc.js
CHANGED
|
@@ -137,7 +137,8 @@ function createProxy(channel, path = []) {
|
|
|
137
137
|
handlers[method] = deferThrow(() => new NotSupportedError(`${method} not supported on rpc proxies.`));
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
proxy = new Proxy(RpcProxy, handlers);
|
|
141
|
+
return proxy;
|
|
141
142
|
}
|
|
142
143
|
function exposeObject(object, channel) {
|
|
143
144
|
const { endpoint } = channel;
|
|
@@ -4,7 +4,7 @@ interface TypedArrayConstructor {
|
|
|
4
4
|
new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): TypedArray;
|
|
5
5
|
}
|
|
6
6
|
export declare function serializeArrayBuffer(buffer: ArrayBuffer): string;
|
|
7
|
-
export declare function deserializeArrayBuffer(data: string):
|
|
7
|
+
export declare function deserializeArrayBuffer(data: string): ArrayBufferLike;
|
|
8
8
|
export declare function serializeTypedArray(array: TypedArray): string;
|
|
9
9
|
export declare function getTypedArrayDeserializer(constructor: TypedArrayConstructor): (data: string) => TypedArray;
|
|
10
10
|
export declare function serializeBuffer(buffer: Buffer): string;
|
package/utils/binary.d.ts
CHANGED
|
@@ -4,14 +4,13 @@ import type { BinaryData, Type } from '../types.js';
|
|
|
4
4
|
* @param data data to get ArrayBuffer from
|
|
5
5
|
* @param clone force cloning (might still clone if datas underlying buffer is larger than its view)
|
|
6
6
|
*/
|
|
7
|
-
export declare function toArrayBuffer(data: BinaryData, clone?: boolean):
|
|
7
|
+
export declare function toArrayBuffer(data: BinaryData, clone?: boolean): ArrayBufferLike;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* convert to Uint8Array
|
|
9
|
+
* Convert to Uint8Array
|
|
11
10
|
* @param data binary data
|
|
12
11
|
* @param clone whether to clone buffer or not
|
|
13
12
|
*/
|
|
14
13
|
export declare function toUint8Array(data: BinaryData, clone?: boolean): Uint8Array;
|
|
15
|
-
export declare function concatArrayBuffers(buffers: ArrayBufferLike[]):
|
|
14
|
+
export declare function concatArrayBuffers(buffers: ArrayBufferLike[]): ArrayBufferLike;
|
|
16
15
|
export declare function concatArrayBufferViews<T extends ArrayBufferView>(arrays: T[], totalLength?: number): T;
|
|
17
16
|
export declare function concatArrayBufferViews<T extends ArrayBufferView>(arrays: ArrayBufferView[], targetType: Type<T, [ArrayBufferLike, number, number]>, totalLength?: number): T;
|
package/utils/binary.js
CHANGED
|
@@ -16,8 +16,7 @@ export function toArrayBuffer(data, clone = false) {
|
|
|
16
16
|
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
* convert to Uint8Array
|
|
19
|
+
* Convert to Uint8Array
|
|
21
20
|
* @param data binary data
|
|
22
21
|
* @param clone whether to clone buffer or not
|
|
23
22
|
*/
|
package/utils/type-guards.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AbstractConstructor, JsonPrimitive, PascalCase, Primitive, TypedArray } from '../types.js';
|
|
1
|
+
import type { AbstractConstructor, BinaryData, JsonPrimitive, PascalCase, Primitive, TypedArray } from '../types.js';
|
|
2
2
|
export type AssertionMessage = string | (() => string);
|
|
3
3
|
export type IsFunction<T> = <U extends T = T>(value: any) => value is U;
|
|
4
4
|
export type IsNotFunction<T> = <V>(value: V) => value is Exclude<V, T>;
|