@tstdl/base 0.92.30 → 0.92.31
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.service.d.ts +7 -0
- package/ai/ai.service.js +109 -32
- package/enumeration/enumeration.d.ts +2 -5
- package/package.json +3 -3
package/ai/ai.service.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export type SpecializedGenerationResult<T> = {
|
|
|
7
7
|
result: T;
|
|
8
8
|
raw: GenerationResult;
|
|
9
9
|
};
|
|
10
|
+
export type SpecializedGenerationResultGenerator<T> = AsyncGenerator<T> & {
|
|
11
|
+
raw: Promise<GenerationResult>;
|
|
12
|
+
};
|
|
10
13
|
export declare class AiServiceOptions {
|
|
11
14
|
apiKey: string;
|
|
12
15
|
defaultModel?: AiModel;
|
|
@@ -44,10 +47,14 @@ export declare class AiService implements Resolvable<AiServiceArgument> {
|
|
|
44
47
|
}): Promise<SpecializedGenerationResult<AnalyzeContentResult<T>>>;
|
|
45
48
|
getAnalyzeContentConents(parts: OneOrMany<ContentPart>): Content[];
|
|
46
49
|
callFunctions<const T extends SchemaFunctionDeclarations>(options: CallFunctionsOptions<T>): Promise<SpecializedGenerationResult<SchemaFunctionDeclarationsResult<T>[]>>;
|
|
50
|
+
callFunctionsStream<const T extends SchemaFunctionDeclarations>(options: CallFunctionsOptions<T>): SpecializedGenerationResultGenerator<SchemaFunctionDeclarationsResult<T>>;
|
|
47
51
|
generate(request: GenerationRequest): Promise<GenerationResult>;
|
|
52
|
+
generateStream(request: GenerationRequest): AsyncGenerator<GenerationResult>;
|
|
53
|
+
private _callFunctionsStream;
|
|
48
54
|
private convertContents;
|
|
49
55
|
private convertContent;
|
|
50
56
|
private convertFunctions;
|
|
51
57
|
private convertGoogleContent;
|
|
52
58
|
private getModel;
|
|
53
59
|
}
|
|
60
|
+
export declare function mergeGenerationStreamItems(items: GenerationResult[]): GenerationResult;
|
package/ai/ai.service.js
CHANGED
|
@@ -8,13 +8,15 @@ import { FinishReason, FunctionCallingMode as GoogleFunctionCallingMode, GoogleG
|
|
|
8
8
|
import { NotSupportedError } from '../errors/not-supported.error.js';
|
|
9
9
|
import { Singleton } from '../injector/decorators.js';
|
|
10
10
|
import { inject, injectArgument } from '../injector/inject.js';
|
|
11
|
+
import { DeferredPromise } from '../promise/deferred-promise.js';
|
|
12
|
+
import { LazyPromise } from '../promise/lazy-promise.js';
|
|
11
13
|
import { convertToOpenApiSchema } from '../schema/converters/openapi-converter.js';
|
|
12
14
|
import { array, enumeration, nullable, object, string } from '../schema/index.js';
|
|
13
15
|
import { toArray } from '../utils/array/array.js';
|
|
14
16
|
import { mapAsync } from '../utils/async-iterable-helpers/map.js';
|
|
15
17
|
import { toArrayAsync } from '../utils/async-iterable-helpers/to-array.js';
|
|
16
18
|
import { hasOwnProperty, objectEntries } from '../utils/object/object.js';
|
|
17
|
-
import { assertDefinedPass, assertNotNullPass, isDefined } from '../utils/type-guards.js';
|
|
19
|
+
import { assertDefinedPass, assertNotNullPass, isDefined, isUndefined } from '../utils/type-guards.js';
|
|
18
20
|
import { resolveValueOrAsyncProvider } from '../utils/value-or-provider.js';
|
|
19
21
|
import { AiFileService } from './ai-file.service.js';
|
|
20
22
|
import { AiSession } from './ai-session.js';
|
|
@@ -171,7 +173,20 @@ Always output the content and tags in ${options?.targetLanguage ?? 'the same lan
|
|
|
171
173
|
raw: generation
|
|
172
174
|
};
|
|
173
175
|
}
|
|
176
|
+
callFunctionsStream(options) {
|
|
177
|
+
const itemsPromise = new DeferredPromise();
|
|
178
|
+
const generator = this._callFunctionsStream(options, itemsPromise);
|
|
179
|
+
generator.raw = new LazyPromise(async () => {
|
|
180
|
+
const items = await itemsPromise;
|
|
181
|
+
return mergeGenerationStreamItems(items);
|
|
182
|
+
});
|
|
183
|
+
return generator;
|
|
184
|
+
}
|
|
174
185
|
async generate(request) {
|
|
186
|
+
const items = await toArrayAsync(this.generateStream(request));
|
|
187
|
+
return mergeGenerationStreamItems(items);
|
|
188
|
+
}
|
|
189
|
+
async *generateStream(request) {
|
|
175
190
|
const googleFunctionDeclarations = isDefined(request.functions) ? await this.convertFunctions(request.functions) : undefined;
|
|
176
191
|
const generationConfig = {
|
|
177
192
|
maxOutputTokens: request.generationOptions?.maxOutputTokens,
|
|
@@ -183,15 +198,14 @@ Always output the content and tags in ${options?.targetLanguage ?? 'the same lan
|
|
|
183
198
|
presencePenalty: request.generationOptions?.presencePenalty,
|
|
184
199
|
frequencyPenalty: request.generationOptions?.frequencyPenalty
|
|
185
200
|
};
|
|
186
|
-
const
|
|
187
|
-
const generationContent = { role: 'model', parts: [] };
|
|
201
|
+
const inputContent = this.convertContents(request.contents);
|
|
188
202
|
const maxTotalOutputTokens = request.generationOptions?.maxOutputTokens ?? 8192;
|
|
189
203
|
let iterations = 0;
|
|
190
204
|
let totalPromptTokens = 0;
|
|
191
205
|
let totalOutputTokens = 0;
|
|
192
|
-
let
|
|
206
|
+
let totalTokens = 0;
|
|
193
207
|
while (totalOutputTokens < maxTotalOutputTokens) {
|
|
194
|
-
const generation = await this.getModel(request.model ?? this.defaultModel).
|
|
208
|
+
const generation = await this.getModel(request.model ?? this.defaultModel).generateContentStream({
|
|
195
209
|
generationConfig: {
|
|
196
210
|
...generationConfig,
|
|
197
211
|
maxOutputTokens: Math.min(8192, maxTotalOutputTokens - totalOutputTokens)
|
|
@@ -201,40 +215,80 @@ Always output the content and tags in ${options?.targetLanguage ?? 'the same lan
|
|
|
201
215
|
toolConfig: isDefined(request.functionCallingMode)
|
|
202
216
|
? { functionCallingConfig: { mode: functionCallingModeMap[request.functionCallingMode] } }
|
|
203
217
|
: undefined,
|
|
204
|
-
contents:
|
|
218
|
+
contents: inputContent
|
|
205
219
|
});
|
|
206
220
|
iterations++;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
221
|
+
let lastUsageMetadata;
|
|
222
|
+
let candidate;
|
|
223
|
+
for await (const generationResponse of generation.stream) {
|
|
224
|
+
candidate = generationResponse.candidates.at(0);
|
|
225
|
+
inputContent.push(candidate.content);
|
|
226
|
+
const { promptTokenCount = 0, candidatesTokenCount = 0 } = generationResponse.usageMetadata ?? {};
|
|
227
|
+
lastUsageMetadata = generationResponse.usageMetadata;
|
|
228
|
+
const content = this.convertGoogleContent(candidate.content);
|
|
229
|
+
let text;
|
|
230
|
+
let functionCallParts;
|
|
231
|
+
const result = {
|
|
232
|
+
content,
|
|
233
|
+
get text() {
|
|
234
|
+
if (isUndefined(text)) {
|
|
235
|
+
const textParts = content.parts.filter((part) => hasOwnProperty(part, 'text')).map((part) => part.text);
|
|
236
|
+
text = (textParts.length > 0) ? textParts.join('') : null;
|
|
237
|
+
}
|
|
238
|
+
return text;
|
|
239
|
+
},
|
|
240
|
+
get functionCalls() {
|
|
241
|
+
if (isUndefined(functionCallParts)) {
|
|
242
|
+
functionCallParts = content.parts.filter((part) => hasOwnProperty(part, 'functionCall')).map((part) => part.functionCall);
|
|
243
|
+
}
|
|
244
|
+
return functionCallParts;
|
|
245
|
+
},
|
|
246
|
+
finishReason: candidate.finishReason == FinishReason.MAX_TOKENS
|
|
247
|
+
? 'maxTokens'
|
|
248
|
+
: candidate.finishReason == FinishReason.STOP
|
|
249
|
+
? 'stop'
|
|
250
|
+
: 'unknown',
|
|
251
|
+
usage: {
|
|
252
|
+
iterations,
|
|
253
|
+
prompt: totalPromptTokens + promptTokenCount,
|
|
254
|
+
output: totalOutputTokens + candidatesTokenCount,
|
|
255
|
+
total: totalTokens + promptTokenCount + candidatesTokenCount
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
yield result;
|
|
211
259
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (candidate
|
|
260
|
+
totalPromptTokens += lastUsageMetadata?.promptTokenCount ?? 0;
|
|
261
|
+
totalOutputTokens += lastUsageMetadata?.candidatesTokenCount ?? 0;
|
|
262
|
+
totalTokens += lastUsageMetadata?.totalTokenCount ?? 0;
|
|
263
|
+
if (candidate?.finishReason != FinishReason.MAX_TOKENS) {
|
|
216
264
|
break;
|
|
217
265
|
}
|
|
218
266
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
267
|
+
}
|
|
268
|
+
async *_callFunctionsStream(options, itemsPromise) {
|
|
269
|
+
const generationStream = this.generateStream({
|
|
270
|
+
model: options.model,
|
|
271
|
+
generationOptions: {
|
|
272
|
+
temperature: 0.5,
|
|
273
|
+
...options
|
|
274
|
+
},
|
|
275
|
+
systemInstruction: options.systemInstruction,
|
|
276
|
+
functions: options.functions,
|
|
277
|
+
functionCallingMode: 'force',
|
|
278
|
+
contents: options.contents
|
|
279
|
+
});
|
|
280
|
+
const items = [];
|
|
281
|
+
for await (const generation of generationStream) {
|
|
282
|
+
items.push(generation);
|
|
283
|
+
for (const call of generation.functionCalls) {
|
|
284
|
+
const fn = assertDefinedPass(options.functions[call.name], 'Function in response not declared.');
|
|
285
|
+
const parametersSchema = await resolveValueOrAsyncProvider(fn.parameters);
|
|
286
|
+
const parameters = parametersSchema.parse(call.parameters);
|
|
287
|
+
const handlerResult = isSchemaFunctionDeclarationWithHandler(fn) ? await fn.handler(parameters) : undefined;
|
|
288
|
+
yield { functionName: call.name, parameters: parameters, handlerResult: handlerResult };
|
|
236
289
|
}
|
|
237
|
-
}
|
|
290
|
+
}
|
|
291
|
+
itemsPromise.resolve(items);
|
|
238
292
|
}
|
|
239
293
|
convertContents(contents) {
|
|
240
294
|
return toArray(contents).map((content) => this.convertContent(content));
|
|
@@ -306,3 +360,26 @@ AiService = __decorate([
|
|
|
306
360
|
Singleton()
|
|
307
361
|
], AiService);
|
|
308
362
|
export { AiService };
|
|
363
|
+
export function mergeGenerationStreamItems(items) {
|
|
364
|
+
const parts = items.flatMap((item) => item.content.parts);
|
|
365
|
+
let text;
|
|
366
|
+
let functionCallParts;
|
|
367
|
+
return {
|
|
368
|
+
content: { role: 'model', parts },
|
|
369
|
+
get text() {
|
|
370
|
+
if (isUndefined(text)) {
|
|
371
|
+
const textParts = parts.filter((part) => hasOwnProperty(part, 'text')).map((part) => part.text);
|
|
372
|
+
text = (textParts.length > 0) ? textParts.join('') : null;
|
|
373
|
+
}
|
|
374
|
+
return text;
|
|
375
|
+
},
|
|
376
|
+
get functionCalls() {
|
|
377
|
+
if (isUndefined(functionCallParts)) {
|
|
378
|
+
functionCallParts = parts.filter((part) => hasOwnProperty(part, 'functionCall')).map((part) => part.functionCall);
|
|
379
|
+
}
|
|
380
|
+
return functionCallParts;
|
|
381
|
+
},
|
|
382
|
+
finishReason: items.at(-1).finishReason,
|
|
383
|
+
usage: items.at(-1).usage
|
|
384
|
+
};
|
|
385
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { EnumerationObject, SimplifyObject } from '../types.js';
|
|
1
|
+
import type { EnumerationObject } from '../types.js';
|
|
3
2
|
export type EnumType<T extends EnumerationObject> = T[keyof T];
|
|
4
|
-
export declare function defineEnum<const
|
|
5
|
-
[P in keyof T]: Tagged<T[P], Name>;
|
|
6
|
-
}>;
|
|
3
|
+
export declare function defineEnum<const T extends EnumerationObject>(name: string, enumObject: T): T;
|
|
7
4
|
export declare function tryGetEnumName(enumeration: EnumerationObject): string | undefined;
|
|
8
5
|
export declare function getEnumName(enumeration: EnumerationObject): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.92.
|
|
3
|
+
"version": "0.92.31",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -163,9 +163,9 @@
|
|
|
163
163
|
"minio": "^8.0",
|
|
164
164
|
"mjml": "^4.15",
|
|
165
165
|
"mongodb": "^6.12",
|
|
166
|
-
"nodemailer": "^6.
|
|
166
|
+
"nodemailer": "^6.10",
|
|
167
167
|
"pg": "8.13",
|
|
168
|
-
"playwright": "^1.
|
|
168
|
+
"playwright": "^1.50",
|
|
169
169
|
"preact": "^10.25",
|
|
170
170
|
"preact-render-to-string": "^6.5",
|
|
171
171
|
"undici": "^7.3",
|