@promptbook/cli 0.89.0-9 → 0.89.0
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/README.md +9 -11
- package/esm/index.es.js +925 -616
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +40 -0
- package/esm/typings/src/_packages/core.index.d.ts +8 -4
- package/esm/typings/src/_packages/types.index.d.ts +18 -0
- package/esm/typings/src/_packages/utils.index.d.ts +4 -0
- package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
- package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +16 -3
- package/esm/typings/src/cli/test/ptbk.d.ts +1 -1
- package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +2 -0
- package/esm/typings/src/config.d.ts +10 -19
- package/esm/typings/src/errors/0-index.d.ts +7 -4
- package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
- package/esm/typings/src/errors/WrappedError.d.ts +10 -0
- package/esm/typings/src/errors/assertsError.d.ts +11 -0
- package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
- package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +9 -0
- package/esm/typings/src/formats/csv/utils/isValidCsvString.test.d.ts +1 -0
- package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +3 -0
- package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +9 -0
- package/esm/typings/src/formats/xml/utils/isValidXmlString.test.d.ts +1 -0
- package/esm/typings/src/llm-providers/_common/register/{$provideEnvFilepath.d.ts → $provideEnvFilename.d.ts} +2 -2
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +11 -2
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
- package/esm/typings/src/remote-server/openapi-types.d.ts +284 -0
- package/esm/typings/src/remote-server/openapi.d.ts +187 -0
- package/esm/typings/src/remote-server/socket-types/_subtypes/Identification.d.ts +7 -1
- package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
- package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
- package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
- package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +15 -9
- package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
- package/esm/typings/src/types/typeAliases.d.ts +26 -0
- package/package.json +15 -11
- package/umd/index.umd.js +929 -620
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
package/esm/index.es.js
CHANGED
|
@@ -3,14 +3,14 @@ import commander from 'commander';
|
|
|
3
3
|
import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
4
|
import { forTime, forEver } from 'waitasecond';
|
|
5
5
|
import prompts from 'prompts';
|
|
6
|
-
import {
|
|
6
|
+
import { join, basename, dirname, relative } from 'path';
|
|
7
7
|
import { stat, access, constants, readFile, writeFile, readdir, mkdir, unlink, rm, rename, rmdir } from 'fs/promises';
|
|
8
|
+
import * as dotenv from 'dotenv';
|
|
8
9
|
import hexEncoder from 'crypto-js/enc-hex';
|
|
9
10
|
import sha256 from 'crypto-js/sha256';
|
|
10
11
|
import { randomBytes } from 'crypto';
|
|
11
12
|
import { io } from 'socket.io-client';
|
|
12
13
|
import { Subject } from 'rxjs';
|
|
13
|
-
import * as dotenv from 'dotenv';
|
|
14
14
|
import { spawn } from 'child_process';
|
|
15
15
|
import JSZip from 'jszip';
|
|
16
16
|
import { format } from 'prettier';
|
|
@@ -23,7 +23,7 @@ import moment from 'moment';
|
|
|
23
23
|
import express from 'express';
|
|
24
24
|
import http from 'http';
|
|
25
25
|
import { Server } from 'socket.io';
|
|
26
|
-
import
|
|
26
|
+
import * as OpenApiValidator from 'express-openapi-validator';
|
|
27
27
|
import swaggerUi from 'swagger-ui-express';
|
|
28
28
|
import Anthropic from '@anthropic-ai/sdk';
|
|
29
29
|
import { OpenAIClient, AzureKeyCredential } from '@azure/openai';
|
|
@@ -46,12 +46,43 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
46
46
|
* @generated
|
|
47
47
|
* @see https://github.com/webgptorg/promptbook
|
|
48
48
|
*/
|
|
49
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.89.0
|
|
49
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.89.0';
|
|
50
50
|
/**
|
|
51
51
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
52
52
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
53
53
|
*/
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Available remote servers for the Promptbook
|
|
57
|
+
*
|
|
58
|
+
* @public exported from `@promptbook/core`
|
|
59
|
+
*/
|
|
60
|
+
const REMOTE_SERVER_URLS = [
|
|
61
|
+
{
|
|
62
|
+
title: 'Promptbook',
|
|
63
|
+
description: `Servers of Promptbook.studio`,
|
|
64
|
+
owner: 'AI Web, LLC <legal@ptbk.io> (https://www.ptbk.io/)',
|
|
65
|
+
isAnonymousModeAllowed: true,
|
|
66
|
+
urls: [
|
|
67
|
+
'https://promptbook.s5.ptbk.io/',
|
|
68
|
+
// Note: Servers 1-4 are not running
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
/*
|
|
72
|
+
Note: Working on older version of Promptbook and not supported anymore
|
|
73
|
+
{
|
|
74
|
+
title: 'Pavol Promptbook Server',
|
|
75
|
+
description: `Personal server of Pavol Hejný with simple testing server, DO NOT USE IT FOR PRODUCTION`,
|
|
76
|
+
owner: 'Pavol Hejný <pavol@ptbk.io> (https://www.pavolhejny.com/)',
|
|
77
|
+
isAnonymousModeAllowed: true,
|
|
78
|
+
urls: ['https://api.pavolhejny.com/promptbook'],
|
|
79
|
+
},
|
|
80
|
+
*/
|
|
81
|
+
];
|
|
82
|
+
/**
|
|
83
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
84
|
+
*/
|
|
85
|
+
|
|
55
86
|
/**
|
|
56
87
|
* Returns the same value that is passed as argument.
|
|
57
88
|
* No side effects.
|
|
@@ -106,6 +137,7 @@ const ADMIN_GITHUB_NAME = 'hejny';
|
|
|
106
137
|
* @public exported from `@promptbook/core`
|
|
107
138
|
*/
|
|
108
139
|
const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
|
|
140
|
+
// <- TODO: [🐊] Pick the best claim
|
|
109
141
|
/**
|
|
110
142
|
* When the title is not provided, the default title is used
|
|
111
143
|
*
|
|
@@ -136,6 +168,12 @@ const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
|
136
168
|
* @private within the repository
|
|
137
169
|
*/
|
|
138
170
|
const GENERATOR_WARNING_BY_PROMPTBOOK_CLI = `⚠️ WARNING: This code has been generated by \`@promptbook/cli\` so that any manual changes will be overwritten`;
|
|
171
|
+
/**
|
|
172
|
+
* Warning message for the automatically generated sections of `.env` files
|
|
173
|
+
*
|
|
174
|
+
* @private within the repository
|
|
175
|
+
*/
|
|
176
|
+
const GENERATOR_WARNING_IN_ENV = `Note: Added by Promptbook`;
|
|
139
177
|
// <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
|
|
140
178
|
/**
|
|
141
179
|
* The maximum number of iterations for a loops
|
|
@@ -156,6 +194,7 @@ const VALUE_STRINGS = {
|
|
|
156
194
|
infinity: '(infinity; ∞)',
|
|
157
195
|
negativeInfinity: '(negative infinity; -∞)',
|
|
158
196
|
unserializable: '(unserializable value)',
|
|
197
|
+
circular: '(circular JSON)',
|
|
159
198
|
};
|
|
160
199
|
/**
|
|
161
200
|
* Small number limit
|
|
@@ -215,7 +254,7 @@ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [🤹♂️]
|
|
|
215
254
|
*/
|
|
216
255
|
const DEFAULT_BOOKS_DIRNAME = './books';
|
|
217
256
|
// <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
218
|
-
// TODO:
|
|
257
|
+
// TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
|
|
219
258
|
/**
|
|
220
259
|
* Where to store the temporary downloads
|
|
221
260
|
*
|
|
@@ -271,11 +310,11 @@ const MOMENT_ARG_THRESHOLDS = {
|
|
|
271
310
|
ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
|
|
272
311
|
};
|
|
273
312
|
/**
|
|
274
|
-
*
|
|
313
|
+
* Default remote server URL for the Promptbook
|
|
275
314
|
*
|
|
276
315
|
* @public exported from `@promptbook/core`
|
|
277
316
|
*/
|
|
278
|
-
const DEFAULT_REMOTE_SERVER_URL =
|
|
317
|
+
const DEFAULT_REMOTE_SERVER_URL = REMOTE_SERVER_URLS[0].urls[0];
|
|
279
318
|
// <- TODO: [🧜♂️]
|
|
280
319
|
/**
|
|
281
320
|
* @@@
|
|
@@ -409,6 +448,122 @@ const $isRunningInWebWorker = new Function(`
|
|
|
409
448
|
* TODO: [🎺]
|
|
410
449
|
*/
|
|
411
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Make error report URL for the given error
|
|
453
|
+
*
|
|
454
|
+
* @private private within the repository
|
|
455
|
+
*/
|
|
456
|
+
function getErrorReportUrl(error) {
|
|
457
|
+
const report = {
|
|
458
|
+
title: `🐜 Error report from ${NAME}`,
|
|
459
|
+
body: spaceTrim((block) => `
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
463
|
+
|
|
464
|
+
\`\`\`
|
|
465
|
+
${block(error.message || '(no error message)')}
|
|
466
|
+
\`\`\`
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
## More info:
|
|
470
|
+
|
|
471
|
+
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
472
|
+
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
473
|
+
- **Time:** ${new Date().toISOString()}
|
|
474
|
+
|
|
475
|
+
<details>
|
|
476
|
+
<summary>Stack trace:</summary>
|
|
477
|
+
|
|
478
|
+
## Stack trace:
|
|
479
|
+
|
|
480
|
+
\`\`\`stacktrace
|
|
481
|
+
${block(error.stack || '(empty)')}
|
|
482
|
+
\`\`\`
|
|
483
|
+
</details>
|
|
484
|
+
|
|
485
|
+
`),
|
|
486
|
+
};
|
|
487
|
+
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
488
|
+
reportUrl.searchParams.set('labels', 'bug');
|
|
489
|
+
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
490
|
+
reportUrl.searchParams.set('title', report.title);
|
|
491
|
+
reportUrl.searchParams.set('body', report.body);
|
|
492
|
+
return reportUrl;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
497
|
+
*
|
|
498
|
+
* @public exported from `@promptbook/core`
|
|
499
|
+
*/
|
|
500
|
+
class UnexpectedError extends Error {
|
|
501
|
+
constructor(message) {
|
|
502
|
+
super(spaceTrim$1((block) => `
|
|
503
|
+
${block(message)}
|
|
504
|
+
|
|
505
|
+
Note: This error should not happen.
|
|
506
|
+
It's probbably a bug in the pipeline collection
|
|
507
|
+
|
|
508
|
+
Please report issue:
|
|
509
|
+
${block(getErrorReportUrl(new Error(message)).href)}
|
|
510
|
+
|
|
511
|
+
Or contact us on ${ADMIN_EMAIL}
|
|
512
|
+
|
|
513
|
+
`));
|
|
514
|
+
this.name = 'UnexpectedError';
|
|
515
|
+
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
521
|
+
*
|
|
522
|
+
* @public exported from `@promptbook/core`
|
|
523
|
+
*/
|
|
524
|
+
class WrappedError extends Error {
|
|
525
|
+
constructor(whatWasThrown) {
|
|
526
|
+
const tag = `[🤮]`;
|
|
527
|
+
console.error(tag, whatWasThrown);
|
|
528
|
+
super(spaceTrim$1(`
|
|
529
|
+
Non-Error object was thrown
|
|
530
|
+
|
|
531
|
+
Note: Look for ${tag} in the console for more details
|
|
532
|
+
Please report issue on ${ADMIN_EMAIL}
|
|
533
|
+
`));
|
|
534
|
+
this.name = 'WrappedError';
|
|
535
|
+
Object.setPrototypeOf(this, WrappedError.prototype);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Helper used in catch blocks to assert that the error is an instance of `Error`
|
|
541
|
+
*
|
|
542
|
+
* @param whatWasThrown Any object that was thrown
|
|
543
|
+
* @returns Nothing if the error is an instance of `Error`
|
|
544
|
+
* @throws `WrappedError` or `UnexpectedError` if the error is not standard
|
|
545
|
+
*
|
|
546
|
+
* @private within the repository
|
|
547
|
+
*/
|
|
548
|
+
function assertsError(whatWasThrown) {
|
|
549
|
+
// Case 1: Handle error which was rethrown as `WrappedError`
|
|
550
|
+
if (whatWasThrown instanceof WrappedError) {
|
|
551
|
+
const wrappedError = whatWasThrown;
|
|
552
|
+
throw wrappedError;
|
|
553
|
+
}
|
|
554
|
+
// Case 2: Handle unexpected errors
|
|
555
|
+
if (whatWasThrown instanceof UnexpectedError) {
|
|
556
|
+
const unexpectedError = whatWasThrown;
|
|
557
|
+
throw unexpectedError;
|
|
558
|
+
}
|
|
559
|
+
// Case 3: Handle standard errors - keep them up to consumer
|
|
560
|
+
if (whatWasThrown instanceof Error) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
// Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
|
|
564
|
+
throw new WrappedError(whatWasThrown);
|
|
565
|
+
}
|
|
566
|
+
|
|
412
567
|
/**
|
|
413
568
|
* Wraps action to handle error console logging and exit process with error code
|
|
414
569
|
*
|
|
@@ -423,9 +578,7 @@ function handleActionErrors(action) {
|
|
|
423
578
|
return process.exit(0);
|
|
424
579
|
}
|
|
425
580
|
catch (error) {
|
|
426
|
-
|
|
427
|
-
throw error;
|
|
428
|
-
}
|
|
581
|
+
assertsError(error);
|
|
429
582
|
// console.error(colors.bgRed(error.name));
|
|
430
583
|
console.error(colors.red(/* error.stack || */ error.message));
|
|
431
584
|
return process.exit(1);
|
|
@@ -532,74 +685,6 @@ class NotYetImplementedError extends Error {
|
|
|
532
685
|
}
|
|
533
686
|
}
|
|
534
687
|
|
|
535
|
-
/**
|
|
536
|
-
* Make error report URL for the given error
|
|
537
|
-
*
|
|
538
|
-
* @private private within the repository
|
|
539
|
-
*/
|
|
540
|
-
function getErrorReportUrl(error) {
|
|
541
|
-
const report = {
|
|
542
|
-
title: `🐜 Error report from ${NAME}`,
|
|
543
|
-
body: spaceTrim((block) => `
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
547
|
-
|
|
548
|
-
\`\`\`
|
|
549
|
-
${block(error.message || '(no error message)')}
|
|
550
|
-
\`\`\`
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
## More info:
|
|
554
|
-
|
|
555
|
-
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
556
|
-
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
557
|
-
- **Time:** ${new Date().toISOString()}
|
|
558
|
-
|
|
559
|
-
<details>
|
|
560
|
-
<summary>Stack trace:</summary>
|
|
561
|
-
|
|
562
|
-
## Stack trace:
|
|
563
|
-
|
|
564
|
-
\`\`\`stacktrace
|
|
565
|
-
${block(error.stack || '(empty)')}
|
|
566
|
-
\`\`\`
|
|
567
|
-
</details>
|
|
568
|
-
|
|
569
|
-
`),
|
|
570
|
-
};
|
|
571
|
-
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
572
|
-
reportUrl.searchParams.set('labels', 'bug');
|
|
573
|
-
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
574
|
-
reportUrl.searchParams.set('title', report.title);
|
|
575
|
-
reportUrl.searchParams.set('body', report.body);
|
|
576
|
-
return reportUrl;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
581
|
-
*
|
|
582
|
-
* @public exported from `@promptbook/core`
|
|
583
|
-
*/
|
|
584
|
-
class UnexpectedError extends Error {
|
|
585
|
-
constructor(message) {
|
|
586
|
-
super(spaceTrim$1((block) => `
|
|
587
|
-
${block(message)}
|
|
588
|
-
|
|
589
|
-
Note: This error should not happen.
|
|
590
|
-
It's probbably a bug in the pipeline collection
|
|
591
|
-
|
|
592
|
-
Please report issue:
|
|
593
|
-
${block(getErrorReportUrl(new Error(message)).href)}
|
|
594
|
-
|
|
595
|
-
Or contact us on ${ADMIN_EMAIL}
|
|
596
|
-
|
|
597
|
-
`));
|
|
598
|
-
this.name = 'UnexpectedError';
|
|
599
|
-
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
688
|
/**
|
|
604
689
|
* @@@
|
|
605
690
|
*
|
|
@@ -919,6 +1004,40 @@ function $sideEffect(...sideEffectSubjects) {
|
|
|
919
1004
|
keepUnused(...sideEffectSubjects);
|
|
920
1005
|
}
|
|
921
1006
|
|
|
1007
|
+
/**
|
|
1008
|
+
* Convert identification to Promptbook token
|
|
1009
|
+
*
|
|
1010
|
+
* @param identification
|
|
1011
|
+
*
|
|
1012
|
+
* @public exported from `@promptbook/core`
|
|
1013
|
+
*/
|
|
1014
|
+
function identificationToPromptbookToken(identification) {
|
|
1015
|
+
const { appId, userId, userToken } = identification;
|
|
1016
|
+
const promptbookToken = `${appId}-${userId}-${userToken}`;
|
|
1017
|
+
return promptbookToken;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Convert Promptbook token to identification
|
|
1022
|
+
*
|
|
1023
|
+
* @param promptbookToken
|
|
1024
|
+
*
|
|
1025
|
+
* @public exported from `@promptbook/core`
|
|
1026
|
+
*/
|
|
1027
|
+
function promptbookTokenToIdentification(promptbookToken) {
|
|
1028
|
+
const [appId, userId, userToken] = promptbookToken.split('-');
|
|
1029
|
+
if (!appId || !userId || !userToken) {
|
|
1030
|
+
throw new Error(`Invalid promptbook token: ${promptbookToken}`);
|
|
1031
|
+
}
|
|
1032
|
+
const identification = {
|
|
1033
|
+
appId,
|
|
1034
|
+
userId,
|
|
1035
|
+
userToken,
|
|
1036
|
+
isAnonymous: false,
|
|
1037
|
+
};
|
|
1038
|
+
return identification;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
922
1041
|
/**
|
|
923
1042
|
* Just marks a place of place where should be something implemented
|
|
924
1043
|
* No side effects.
|
|
@@ -932,27 +1051,199 @@ function $sideEffect(...sideEffectSubjects) {
|
|
|
932
1051
|
function TODO_USE(...value) {
|
|
933
1052
|
}
|
|
934
1053
|
|
|
935
|
-
/**
|
|
936
|
-
* @@@
|
|
937
|
-
*
|
|
938
|
-
* @public exported from `@promptbook/node`
|
|
939
|
-
*/
|
|
940
|
-
function $provideFilesystemForNode(options) {
|
|
941
|
-
if (!$isRunningInNode()) {
|
|
942
|
-
throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
|
|
1054
|
+
/**
|
|
1055
|
+
* @@@
|
|
1056
|
+
*
|
|
1057
|
+
* @public exported from `@promptbook/node`
|
|
1058
|
+
*/
|
|
1059
|
+
function $provideFilesystemForNode(options) {
|
|
1060
|
+
if (!$isRunningInNode()) {
|
|
1061
|
+
throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
|
|
1062
|
+
}
|
|
1063
|
+
return {
|
|
1064
|
+
stat,
|
|
1065
|
+
access,
|
|
1066
|
+
constants,
|
|
1067
|
+
readFile,
|
|
1068
|
+
writeFile,
|
|
1069
|
+
readdir,
|
|
1070
|
+
mkdir,
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1075
|
+
*/
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Checks if the file exists
|
|
1079
|
+
*
|
|
1080
|
+
* @private within the repository
|
|
1081
|
+
*/
|
|
1082
|
+
async function isFileExisting(filename, fs) {
|
|
1083
|
+
const isReadAccessAllowed = await fs
|
|
1084
|
+
.access(filename, fs.constants.R_OK)
|
|
1085
|
+
.then(() => true)
|
|
1086
|
+
.catch(() => false);
|
|
1087
|
+
if (!isReadAccessAllowed) {
|
|
1088
|
+
return false;
|
|
1089
|
+
}
|
|
1090
|
+
const isFile = await fs
|
|
1091
|
+
.stat(filename)
|
|
1092
|
+
.then((fileStat) => fileStat.isFile())
|
|
1093
|
+
.catch(() => false);
|
|
1094
|
+
return isFile;
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Note: Not [~🟢~] because it is not directly dependent on `fs
|
|
1098
|
+
* TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
|
|
1099
|
+
* TODO: [🖇] What about symlinks?
|
|
1100
|
+
*/
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Determines if the given path is a root path.
|
|
1104
|
+
*
|
|
1105
|
+
* Note: This does not check if the file exists only if the path is valid
|
|
1106
|
+
* @public exported from `@promptbook/utils`
|
|
1107
|
+
*/
|
|
1108
|
+
function isRootPath(value) {
|
|
1109
|
+
if (value === '/') {
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
if (/^[A-Z]:\\$/i.test(value)) {
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* TODO: [🍏] Make for MacOS paths
|
|
1119
|
+
*/
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Provides the path to the `.env` file
|
|
1123
|
+
*
|
|
1124
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
1125
|
+
*
|
|
1126
|
+
* @private within the repository - for CLI utils
|
|
1127
|
+
*/
|
|
1128
|
+
async function $provideEnvFilename() {
|
|
1129
|
+
if (!$isRunningInNode()) {
|
|
1130
|
+
throw new EnvironmentMismatchError('Function `$provideEnvFilename` works only in Node.js environment');
|
|
1131
|
+
}
|
|
1132
|
+
const envFilePatterns = [
|
|
1133
|
+
'.env',
|
|
1134
|
+
'.env.test',
|
|
1135
|
+
'.env.local',
|
|
1136
|
+
'.env.development.local',
|
|
1137
|
+
'.env.development',
|
|
1138
|
+
'.env.production.local',
|
|
1139
|
+
'.env.production',
|
|
1140
|
+
'.env.prod.local',
|
|
1141
|
+
'.env.prod',
|
|
1142
|
+
// <- TODO: Maybe add more patterns
|
|
1143
|
+
];
|
|
1144
|
+
let rootDirname = process.cwd();
|
|
1145
|
+
up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
|
|
1146
|
+
for (const pattern of envFilePatterns) {
|
|
1147
|
+
const envFilename = join(rootDirname, pattern);
|
|
1148
|
+
if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
|
|
1149
|
+
$setUsedEnvFilename(envFilename);
|
|
1150
|
+
return envFilename;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (isRootPath(rootDirname)) {
|
|
1154
|
+
break up_to_root;
|
|
1155
|
+
}
|
|
1156
|
+
// Note: If the directory does not exist, try the parent directory
|
|
1157
|
+
rootDirname = join(rootDirname, '..');
|
|
1158
|
+
}
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1163
|
+
*/
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Stores data in .env variables
|
|
1167
|
+
*
|
|
1168
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes to `process.env`
|
|
1169
|
+
*
|
|
1170
|
+
* @private within the repository - for CLI utils
|
|
1171
|
+
*/
|
|
1172
|
+
class $EnvStorage {
|
|
1173
|
+
constructor() {
|
|
1174
|
+
this.envFilename = null;
|
|
1175
|
+
}
|
|
1176
|
+
async $provideOrCreateEnvFile() {
|
|
1177
|
+
if (this.envFilename !== null) {
|
|
1178
|
+
return this.envFilename;
|
|
1179
|
+
}
|
|
1180
|
+
let envFilename = await $provideEnvFilename();
|
|
1181
|
+
if (envFilename !== null) {
|
|
1182
|
+
this.envFilename = envFilename;
|
|
1183
|
+
return envFilename;
|
|
1184
|
+
}
|
|
1185
|
+
envFilename = join(process.cwd(), '.env');
|
|
1186
|
+
await writeFile(envFilename, '# This file was initialized by Promptbook', 'utf-8');
|
|
1187
|
+
this.envFilename = envFilename;
|
|
1188
|
+
return envFilename;
|
|
1189
|
+
}
|
|
1190
|
+
transformKey(key) {
|
|
1191
|
+
return normalizeTo_SCREAMING_CASE(key);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
1195
|
+
*/
|
|
1196
|
+
get length() {
|
|
1197
|
+
throw new NotYetImplementedError('Method `$EnvStorage.length` not implemented.');
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
1201
|
+
*/
|
|
1202
|
+
clear() {
|
|
1203
|
+
throw new NotYetImplementedError('Method `$EnvStorage.clear` not implemented.');
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
1207
|
+
*/
|
|
1208
|
+
async getItem(key) {
|
|
1209
|
+
dotenv.config({ path: await this.$provideOrCreateEnvFile() });
|
|
1210
|
+
return process.env[this.transformKey(key)] || null;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
1214
|
+
*/
|
|
1215
|
+
key(index) {
|
|
1216
|
+
throw new NotYetImplementedError('Method `$EnvStorage.key` not implemented.');
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1220
|
+
*/
|
|
1221
|
+
async setItem(key, value) {
|
|
1222
|
+
const envFilename = await this.$provideOrCreateEnvFile();
|
|
1223
|
+
const envContent = await readFile(envFilename, 'utf-8');
|
|
1224
|
+
const transformedKey = this.transformKey(key);
|
|
1225
|
+
const updatedEnvContent = envContent
|
|
1226
|
+
.split('\n')
|
|
1227
|
+
.filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
|
|
1228
|
+
.filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
|
|
1229
|
+
.join('\n');
|
|
1230
|
+
const newEnvContent = spaceTrim((block) => `
|
|
1231
|
+
${block(updatedEnvContent)}
|
|
1232
|
+
|
|
1233
|
+
# ${GENERATOR_WARNING_IN_ENV}
|
|
1234
|
+
${transformedKey}=${JSON.stringify(value)}
|
|
1235
|
+
`);
|
|
1236
|
+
await writeFile(envFilename, newEnvContent, 'utf-8');
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
1240
|
+
*/
|
|
1241
|
+
removeItem(key) {
|
|
1242
|
+
throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
|
|
943
1243
|
}
|
|
944
|
-
return {
|
|
945
|
-
stat,
|
|
946
|
-
access,
|
|
947
|
-
constants,
|
|
948
|
-
readFile,
|
|
949
|
-
writeFile,
|
|
950
|
-
readdir,
|
|
951
|
-
mkdir,
|
|
952
|
-
};
|
|
953
1244
|
}
|
|
954
1245
|
/**
|
|
955
|
-
*
|
|
1246
|
+
* TODO: Write file more securely - ensure that there can be no accidental overwriting of existing variables and other content
|
|
956
1247
|
*/
|
|
957
1248
|
|
|
958
1249
|
/**
|
|
@@ -1088,9 +1379,7 @@ function checkSerializableAsJson(options) {
|
|
|
1088
1379
|
JSON.stringify(value); // <- TODO: [0]
|
|
1089
1380
|
}
|
|
1090
1381
|
catch (error) {
|
|
1091
|
-
|
|
1092
|
-
throw error;
|
|
1093
|
-
}
|
|
1382
|
+
assertsError(error);
|
|
1094
1383
|
throw new UnexpectedError(spaceTrim((block) => `
|
|
1095
1384
|
\`${name}\` is not serializable
|
|
1096
1385
|
|
|
@@ -1323,31 +1612,6 @@ function stringifyPipelineJson(pipeline) {
|
|
|
1323
1612
|
* TODO: [🍙] Make some standard order of json properties
|
|
1324
1613
|
*/
|
|
1325
1614
|
|
|
1326
|
-
/**
|
|
1327
|
-
* Checks if the file exists
|
|
1328
|
-
*
|
|
1329
|
-
* @private within the repository
|
|
1330
|
-
*/
|
|
1331
|
-
async function isFileExisting(filename, fs) {
|
|
1332
|
-
const isReadAccessAllowed = await fs
|
|
1333
|
-
.access(filename, fs.constants.R_OK)
|
|
1334
|
-
.then(() => true)
|
|
1335
|
-
.catch(() => false);
|
|
1336
|
-
if (!isReadAccessAllowed) {
|
|
1337
|
-
return false;
|
|
1338
|
-
}
|
|
1339
|
-
const isFile = await fs
|
|
1340
|
-
.stat(filename)
|
|
1341
|
-
.then((fileStat) => fileStat.isFile())
|
|
1342
|
-
.catch(() => false);
|
|
1343
|
-
return isFile;
|
|
1344
|
-
}
|
|
1345
|
-
/**
|
|
1346
|
-
* Note: Not [~🟢~] because it is not directly dependent on `fs
|
|
1347
|
-
* TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
|
|
1348
|
-
* TODO: [🖇] What about symlinks?
|
|
1349
|
-
*/
|
|
1350
|
-
|
|
1351
1615
|
/**
|
|
1352
1616
|
* Removes emojis from a string and fix whitespaces
|
|
1353
1617
|
*
|
|
@@ -1853,53 +2117,6 @@ class FileCacheStorage {
|
|
|
1853
2117
|
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1854
2118
|
*/
|
|
1855
2119
|
|
|
1856
|
-
/**
|
|
1857
|
-
* Stores data in memory (HEAP)
|
|
1858
|
-
*
|
|
1859
|
-
* @public exported from `@promptbook/core`
|
|
1860
|
-
*/
|
|
1861
|
-
class MemoryStorage {
|
|
1862
|
-
constructor() {
|
|
1863
|
-
this.storage = {};
|
|
1864
|
-
}
|
|
1865
|
-
/**
|
|
1866
|
-
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
1867
|
-
*/
|
|
1868
|
-
get length() {
|
|
1869
|
-
return Object.keys(this.storage).length;
|
|
1870
|
-
}
|
|
1871
|
-
/**
|
|
1872
|
-
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
1873
|
-
*/
|
|
1874
|
-
clear() {
|
|
1875
|
-
this.storage = {};
|
|
1876
|
-
}
|
|
1877
|
-
/**
|
|
1878
|
-
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
1879
|
-
*/
|
|
1880
|
-
getItem(key) {
|
|
1881
|
-
return this.storage[key] || null;
|
|
1882
|
-
}
|
|
1883
|
-
/**
|
|
1884
|
-
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
1885
|
-
*/
|
|
1886
|
-
key(index) {
|
|
1887
|
-
return Object.keys(this.storage)[index] || null;
|
|
1888
|
-
}
|
|
1889
|
-
/**
|
|
1890
|
-
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1891
|
-
*/
|
|
1892
|
-
setItem(key, value) {
|
|
1893
|
-
this.storage[key] = value;
|
|
1894
|
-
}
|
|
1895
|
-
/**
|
|
1896
|
-
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
1897
|
-
*/
|
|
1898
|
-
removeItem(key) {
|
|
1899
|
-
delete this.storage[key];
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
2120
|
/**
|
|
1904
2121
|
* This error indicates problems parsing the format value
|
|
1905
2122
|
*
|
|
@@ -2076,7 +2293,7 @@ class PipelineExecutionError extends Error {
|
|
|
2076
2293
|
}
|
|
2077
2294
|
}
|
|
2078
2295
|
/**
|
|
2079
|
-
* TODO:
|
|
2296
|
+
* TODO: [🧠][🌂] Add id to all errors
|
|
2080
2297
|
*/
|
|
2081
2298
|
|
|
2082
2299
|
/**
|
|
@@ -2138,7 +2355,10 @@ const PROMPTBOOK_ERRORS = {
|
|
|
2138
2355
|
PipelineExecutionError,
|
|
2139
2356
|
PipelineLogicError,
|
|
2140
2357
|
PipelineUrlError,
|
|
2358
|
+
AuthenticationError,
|
|
2359
|
+
PromptbookFetchError,
|
|
2141
2360
|
UnexpectedError,
|
|
2361
|
+
WrappedError,
|
|
2142
2362
|
// TODO: [🪑]> VersionMismatchError,
|
|
2143
2363
|
};
|
|
2144
2364
|
/**
|
|
@@ -2155,8 +2375,6 @@ const COMMON_JAVASCRIPT_ERRORS = {
|
|
|
2155
2375
|
TypeError,
|
|
2156
2376
|
URIError,
|
|
2157
2377
|
AggregateError,
|
|
2158
|
-
AuthenticationError,
|
|
2159
|
-
PromptbookFetchError,
|
|
2160
2378
|
/*
|
|
2161
2379
|
Note: Not widely supported
|
|
2162
2380
|
> InternalError,
|
|
@@ -2214,17 +2432,31 @@ function deserializeError(error) {
|
|
|
2214
2432
|
*/
|
|
2215
2433
|
async function createRemoteClient(options) {
|
|
2216
2434
|
const { remoteServerUrl } = options;
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2435
|
+
if (!isValidUrl(remoteServerUrl)) {
|
|
2436
|
+
throw new Error(`Invalid \`remoteServerUrl\`: "${remoteServerUrl}"`);
|
|
2437
|
+
}
|
|
2438
|
+
const remoteServerUrlParsed = new URL(remoteServerUrl);
|
|
2439
|
+
if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
|
|
2440
|
+
remoteServerUrlParsed.pathname = '/';
|
|
2441
|
+
throw new Error(spaceTrim((block) => `
|
|
2442
|
+
Remote server requires root url \`/\`
|
|
2443
|
+
|
|
2444
|
+
You have provided \`remoteServerUrl\`:
|
|
2445
|
+
${block(remoteServerUrl)}
|
|
2446
|
+
|
|
2447
|
+
But something like this is expected:
|
|
2448
|
+
${block(remoteServerUrlParsed.href)}
|
|
2449
|
+
|
|
2450
|
+
Note: If you need to run multiple services on the same server, use 3rd or 4th degree subdomain
|
|
2451
|
+
|
|
2452
|
+
`));
|
|
2220
2453
|
}
|
|
2221
|
-
path = `${path}/socket.io`;
|
|
2222
2454
|
return new Promise((resolve, reject) => {
|
|
2223
2455
|
const socket = io(remoteServerUrl, {
|
|
2224
2456
|
retries: CONNECTION_RETRIES_LIMIT,
|
|
2225
2457
|
timeout: CONNECTION_TIMEOUT_MS,
|
|
2226
|
-
path,
|
|
2227
|
-
transports: [
|
|
2458
|
+
path: '/socket.io',
|
|
2459
|
+
transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
|
|
2228
2460
|
});
|
|
2229
2461
|
// console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
|
|
2230
2462
|
socket.on('connect', () => {
|
|
@@ -2349,6 +2581,53 @@ class RemoteLlmExecutionTools {
|
|
|
2349
2581
|
* TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
|
|
2350
2582
|
*/
|
|
2351
2583
|
|
|
2584
|
+
/**
|
|
2585
|
+
* Stores data in memory (HEAP)
|
|
2586
|
+
*
|
|
2587
|
+
* @public exported from `@promptbook/core`
|
|
2588
|
+
*/
|
|
2589
|
+
class MemoryStorage {
|
|
2590
|
+
constructor() {
|
|
2591
|
+
this.storage = {};
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
2595
|
+
*/
|
|
2596
|
+
get length() {
|
|
2597
|
+
return Object.keys(this.storage).length;
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
2601
|
+
*/
|
|
2602
|
+
clear() {
|
|
2603
|
+
this.storage = {};
|
|
2604
|
+
}
|
|
2605
|
+
/**
|
|
2606
|
+
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
2607
|
+
*/
|
|
2608
|
+
getItem(key) {
|
|
2609
|
+
return this.storage[key] || null;
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
2613
|
+
*/
|
|
2614
|
+
key(index) {
|
|
2615
|
+
return Object.keys(this.storage)[index] || null;
|
|
2616
|
+
}
|
|
2617
|
+
/**
|
|
2618
|
+
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
2619
|
+
*/
|
|
2620
|
+
setItem(key, value) {
|
|
2621
|
+
this.storage[key] = value;
|
|
2622
|
+
}
|
|
2623
|
+
/**
|
|
2624
|
+
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
2625
|
+
*/
|
|
2626
|
+
removeItem(key) {
|
|
2627
|
+
delete this.storage[key];
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2352
2631
|
/**
|
|
2353
2632
|
* Simple wrapper `new Date().toISOString()`
|
|
2354
2633
|
*
|
|
@@ -2608,101 +2887,38 @@ function countUsage(llmTools) {
|
|
|
2608
2887
|
}
|
|
2609
2888
|
if (llmTools.callCompletionModel !== undefined) {
|
|
2610
2889
|
proxyTools.callCompletionModel = async (prompt) => {
|
|
2611
|
-
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
2612
|
-
const promptResult = await llmTools.callCompletionModel(prompt);
|
|
2613
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2614
|
-
spending.next(promptResult.usage);
|
|
2615
|
-
return promptResult;
|
|
2616
|
-
};
|
|
2617
|
-
}
|
|
2618
|
-
if (llmTools.callEmbeddingModel !== undefined) {
|
|
2619
|
-
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
2620
|
-
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
2621
|
-
const promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
2622
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2623
|
-
spending.next(promptResult.usage);
|
|
2624
|
-
return promptResult;
|
|
2625
|
-
};
|
|
2626
|
-
}
|
|
2627
|
-
// <- Note: [🤖]
|
|
2628
|
-
return proxyTools;
|
|
2629
|
-
}
|
|
2630
|
-
/**
|
|
2631
|
-
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
2632
|
-
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
2633
|
-
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
2634
|
-
* > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
|
|
2635
|
-
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2636
|
-
*/
|
|
2637
|
-
|
|
2638
|
-
/**
|
|
2639
|
-
* Determines if the given path is a root path.
|
|
2640
|
-
*
|
|
2641
|
-
* Note: This does not check if the file exists only if the path is valid
|
|
2642
|
-
* @public exported from `@promptbook/utils`
|
|
2643
|
-
*/
|
|
2644
|
-
function isRootPath(value) {
|
|
2645
|
-
if (value === '/') {
|
|
2646
|
-
return true;
|
|
2647
|
-
}
|
|
2648
|
-
if (/^[A-Z]:\\$/i.test(value)) {
|
|
2649
|
-
return true;
|
|
2650
|
-
}
|
|
2651
|
-
return false;
|
|
2652
|
-
}
|
|
2653
|
-
/**
|
|
2654
|
-
* TODO: [🍏] Make for MacOS paths
|
|
2655
|
-
*/
|
|
2656
|
-
|
|
2657
|
-
/**
|
|
2658
|
-
* Provides the path to the `.env` file
|
|
2659
|
-
*
|
|
2660
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file
|
|
2661
|
-
*
|
|
2662
|
-
* @private within the repository - for CLI utils
|
|
2663
|
-
*/
|
|
2664
|
-
async function $provideEnvFilepath() {
|
|
2665
|
-
if (!$isRunningInNode()) {
|
|
2666
|
-
throw new EnvironmentMismatchError('Function `$provideEnvFilepath` works only in Node.js environment');
|
|
2667
|
-
}
|
|
2668
|
-
const envFilePatterns = [
|
|
2669
|
-
'.env',
|
|
2670
|
-
'.env.test',
|
|
2671
|
-
'.env.local',
|
|
2672
|
-
'.env.development.local',
|
|
2673
|
-
'.env.development',
|
|
2674
|
-
'.env.production.local',
|
|
2675
|
-
'.env.production',
|
|
2676
|
-
'.env.prod.local',
|
|
2677
|
-
'.env.prod',
|
|
2678
|
-
// <- TODO: Maybe add more patterns
|
|
2679
|
-
];
|
|
2680
|
-
let rootDirname = process.cwd();
|
|
2681
|
-
up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
|
|
2682
|
-
for (const pattern of envFilePatterns) {
|
|
2683
|
-
const envFilename = join(rootDirname, pattern);
|
|
2684
|
-
if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
|
|
2685
|
-
$setUsedEnvFilename(envFilename);
|
|
2686
|
-
return envFilename;
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
|
-
if (isRootPath(rootDirname)) {
|
|
2690
|
-
break up_to_root;
|
|
2691
|
-
}
|
|
2692
|
-
// Note: If the directory does not exist, try the parent directory
|
|
2693
|
-
rootDirname = join(rootDirname, '..');
|
|
2890
|
+
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
2891
|
+
const promptResult = await llmTools.callCompletionModel(prompt);
|
|
2892
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2893
|
+
spending.next(promptResult.usage);
|
|
2894
|
+
return promptResult;
|
|
2895
|
+
};
|
|
2694
2896
|
}
|
|
2695
|
-
|
|
2897
|
+
if (llmTools.callEmbeddingModel !== undefined) {
|
|
2898
|
+
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
2899
|
+
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
2900
|
+
const promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
2901
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2902
|
+
spending.next(promptResult.usage);
|
|
2903
|
+
return promptResult;
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
// <- Note: [🤖]
|
|
2907
|
+
return proxyTools;
|
|
2696
2908
|
}
|
|
2697
2909
|
/**
|
|
2698
|
-
*
|
|
2910
|
+
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
2911
|
+
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
2912
|
+
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
2913
|
+
* > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
|
|
2914
|
+
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2699
2915
|
*/
|
|
2700
2916
|
|
|
2701
2917
|
/**
|
|
2702
2918
|
* @@@
|
|
2703
2919
|
*
|
|
2704
2920
|
* @@@ .env
|
|
2705
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
2921
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
2706
2922
|
*
|
|
2707
2923
|
* It looks for environment variables:
|
|
2708
2924
|
* - `process.env.OPENAI_API_KEY`
|
|
@@ -2716,7 +2932,7 @@ async function $provideLlmToolsConfigurationFromEnv() {
|
|
|
2716
2932
|
if (!$isRunningInNode()) {
|
|
2717
2933
|
throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
|
|
2718
2934
|
}
|
|
2719
|
-
const envFilepath = await $
|
|
2935
|
+
const envFilepath = await $provideEnvFilename();
|
|
2720
2936
|
if (envFilepath !== null) {
|
|
2721
2937
|
dotenv.config({ path: envFilepath });
|
|
2722
2938
|
}
|
|
@@ -2824,14 +3040,15 @@ class MultipleLlmExecutionTools {
|
|
|
2824
3040
|
}
|
|
2825
3041
|
}
|
|
2826
3042
|
catch (error) {
|
|
2827
|
-
|
|
3043
|
+
assertsError(error);
|
|
3044
|
+
if (error instanceof UnexpectedError) {
|
|
2828
3045
|
throw error;
|
|
2829
3046
|
}
|
|
2830
3047
|
errors.push({ llmExecutionTools, error });
|
|
2831
3048
|
}
|
|
2832
3049
|
}
|
|
2833
3050
|
if (errors.length === 1) {
|
|
2834
|
-
throw errors[0];
|
|
3051
|
+
throw errors[0].error;
|
|
2835
3052
|
}
|
|
2836
3053
|
else if (errors.length > 1) {
|
|
2837
3054
|
throw new PipelineExecutionError(
|
|
@@ -2978,7 +3195,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
|
|
|
2978
3195
|
* Note: This function is not cached, every call creates new instance of `MultipleLlmExecutionTools`
|
|
2979
3196
|
*
|
|
2980
3197
|
* @@@ .env
|
|
2981
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
3198
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
2982
3199
|
*
|
|
2983
3200
|
* It looks for environment variables:
|
|
2984
3201
|
* - `process.env.OPENAI_API_KEY`
|
|
@@ -3023,7 +3240,7 @@ async function $provideLlmToolsFromEnv(options = {}) {
|
|
|
3023
3240
|
/**
|
|
3024
3241
|
* Returns LLM tools for CLI
|
|
3025
3242
|
*
|
|
3026
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
3243
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes this .env file
|
|
3027
3244
|
*
|
|
3028
3245
|
* @private within the repository - for CLI utils
|
|
3029
3246
|
*/
|
|
@@ -3032,18 +3249,27 @@ async function $provideLlmToolsForWizzardOrCli(options) {
|
|
|
3032
3249
|
throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
|
|
3033
3250
|
}
|
|
3034
3251
|
options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
|
|
3035
|
-
const { strategy, isCacheReloaded } = options;
|
|
3252
|
+
const { isLoginloaded, strategy, isCacheReloaded } = options;
|
|
3036
3253
|
let llmExecutionTools;
|
|
3037
3254
|
if (strategy === 'REMOTE_SERVER') {
|
|
3038
3255
|
const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3256
|
+
const storage = new $EnvStorage();
|
|
3257
|
+
let key = `PROMPTBOOK_TOKEN`;
|
|
3258
|
+
if (remoteServerUrl !== DEFAULT_REMOTE_SERVER_URL) {
|
|
3259
|
+
key = `${key}_${remoteServerUrl.replace(/^https?:\/\//i, '')}`;
|
|
3260
|
+
}
|
|
3261
|
+
let identification = null;
|
|
3262
|
+
let promptbookToken = await storage.getItem(key);
|
|
3263
|
+
if (promptbookToken === null || isLoginloaded) {
|
|
3045
3264
|
identification = await loginPrompt();
|
|
3046
|
-
|
|
3265
|
+
// Note: When login prompt fails, `process.exit(1)` is called so no need to check for null
|
|
3266
|
+
if (identification.isAnonymous === false) {
|
|
3267
|
+
promptbookToken = identificationToPromptbookToken(identification);
|
|
3268
|
+
await storage.setItem(key, promptbookToken);
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
else {
|
|
3272
|
+
identification = promptbookTokenToIdentification(promptbookToken);
|
|
3047
3273
|
}
|
|
3048
3274
|
llmExecutionTools = new RemoteLlmExecutionTools({
|
|
3049
3275
|
remoteServerUrl,
|
|
@@ -3084,9 +3310,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
|
|
|
3084
3310
|
return await fetch(urlOrRequest, init);
|
|
3085
3311
|
}
|
|
3086
3312
|
catch (error) {
|
|
3087
|
-
|
|
3088
|
-
throw error;
|
|
3089
|
-
}
|
|
3313
|
+
assertsError(error);
|
|
3090
3314
|
let url;
|
|
3091
3315
|
if (typeof urlOrRequest === 'string') {
|
|
3092
3316
|
url = urlOrRequest;
|
|
@@ -3125,8 +3349,8 @@ function isValidEmail(email) {
|
|
|
3125
3349
|
/**
|
|
3126
3350
|
* @private utility of CLI
|
|
3127
3351
|
*/
|
|
3128
|
-
function $provideLlmToolsForCli(options) {
|
|
3129
|
-
const { cliOptions: {
|
|
3352
|
+
async function $provideLlmToolsForCli(options) {
|
|
3353
|
+
const { isLoginloaded, cliOptions: {
|
|
3130
3354
|
/* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
|
|
3131
3355
|
let strategy;
|
|
3132
3356
|
if (/^b/i.test(provider)) {
|
|
@@ -3140,7 +3364,11 @@ function $provideLlmToolsForCli(options) {
|
|
|
3140
3364
|
process.exit(1);
|
|
3141
3365
|
}
|
|
3142
3366
|
if (strategy === 'BRING_YOUR_OWN_KEYS') {
|
|
3143
|
-
|
|
3367
|
+
if (isLoginloaded) {
|
|
3368
|
+
throw new UnexpectedError(`\`$provideLlmToolsForCli\` isLoginloaded is not supported for strategy "BRING_YOUR_OWN_KEYS"`);
|
|
3369
|
+
}
|
|
3370
|
+
const llm = await $provideLlmToolsForWizzardOrCli({ strategy, ...options });
|
|
3371
|
+
return { strategy, llm };
|
|
3144
3372
|
}
|
|
3145
3373
|
else if (strategy === 'REMOTE_SERVER') {
|
|
3146
3374
|
if (!isValidUrl(remoteServerUrlRaw)) {
|
|
@@ -3148,7 +3376,8 @@ function $provideLlmToolsForCli(options) {
|
|
|
3148
3376
|
process.exit(1);
|
|
3149
3377
|
}
|
|
3150
3378
|
const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
|
|
3151
|
-
|
|
3379
|
+
const llm = await $provideLlmToolsForWizzardOrCli({
|
|
3380
|
+
isLoginloaded,
|
|
3152
3381
|
strategy,
|
|
3153
3382
|
appId: CLI_APP_ID,
|
|
3154
3383
|
remoteServerUrl,
|
|
@@ -3158,6 +3387,10 @@ function $provideLlmToolsForCli(options) {
|
|
|
3158
3387
|
console.log(colors.red(`You can not login to remote server in non-interactive mode`));
|
|
3159
3388
|
process.exit(1);
|
|
3160
3389
|
}
|
|
3390
|
+
console.info(colors.cyan(spaceTrim(`
|
|
3391
|
+
You will be logged in to ${remoteServerUrl}
|
|
3392
|
+
If you don't have an account, it will be created automatically.
|
|
3393
|
+
`)));
|
|
3161
3394
|
const { username, password } = await prompts([
|
|
3162
3395
|
{
|
|
3163
3396
|
type: 'text',
|
|
@@ -3175,7 +3408,6 @@ function $provideLlmToolsForCli(options) {
|
|
|
3175
3408
|
},
|
|
3176
3409
|
]);
|
|
3177
3410
|
const loginUrl = `${remoteServerUrl}/login`;
|
|
3178
|
-
console.log('!!!', { loginUrl });
|
|
3179
3411
|
// TODO: [🧠] Should we use normal `fetch` or `scraperFetch`
|
|
3180
3412
|
const response = await promptbookFetch(loginUrl, {
|
|
3181
3413
|
method: 'POST',
|
|
@@ -3188,20 +3420,7 @@ function $provideLlmToolsForCli(options) {
|
|
|
3188
3420
|
password,
|
|
3189
3421
|
}),
|
|
3190
3422
|
});
|
|
3191
|
-
console.log('!!!', {
|
|
3192
|
-
loginUrl,
|
|
3193
|
-
username,
|
|
3194
|
-
password,
|
|
3195
|
-
// type: response.type,
|
|
3196
|
-
// text: await response.text(),
|
|
3197
|
-
});
|
|
3198
3423
|
const { isSuccess, message, error, identification } = (await response.json());
|
|
3199
|
-
console.log('!!!', {
|
|
3200
|
-
isSuccess,
|
|
3201
|
-
message,
|
|
3202
|
-
error,
|
|
3203
|
-
identification,
|
|
3204
|
-
});
|
|
3205
3424
|
if (message) {
|
|
3206
3425
|
if (isSuccess) {
|
|
3207
3426
|
console.log(colors.green(message));
|
|
@@ -3222,6 +3441,7 @@ function $provideLlmToolsForCli(options) {
|
|
|
3222
3441
|
return identification;
|
|
3223
3442
|
},
|
|
3224
3443
|
});
|
|
3444
|
+
return { strategy, llm };
|
|
3225
3445
|
}
|
|
3226
3446
|
else {
|
|
3227
3447
|
throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
|
|
@@ -3243,11 +3463,12 @@ function $initializeListModelsCommand(program) {
|
|
|
3243
3463
|
listModelsCommand.alias('models');
|
|
3244
3464
|
listModelsCommand.alias('llm');
|
|
3245
3465
|
listModelsCommand.action(handleActionErrors(async (cliOptions) => {
|
|
3246
|
-
|
|
3247
|
-
// TODO: !!!!!! Not relevant for remote server and also for `about` command
|
|
3248
|
-
const llm = await $provideLlmToolsForCli({ cliOptions });
|
|
3466
|
+
const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
|
|
3249
3467
|
$sideEffect(llm);
|
|
3250
3468
|
// <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
|
|
3469
|
+
if (strategy !== 'BRING_YOUR_OWN_KEYS') {
|
|
3470
|
+
console.warn(colors.yellow(`You are using --strategy ${strategy} but models listed below are relevant for --strategy BRING_YOUR_OWN_KEYS`));
|
|
3471
|
+
}
|
|
3251
3472
|
console.info($registeredLlmToolsMessage());
|
|
3252
3473
|
return process.exit(0);
|
|
3253
3474
|
}));
|
|
@@ -3430,9 +3651,7 @@ async function locateAppOnLinux({ linuxWhich, }) {
|
|
|
3430
3651
|
return result.trim();
|
|
3431
3652
|
}
|
|
3432
3653
|
catch (error) {
|
|
3433
|
-
|
|
3434
|
-
throw error;
|
|
3435
|
-
}
|
|
3654
|
+
assertsError(error);
|
|
3436
3655
|
return null;
|
|
3437
3656
|
}
|
|
3438
3657
|
}
|
|
@@ -3487,9 +3706,7 @@ async function locateAppOnMacOs({ macOsName, }) {
|
|
|
3487
3706
|
return result.trim() + toExec;
|
|
3488
3707
|
}
|
|
3489
3708
|
catch (error) {
|
|
3490
|
-
|
|
3491
|
-
throw error;
|
|
3492
|
-
}
|
|
3709
|
+
assertsError(error);
|
|
3493
3710
|
return null;
|
|
3494
3711
|
}
|
|
3495
3712
|
}
|
|
@@ -3520,9 +3737,7 @@ async function locateAppOnWindows({ appName, windowsSuffix, }) {
|
|
|
3520
3737
|
throw new Error(`Can not locate app ${appName} on Windows.`);
|
|
3521
3738
|
}
|
|
3522
3739
|
catch (error) {
|
|
3523
|
-
|
|
3524
|
-
throw error;
|
|
3525
|
-
}
|
|
3740
|
+
assertsError(error);
|
|
3526
3741
|
return null;
|
|
3527
3742
|
}
|
|
3528
3743
|
}
|
|
@@ -3781,6 +3996,7 @@ function $initializeListScrapersCommand(program) {
|
|
|
3781
3996
|
`));
|
|
3782
3997
|
listModelsCommand.alias('scrapers');
|
|
3783
3998
|
listModelsCommand.action(handleActionErrors(async () => {
|
|
3999
|
+
// TODO: [🌞] Do not allow on REMOTE_SERVER strategy
|
|
3784
4000
|
const scrapers = await $provideScrapersForNode({});
|
|
3785
4001
|
const executables = await $provideExecutablesForNode();
|
|
3786
4002
|
console.info(spaceTrim((block) => `
|
|
@@ -3816,42 +4032,20 @@ function $initializeLoginCommand(program) {
|
|
|
3816
4032
|
loginCommand.description(spaceTrim(`
|
|
3817
4033
|
Login to the remote Promptbook server
|
|
3818
4034
|
`));
|
|
3819
|
-
loginCommand.action(handleActionErrors(async () => {
|
|
3820
|
-
//
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
{
|
|
3828
|
-
type: 'text',
|
|
3829
|
-
name: 'email',
|
|
3830
|
-
message: 'Enter your email:',
|
|
3831
|
-
validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
|
|
3832
|
-
},
|
|
3833
|
-
{
|
|
3834
|
-
type: 'password',
|
|
3835
|
-
name: 'password',
|
|
3836
|
-
message: 'Enter your password:',
|
|
3837
|
-
validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
|
|
4035
|
+
loginCommand.action(handleActionErrors(async (cliOptions) => {
|
|
4036
|
+
// Note: Not interested in return value of this function but the side effect of logging in
|
|
4037
|
+
await $provideLlmToolsForCli({
|
|
4038
|
+
isLoginloaded: true,
|
|
4039
|
+
cliOptions: {
|
|
4040
|
+
...cliOptions,
|
|
4041
|
+
strategy: 'REMOTE_SERVER', // <- Note: Overriding strategy to `REMOTE_SERVER`
|
|
4042
|
+
// TODO: Do not allow flag `--strategy` in `login` command at all
|
|
3838
4043
|
},
|
|
3839
|
-
|
|
3840
|
-
TODO_USE(email, password);
|
|
3841
|
-
await forTime(1000);
|
|
3842
|
-
console.error(colors.green(spaceTrim(`
|
|
3843
|
-
Your account ${email} was successfully created.
|
|
3844
|
-
|
|
3845
|
-
Please verify your email:
|
|
3846
|
-
https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
|
|
3847
|
-
|
|
3848
|
-
After verification, you will receive 500 000 credits for free 🎉
|
|
3849
|
-
`)));
|
|
4044
|
+
});
|
|
3850
4045
|
return process.exit(0);
|
|
3851
4046
|
}));
|
|
3852
4047
|
}
|
|
3853
4048
|
/**
|
|
3854
|
-
* TODO: Pass remote server URL (and path)
|
|
3855
4049
|
* TODO: Implement non-interactive login
|
|
3856
4050
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3857
4051
|
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
@@ -4272,6 +4466,9 @@ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"
|
|
|
4272
4466
|
/**
|
|
4273
4467
|
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
4274
4468
|
*
|
|
4469
|
+
* @param value The string to check
|
|
4470
|
+
* @returns True if the string is a valid JSON string, false otherwise
|
|
4471
|
+
*
|
|
4275
4472
|
* @public exported from `@promptbook/utils`
|
|
4276
4473
|
*/
|
|
4277
4474
|
function isValidJsonString(value /* <- [👨⚖️] */) {
|
|
@@ -4280,9 +4477,7 @@ function isValidJsonString(value /* <- [👨⚖️] */) {
|
|
|
4280
4477
|
return true;
|
|
4281
4478
|
}
|
|
4282
4479
|
catch (error) {
|
|
4283
|
-
|
|
4284
|
-
throw error;
|
|
4285
|
-
}
|
|
4480
|
+
assertsError(error);
|
|
4286
4481
|
if (error.message.includes('Unexpected token')) {
|
|
4287
4482
|
return false;
|
|
4288
4483
|
}
|
|
@@ -4813,8 +5008,8 @@ function createTask(options) {
|
|
|
4813
5008
|
updatedAt = new Date();
|
|
4814
5009
|
errors.push(...executionResult.errors);
|
|
4815
5010
|
warnings.push(...executionResult.warnings);
|
|
4816
|
-
// <- TODO:
|
|
4817
|
-
// TODO: [🧠]
|
|
5011
|
+
// <- TODO: [🌂] Only unique errors and warnings should be added (or filtered)
|
|
5012
|
+
// TODO: [🧠] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
|
|
4818
5013
|
// Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
|
|
4819
5014
|
// And delete `ExecutionTask.currentValue.preparedPipeline`
|
|
4820
5015
|
assertsTaskSuccessful(executionResult);
|
|
@@ -4824,6 +5019,7 @@ function createTask(options) {
|
|
|
4824
5019
|
partialResultSubject.next(executionResult);
|
|
4825
5020
|
}
|
|
4826
5021
|
catch (error) {
|
|
5022
|
+
assertsError(error);
|
|
4827
5023
|
status = 'ERROR';
|
|
4828
5024
|
errors.push(error);
|
|
4829
5025
|
partialResultSubject.error(error);
|
|
@@ -4969,13 +5165,19 @@ function valueToString(value) {
|
|
|
4969
5165
|
return value.toISOString();
|
|
4970
5166
|
}
|
|
4971
5167
|
else {
|
|
4972
|
-
|
|
5168
|
+
try {
|
|
5169
|
+
return JSON.stringify(value);
|
|
5170
|
+
}
|
|
5171
|
+
catch (error) {
|
|
5172
|
+
if (error instanceof TypeError && error.message.includes('circular structure')) {
|
|
5173
|
+
return VALUE_STRINGS.circular;
|
|
5174
|
+
}
|
|
5175
|
+
throw error;
|
|
5176
|
+
}
|
|
4973
5177
|
}
|
|
4974
5178
|
}
|
|
4975
5179
|
catch (error) {
|
|
4976
|
-
|
|
4977
|
-
throw error;
|
|
4978
|
-
}
|
|
5180
|
+
assertsError(error);
|
|
4979
5181
|
console.error(error);
|
|
4980
5182
|
return VALUE_STRINGS.unserializable;
|
|
4981
5183
|
}
|
|
@@ -5032,9 +5234,7 @@ function extractVariablesFromJavascript(script) {
|
|
|
5032
5234
|
}
|
|
5033
5235
|
}
|
|
5034
5236
|
catch (error) {
|
|
5035
|
-
|
|
5036
|
-
throw error;
|
|
5037
|
-
}
|
|
5237
|
+
assertsError(error);
|
|
5038
5238
|
throw new ParseError(spaceTrim$1((block) => `
|
|
5039
5239
|
Can not extract variables from the script
|
|
5040
5240
|
${block(error.stack || error.message)}
|
|
@@ -5153,6 +5353,28 @@ const MANDATORY_CSV_SETTINGS = Object.freeze({
|
|
|
5153
5353
|
// encoding: 'utf-8',
|
|
5154
5354
|
});
|
|
5155
5355
|
|
|
5356
|
+
/**
|
|
5357
|
+
* Function to check if a string is valid CSV
|
|
5358
|
+
*
|
|
5359
|
+
* @param value The string to check
|
|
5360
|
+
* @returns True if the string is a valid CSV string, false otherwise
|
|
5361
|
+
*
|
|
5362
|
+
* @public exported from `@promptbook/utils`
|
|
5363
|
+
*/
|
|
5364
|
+
function isValidCsvString(value) {
|
|
5365
|
+
try {
|
|
5366
|
+
// A simple check for CSV format: at least one comma and no invalid characters
|
|
5367
|
+
if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
|
|
5368
|
+
return true;
|
|
5369
|
+
}
|
|
5370
|
+
return false;
|
|
5371
|
+
}
|
|
5372
|
+
catch (error) {
|
|
5373
|
+
assertsError(error);
|
|
5374
|
+
return false;
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5156
5378
|
/**
|
|
5157
5379
|
* Definition for CSV spreadsheet
|
|
5158
5380
|
*
|
|
@@ -5163,7 +5385,7 @@ const CsvFormatDefinition = {
|
|
|
5163
5385
|
formatName: 'CSV',
|
|
5164
5386
|
aliases: ['SPREADSHEET', 'TABLE'],
|
|
5165
5387
|
isValid(value, settings, schema) {
|
|
5166
|
-
return
|
|
5388
|
+
return isValidCsvString(value);
|
|
5167
5389
|
},
|
|
5168
5390
|
canBeValid(partialValue, settings, schema) {
|
|
5169
5391
|
return true;
|
|
@@ -5317,6 +5539,30 @@ const TextFormatDefinition = {
|
|
|
5317
5539
|
* TODO: [🏢] Allow to expect something inside each item of list and other formats
|
|
5318
5540
|
*/
|
|
5319
5541
|
|
|
5542
|
+
/**
|
|
5543
|
+
* Function to check if a string is valid XML
|
|
5544
|
+
*
|
|
5545
|
+
* @param value
|
|
5546
|
+
* @returns True if the string is a valid XML string, false otherwise
|
|
5547
|
+
*
|
|
5548
|
+
* @public exported from `@promptbook/utils`
|
|
5549
|
+
*/
|
|
5550
|
+
function isValidXmlString(value) {
|
|
5551
|
+
try {
|
|
5552
|
+
const parser = new DOMParser();
|
|
5553
|
+
const parsedDocument = parser.parseFromString(value, 'application/xml');
|
|
5554
|
+
const parserError = parsedDocument.getElementsByTagName('parsererror');
|
|
5555
|
+
if (parserError.length > 0) {
|
|
5556
|
+
return false;
|
|
5557
|
+
}
|
|
5558
|
+
return true;
|
|
5559
|
+
}
|
|
5560
|
+
catch (error) {
|
|
5561
|
+
assertsError(error);
|
|
5562
|
+
return false;
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
|
|
5320
5566
|
/**
|
|
5321
5567
|
* Definition for XML format
|
|
5322
5568
|
*
|
|
@@ -5326,7 +5572,7 @@ const XmlFormatDefinition = {
|
|
|
5326
5572
|
formatName: 'XML',
|
|
5327
5573
|
mimeType: 'application/xml',
|
|
5328
5574
|
isValid(value, settings, schema) {
|
|
5329
|
-
return
|
|
5575
|
+
return isValidXmlString(value);
|
|
5330
5576
|
},
|
|
5331
5577
|
canBeValid(partialValue, settings, schema) {
|
|
5332
5578
|
return true;
|
|
@@ -5918,9 +6164,7 @@ async function executeAttempts(options) {
|
|
|
5918
6164
|
break scripts;
|
|
5919
6165
|
}
|
|
5920
6166
|
catch (error) {
|
|
5921
|
-
|
|
5922
|
-
throw error;
|
|
5923
|
-
}
|
|
6167
|
+
assertsError(error);
|
|
5924
6168
|
if (error instanceof UnexpectedError) {
|
|
5925
6169
|
throw error;
|
|
5926
6170
|
}
|
|
@@ -5990,9 +6234,7 @@ async function executeAttempts(options) {
|
|
|
5990
6234
|
break scripts;
|
|
5991
6235
|
}
|
|
5992
6236
|
catch (error) {
|
|
5993
|
-
|
|
5994
|
-
throw error;
|
|
5995
|
-
}
|
|
6237
|
+
assertsError(error);
|
|
5996
6238
|
if (error instanceof UnexpectedError) {
|
|
5997
6239
|
throw error;
|
|
5998
6240
|
}
|
|
@@ -6613,9 +6855,7 @@ async function executePipeline(options) {
|
|
|
6613
6855
|
await Promise.all(resolving);
|
|
6614
6856
|
}
|
|
6615
6857
|
catch (error /* <- Note: [3] */) {
|
|
6616
|
-
|
|
6617
|
-
throw error;
|
|
6618
|
-
}
|
|
6858
|
+
assertsError(error);
|
|
6619
6859
|
// Note: No need to rethrow UnexpectedError
|
|
6620
6860
|
// if (error instanceof UnexpectedError) {
|
|
6621
6861
|
// Note: Count usage, [🧠] Maybe put to separate function executionReportJsonToUsage + DRY [🤹♂️]
|
|
@@ -7091,9 +7331,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
|
|
|
7091
7331
|
knowledgePreparedUnflatten[index] = pieces;
|
|
7092
7332
|
}
|
|
7093
7333
|
catch (error) {
|
|
7094
|
-
|
|
7095
|
-
throw error;
|
|
7096
|
-
}
|
|
7334
|
+
assertsError(error);
|
|
7097
7335
|
console.warn(error);
|
|
7098
7336
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
7099
7337
|
}
|
|
@@ -7891,6 +8129,8 @@ function parseNumber(value) {
|
|
|
7891
8129
|
*/
|
|
7892
8130
|
|
|
7893
8131
|
/**
|
|
8132
|
+
import { WrappedError } from '../../errors/WrappedError';
|
|
8133
|
+
import { assertsError } from '../../errors/assertsError';
|
|
7894
8134
|
* Parses the expect command
|
|
7895
8135
|
*
|
|
7896
8136
|
* @see `documentationUrl` for more details
|
|
@@ -7982,9 +8222,7 @@ const expectCommandParser = {
|
|
|
7982
8222
|
};
|
|
7983
8223
|
}
|
|
7984
8224
|
catch (error) {
|
|
7985
|
-
|
|
7986
|
-
throw error;
|
|
7987
|
-
}
|
|
8225
|
+
assertsError(error);
|
|
7988
8226
|
throw new ParseError(spaceTrim((block) => `
|
|
7989
8227
|
Invalid FORMAT command
|
|
7990
8228
|
${block(error.message)}:
|
|
@@ -11232,9 +11470,7 @@ class JavascriptEvalExecutionTools {
|
|
|
11232
11470
|
}
|
|
11233
11471
|
}
|
|
11234
11472
|
catch (error) {
|
|
11235
|
-
|
|
11236
|
-
throw error;
|
|
11237
|
-
}
|
|
11473
|
+
assertsError(error);
|
|
11238
11474
|
if (error instanceof ReferenceError) {
|
|
11239
11475
|
const undefinedName = error.message.split(' ')[0];
|
|
11240
11476
|
/*
|
|
@@ -11509,9 +11745,7 @@ async function createCollectionFromDirectory(rootPath, tools, options) {
|
|
|
11509
11745
|
// ---
|
|
11510
11746
|
}
|
|
11511
11747
|
catch (error) {
|
|
11512
|
-
|
|
11513
|
-
throw error;
|
|
11514
|
-
}
|
|
11748
|
+
assertsError(error);
|
|
11515
11749
|
// TODO: [7] DRY
|
|
11516
11750
|
const wrappedErrorMessage = spaceTrim((block) => `
|
|
11517
11751
|
${error.name} in pipeline ${fileName.split('\\').join('/')}:
|
|
@@ -11602,9 +11836,7 @@ async function createCollectionFromDirectory(rootPath, tools, options) {
|
|
|
11602
11836
|
}
|
|
11603
11837
|
}
|
|
11604
11838
|
catch (error) {
|
|
11605
|
-
|
|
11606
|
-
throw error;
|
|
11607
|
-
}
|
|
11839
|
+
assertsError(error);
|
|
11608
11840
|
// TODO: [7] DRY
|
|
11609
11841
|
const wrappedErrorMessage = spaceTrim((block) => `
|
|
11610
11842
|
${error.name} in pipeline ${fileName.split('\\').join('/')}:
|
|
@@ -11820,7 +12052,7 @@ function $initializeMakeCommand(program) {
|
|
|
11820
12052
|
isCacheReloaded,
|
|
11821
12053
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
11822
12054
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
11823
|
-
const llm = await $provideLlmToolsForCli({
|
|
12055
|
+
const { llm } = await $provideLlmToolsForCli({
|
|
11824
12056
|
cliOptions,
|
|
11825
12057
|
...prepareAndScrapeOptions,
|
|
11826
12058
|
});
|
|
@@ -12113,9 +12345,7 @@ function $initializePrettifyCommand(program) {
|
|
|
12113
12345
|
}
|
|
12114
12346
|
}
|
|
12115
12347
|
catch (error) {
|
|
12116
|
-
|
|
12117
|
-
throw error;
|
|
12118
|
-
}
|
|
12348
|
+
assertsError(error);
|
|
12119
12349
|
console.info(colors.red(`Prettify ${error.name} ${filename}`));
|
|
12120
12350
|
console.error(colors.bgRed(`${error.name} in ${basename(__filename)}`));
|
|
12121
12351
|
console.error(colors.red(error.stack || error.message));
|
|
@@ -12435,9 +12665,7 @@ function isValidPipelineString(pipelineString) {
|
|
|
12435
12665
|
return true;
|
|
12436
12666
|
}
|
|
12437
12667
|
catch (error) {
|
|
12438
|
-
|
|
12439
|
-
throw error;
|
|
12440
|
-
}
|
|
12668
|
+
assertsError(error);
|
|
12441
12669
|
return false;
|
|
12442
12670
|
}
|
|
12443
12671
|
}
|
|
@@ -12662,9 +12890,7 @@ async function runInteractiveChatbot(options) {
|
|
|
12662
12890
|
ongoingParameters = result.outputParameters;
|
|
12663
12891
|
}
|
|
12664
12892
|
catch (error) {
|
|
12665
|
-
|
|
12666
|
-
throw error;
|
|
12667
|
-
}
|
|
12893
|
+
assertsError(error);
|
|
12668
12894
|
// TODO: Allow to ressurect the chatbot after an error - prompt the user to continue
|
|
12669
12895
|
console.error(colors.red(error.stack || error.message));
|
|
12670
12896
|
return process.exit(1);
|
|
@@ -12697,7 +12923,6 @@ function $initializeRunCommand(program) {
|
|
|
12697
12923
|
runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
|
|
12698
12924
|
runCommand.option('-s, --save-report <path>', `Save report to file`);
|
|
12699
12925
|
runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
|
|
12700
|
-
console.log('!!!', cliOptions);
|
|
12701
12926
|
const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
|
|
12702
12927
|
if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
|
|
12703
12928
|
console.error(colors.red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
|
|
@@ -12723,12 +12948,10 @@ function $initializeRunCommand(program) {
|
|
|
12723
12948
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
12724
12949
|
let llm;
|
|
12725
12950
|
try {
|
|
12726
|
-
llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
12951
|
+
llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
|
|
12727
12952
|
}
|
|
12728
12953
|
catch (error) {
|
|
12729
|
-
|
|
12730
|
-
throw error;
|
|
12731
|
-
}
|
|
12954
|
+
assertsError(error);
|
|
12732
12955
|
if (!error.message.includes('No LLM tools')) {
|
|
12733
12956
|
throw error;
|
|
12734
12957
|
}
|
|
@@ -12934,6 +13157,198 @@ function $initializeRunCommand(program) {
|
|
|
12934
13157
|
* TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
|
|
12935
13158
|
*/
|
|
12936
13159
|
|
|
13160
|
+
// TODO: !!!! List running services from REMOTE_SERVER_URLS
|
|
13161
|
+
// TODO: !!!! Import directly from YML
|
|
13162
|
+
/**
|
|
13163
|
+
* @private !!!! Decide how to expose this
|
|
13164
|
+
*/
|
|
13165
|
+
const openapiJson = {
|
|
13166
|
+
openapi: '3.0.0',
|
|
13167
|
+
info: {
|
|
13168
|
+
title: 'Promptbook Remote Server API (!!!! From TS)',
|
|
13169
|
+
version: '1.0.0',
|
|
13170
|
+
description: 'API documentation for the Promptbook Remote Server',
|
|
13171
|
+
},
|
|
13172
|
+
paths: {
|
|
13173
|
+
'/': {
|
|
13174
|
+
get: {
|
|
13175
|
+
summary: 'Get server details',
|
|
13176
|
+
description: 'Returns details about the Promptbook server.',
|
|
13177
|
+
responses: {
|
|
13178
|
+
'200': {
|
|
13179
|
+
description: 'Server details in markdown format.',
|
|
13180
|
+
},
|
|
13181
|
+
},
|
|
13182
|
+
},
|
|
13183
|
+
},
|
|
13184
|
+
'/login': {
|
|
13185
|
+
post: {
|
|
13186
|
+
summary: 'Login to the server',
|
|
13187
|
+
description: 'Login to the server and get identification.',
|
|
13188
|
+
requestBody: {
|
|
13189
|
+
required: true,
|
|
13190
|
+
content: {
|
|
13191
|
+
'application/json': {
|
|
13192
|
+
schema: {
|
|
13193
|
+
type: 'object',
|
|
13194
|
+
properties: {
|
|
13195
|
+
username: {
|
|
13196
|
+
type: 'string',
|
|
13197
|
+
},
|
|
13198
|
+
password: {
|
|
13199
|
+
type: 'string',
|
|
13200
|
+
},
|
|
13201
|
+
appId: {
|
|
13202
|
+
type: 'string',
|
|
13203
|
+
},
|
|
13204
|
+
},
|
|
13205
|
+
},
|
|
13206
|
+
},
|
|
13207
|
+
},
|
|
13208
|
+
},
|
|
13209
|
+
responses: {
|
|
13210
|
+
'200': {
|
|
13211
|
+
description: 'Successful login',
|
|
13212
|
+
content: {
|
|
13213
|
+
'application/json': {
|
|
13214
|
+
schema: {
|
|
13215
|
+
type: 'object',
|
|
13216
|
+
properties: {
|
|
13217
|
+
identification: {
|
|
13218
|
+
type: 'object',
|
|
13219
|
+
},
|
|
13220
|
+
},
|
|
13221
|
+
},
|
|
13222
|
+
},
|
|
13223
|
+
},
|
|
13224
|
+
},
|
|
13225
|
+
},
|
|
13226
|
+
},
|
|
13227
|
+
},
|
|
13228
|
+
'/books': {
|
|
13229
|
+
get: {
|
|
13230
|
+
summary: 'List all books',
|
|
13231
|
+
description: 'Returns a list of all available books in the collection.',
|
|
13232
|
+
responses: {
|
|
13233
|
+
'200': {
|
|
13234
|
+
description: 'A list of books.',
|
|
13235
|
+
content: {
|
|
13236
|
+
'application/json': {
|
|
13237
|
+
schema: {
|
|
13238
|
+
type: 'array',
|
|
13239
|
+
items: {
|
|
13240
|
+
type: 'string',
|
|
13241
|
+
},
|
|
13242
|
+
},
|
|
13243
|
+
},
|
|
13244
|
+
},
|
|
13245
|
+
},
|
|
13246
|
+
},
|
|
13247
|
+
},
|
|
13248
|
+
},
|
|
13249
|
+
'/books/{bookId}': {
|
|
13250
|
+
get: {
|
|
13251
|
+
summary: 'Get book content',
|
|
13252
|
+
description: 'Returns the content of a specific book.',
|
|
13253
|
+
parameters: [
|
|
13254
|
+
{
|
|
13255
|
+
in: 'path',
|
|
13256
|
+
name: 'bookId',
|
|
13257
|
+
required: true,
|
|
13258
|
+
schema: {
|
|
13259
|
+
type: 'string',
|
|
13260
|
+
},
|
|
13261
|
+
description: 'The ID of the book to retrieve.',
|
|
13262
|
+
},
|
|
13263
|
+
],
|
|
13264
|
+
responses: {
|
|
13265
|
+
'200': {
|
|
13266
|
+
description: 'The content of the book.',
|
|
13267
|
+
content: {
|
|
13268
|
+
'text/markdown': {
|
|
13269
|
+
schema: {
|
|
13270
|
+
type: 'string',
|
|
13271
|
+
},
|
|
13272
|
+
},
|
|
13273
|
+
},
|
|
13274
|
+
},
|
|
13275
|
+
'404': {
|
|
13276
|
+
description: 'Book not found.',
|
|
13277
|
+
},
|
|
13278
|
+
},
|
|
13279
|
+
},
|
|
13280
|
+
},
|
|
13281
|
+
'/executions': {
|
|
13282
|
+
get: {
|
|
13283
|
+
summary: 'List all executions',
|
|
13284
|
+
description: 'Returns a list of all running execution tasks.',
|
|
13285
|
+
responses: {
|
|
13286
|
+
'200': {
|
|
13287
|
+
description: 'A list of execution tasks.',
|
|
13288
|
+
content: {
|
|
13289
|
+
'application/json': {
|
|
13290
|
+
schema: {
|
|
13291
|
+
type: 'array',
|
|
13292
|
+
items: {
|
|
13293
|
+
type: 'object',
|
|
13294
|
+
},
|
|
13295
|
+
},
|
|
13296
|
+
},
|
|
13297
|
+
},
|
|
13298
|
+
},
|
|
13299
|
+
},
|
|
13300
|
+
},
|
|
13301
|
+
},
|
|
13302
|
+
'/executions/new': {
|
|
13303
|
+
post: {
|
|
13304
|
+
summary: 'Start a new execution',
|
|
13305
|
+
description: 'Starts a new execution task for a given pipeline.',
|
|
13306
|
+
requestBody: {
|
|
13307
|
+
required: true,
|
|
13308
|
+
content: {
|
|
13309
|
+
'application/json': {
|
|
13310
|
+
schema: {
|
|
13311
|
+
type: 'object',
|
|
13312
|
+
properties: {
|
|
13313
|
+
pipelineUrl: {
|
|
13314
|
+
type: 'string',
|
|
13315
|
+
},
|
|
13316
|
+
inputParameters: {
|
|
13317
|
+
type: 'object',
|
|
13318
|
+
},
|
|
13319
|
+
identification: {
|
|
13320
|
+
type: 'object',
|
|
13321
|
+
},
|
|
13322
|
+
},
|
|
13323
|
+
},
|
|
13324
|
+
},
|
|
13325
|
+
},
|
|
13326
|
+
},
|
|
13327
|
+
responses: {
|
|
13328
|
+
'200': {
|
|
13329
|
+
description: 'The newly created execution task.',
|
|
13330
|
+
content: {
|
|
13331
|
+
'application/json': {
|
|
13332
|
+
schema: {
|
|
13333
|
+
type: 'object',
|
|
13334
|
+
},
|
|
13335
|
+
},
|
|
13336
|
+
},
|
|
13337
|
+
},
|
|
13338
|
+
'400': {
|
|
13339
|
+
description: 'Invalid input.',
|
|
13340
|
+
},
|
|
13341
|
+
},
|
|
13342
|
+
},
|
|
13343
|
+
},
|
|
13344
|
+
},
|
|
13345
|
+
components: {},
|
|
13346
|
+
tags: [],
|
|
13347
|
+
};
|
|
13348
|
+
/**
|
|
13349
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13350
|
+
*/
|
|
13351
|
+
|
|
12937
13352
|
/**
|
|
12938
13353
|
* Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
|
|
12939
13354
|
*
|
|
@@ -12944,7 +13359,7 @@ function $initializeRunCommand(program) {
|
|
|
12944
13359
|
* @public exported from `@promptbook/remote-server`
|
|
12945
13360
|
*/
|
|
12946
13361
|
function startRemoteServer(options) {
|
|
12947
|
-
const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
|
|
13362
|
+
const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
|
|
12948
13363
|
isAnonymousModeAllowed: false,
|
|
12949
13364
|
isApplicationModeAllowed: false,
|
|
12950
13365
|
collection: null,
|
|
@@ -12952,22 +13367,6 @@ function startRemoteServer(options) {
|
|
|
12952
13367
|
login: null,
|
|
12953
13368
|
...options,
|
|
12954
13369
|
};
|
|
12955
|
-
// <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
|
|
12956
|
-
let { rootPath = '/' } = options;
|
|
12957
|
-
if (!rootPath.startsWith('/')) {
|
|
12958
|
-
rootPath = `/${rootPath}`;
|
|
12959
|
-
} /* not else */
|
|
12960
|
-
if (rootPath.endsWith('/')) {
|
|
12961
|
-
rootPath = rootPath.slice(0, -1);
|
|
12962
|
-
} /* not else */
|
|
12963
|
-
if (rootPath === '/') {
|
|
12964
|
-
rootPath = '';
|
|
12965
|
-
}
|
|
12966
|
-
const socketioPath = '/' +
|
|
12967
|
-
`${rootPath}/socket.io`
|
|
12968
|
-
.split('/')
|
|
12969
|
-
.filter((part) => part !== '')
|
|
12970
|
-
.join('/');
|
|
12971
13370
|
const startupDate = new Date();
|
|
12972
13371
|
async function getExecutionToolsFromIdentification(identification) {
|
|
12973
13372
|
if (identification === null || identification === undefined) {
|
|
@@ -12990,23 +13389,25 @@ function startRemoteServer(options) {
|
|
|
12990
13389
|
}
|
|
12991
13390
|
else if (isAnonymous === false && createLlmExecutionTools !== null) {
|
|
12992
13391
|
// Note: Application mode
|
|
12993
|
-
|
|
12994
|
-
llm = await createLlmExecutionTools({
|
|
12995
|
-
appId,
|
|
12996
|
-
userId,
|
|
12997
|
-
customOptions,
|
|
12998
|
-
});
|
|
13392
|
+
llm = await createLlmExecutionTools(identification);
|
|
12999
13393
|
}
|
|
13000
13394
|
else {
|
|
13001
13395
|
throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
|
|
13002
13396
|
}
|
|
13003
|
-
const
|
|
13004
|
-
const
|
|
13397
|
+
const customExecutionTools = createExecutionTools ? await createExecutionTools(identification) : {};
|
|
13398
|
+
const fs = customExecutionTools.fs || $provideFilesystemForNode();
|
|
13399
|
+
const executables = customExecutionTools.executables || (await $provideExecutablesForNode());
|
|
13400
|
+
const scrapers = customExecutionTools.scrapers || (await $provideScrapersForNode({ fs, llm, executables }));
|
|
13401
|
+
const script = customExecutionTools.script || (await $provideScriptingForNode({}));
|
|
13402
|
+
const fetch = customExecutionTools.fetch || promptbookFetch;
|
|
13403
|
+
const userInterface = customExecutionTools.userInterface || undefined;
|
|
13005
13404
|
const tools = {
|
|
13006
13405
|
llm,
|
|
13007
13406
|
fs,
|
|
13008
|
-
scrapers
|
|
13009
|
-
script
|
|
13407
|
+
scrapers,
|
|
13408
|
+
script,
|
|
13409
|
+
fetch,
|
|
13410
|
+
userInterface,
|
|
13010
13411
|
};
|
|
13011
13412
|
return tools;
|
|
13012
13413
|
}
|
|
@@ -13016,39 +13417,27 @@ function startRemoteServer(options) {
|
|
|
13016
13417
|
response.setHeader('X-Powered-By', 'Promptbook engine');
|
|
13017
13418
|
next();
|
|
13018
13419
|
});
|
|
13019
|
-
|
|
13020
|
-
|
|
13021
|
-
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
version: '1.0.0',
|
|
13025
|
-
description: 'API documentation for the Promptbook Remote Server',
|
|
13026
|
-
},
|
|
13027
|
-
servers: [
|
|
13028
|
-
{
|
|
13029
|
-
url: `http://localhost:${port}${rootPath}`,
|
|
13030
|
-
// <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
|
|
13031
|
-
},
|
|
13032
|
-
],
|
|
13420
|
+
// TODO: !!!! Expose openapiJson to consumer and also allow to add new routes
|
|
13421
|
+
app.use(OpenApiValidator.middleware({
|
|
13422
|
+
apiSpec: openapiJson,
|
|
13423
|
+
ignorePaths(path) {
|
|
13424
|
+
return path.startsWith('/api-docs') || path.startsWith('/swagger') || path.startsWith('/openapi');
|
|
13033
13425
|
},
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
app.use([`/api-docs`,
|
|
13426
|
+
validateRequests: true,
|
|
13427
|
+
validateResponses: true,
|
|
13428
|
+
}));
|
|
13429
|
+
app.use([`/api-docs`, `/swagger`], swaggerUi.serve, swaggerUi.setup(openapiJson, {
|
|
13430
|
+
// customCss: '.swagger-ui .topbar { display: none }',
|
|
13431
|
+
// customSiteTitle: 'BRJ API',
|
|
13432
|
+
// customfavIcon: 'https://brj.app/favicon.ico',
|
|
13433
|
+
}));
|
|
13434
|
+
app.get(`/openapi`, (request, response) => {
|
|
13435
|
+
response.json(openapiJson);
|
|
13436
|
+
});
|
|
13038
13437
|
const runningExecutionTasks = [];
|
|
13039
13438
|
// <- TODO: [🤬] Identify the users
|
|
13040
13439
|
// TODO: [🧠] Do here some garbage collection of finished tasks
|
|
13041
|
-
|
|
13042
|
-
* @swagger
|
|
13043
|
-
* /:
|
|
13044
|
-
* get:
|
|
13045
|
-
* summary: Get server details
|
|
13046
|
-
* description: Returns details about the Promptbook server.
|
|
13047
|
-
* responses:
|
|
13048
|
-
* 200:
|
|
13049
|
-
* description: Server details in markdown format.
|
|
13050
|
-
*/
|
|
13051
|
-
app.get(['/', rootPath], async (request, response) => {
|
|
13440
|
+
app.get('/', async (request, response) => {
|
|
13052
13441
|
var _a;
|
|
13053
13442
|
if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
|
|
13054
13443
|
return;
|
|
@@ -13067,8 +13456,6 @@ function startRemoteServer(options) {
|
|
|
13067
13456
|
## Details
|
|
13068
13457
|
|
|
13069
13458
|
**Server port:** ${port}
|
|
13070
|
-
**Server root path:** ${rootPath}
|
|
13071
|
-
**Socket.io path:** ${socketioPath}
|
|
13072
13459
|
**Startup date:** ${startupDate.toISOString()}
|
|
13073
13460
|
**Anonymouse mode:** ${isAnonymousModeAllowed ? 'enabled' : 'disabled'}
|
|
13074
13461
|
**Application mode:** ${isApplicationModeAllowed ? 'enabled' : 'disabled'}
|
|
@@ -13107,38 +13494,7 @@ function startRemoteServer(options) {
|
|
|
13107
13494
|
https://github.com/webgptorg/promptbook
|
|
13108
13495
|
`));
|
|
13109
13496
|
});
|
|
13110
|
-
|
|
13111
|
-
* @swagger
|
|
13112
|
-
*
|
|
13113
|
-
* /login:
|
|
13114
|
-
* post:
|
|
13115
|
-
* summary: Login to the server
|
|
13116
|
-
* description: Login to the server and get identification.
|
|
13117
|
-
* requestBody:
|
|
13118
|
-
* required: true
|
|
13119
|
-
* content:
|
|
13120
|
-
* application/json:
|
|
13121
|
-
* schema:
|
|
13122
|
-
* type: object
|
|
13123
|
-
* properties:
|
|
13124
|
-
* username:
|
|
13125
|
-
* type: string
|
|
13126
|
-
* password:
|
|
13127
|
-
* type: string
|
|
13128
|
-
* appId:
|
|
13129
|
-
* type: string
|
|
13130
|
-
* responses:
|
|
13131
|
-
* 200:
|
|
13132
|
-
* description: Successful login
|
|
13133
|
-
* content:
|
|
13134
|
-
* application/json:
|
|
13135
|
-
* schema:
|
|
13136
|
-
* type: object
|
|
13137
|
-
* properties:
|
|
13138
|
-
* identification:
|
|
13139
|
-
* type: object
|
|
13140
|
-
*/
|
|
13141
|
-
app.post([`/login`, `${rootPath}/login`], async (request, response) => {
|
|
13497
|
+
app.post(`/login`, async (request, response) => {
|
|
13142
13498
|
if (!isApplicationModeAllowed || login === null) {
|
|
13143
13499
|
response.status(400).send('Application mode is not allowed');
|
|
13144
13500
|
return;
|
|
@@ -13163,9 +13519,7 @@ function startRemoteServer(options) {
|
|
|
13163
13519
|
return;
|
|
13164
13520
|
}
|
|
13165
13521
|
catch (error) {
|
|
13166
|
-
|
|
13167
|
-
throw error;
|
|
13168
|
-
}
|
|
13522
|
+
assertsError(error);
|
|
13169
13523
|
if (error instanceof AuthenticationError) {
|
|
13170
13524
|
response.status(401).send({
|
|
13171
13525
|
isSuccess: false,
|
|
@@ -13180,23 +13534,7 @@ function startRemoteServer(options) {
|
|
|
13180
13534
|
response.status(400).send({ error: serializeError(error) });
|
|
13181
13535
|
}
|
|
13182
13536
|
});
|
|
13183
|
-
|
|
13184
|
-
* @swagger
|
|
13185
|
-
* /books:
|
|
13186
|
-
* get:
|
|
13187
|
-
* summary: List all books
|
|
13188
|
-
* description: Returns a list of all available books in the collection.
|
|
13189
|
-
* responses:
|
|
13190
|
-
* 200:
|
|
13191
|
-
* description: A list of books.
|
|
13192
|
-
* content:
|
|
13193
|
-
* application/json:
|
|
13194
|
-
* schema:
|
|
13195
|
-
* type: array
|
|
13196
|
-
* items:
|
|
13197
|
-
* type: string
|
|
13198
|
-
*/
|
|
13199
|
-
app.get([`/books`, `${rootPath}/books`], async (request, response) => {
|
|
13537
|
+
app.get(`/books`, async (request, response) => {
|
|
13200
13538
|
if (collection === null) {
|
|
13201
13539
|
response.status(500).send('No collection available');
|
|
13202
13540
|
return;
|
|
@@ -13206,30 +13544,7 @@ function startRemoteServer(options) {
|
|
|
13206
13544
|
response.send(pipelines);
|
|
13207
13545
|
});
|
|
13208
13546
|
// TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
|
|
13209
|
-
|
|
13210
|
-
* @swagger
|
|
13211
|
-
* /books/{bookId}:
|
|
13212
|
-
* get:
|
|
13213
|
-
* summary: Get book content
|
|
13214
|
-
* description: Returns the content of a specific book.
|
|
13215
|
-
* parameters:
|
|
13216
|
-
* - in: path
|
|
13217
|
-
* name: bookId
|
|
13218
|
-
* required: true
|
|
13219
|
-
* schema:
|
|
13220
|
-
* type: string
|
|
13221
|
-
* description: The ID of the book to retrieve.
|
|
13222
|
-
* responses:
|
|
13223
|
-
* 200:
|
|
13224
|
-
* description: The content of the book.
|
|
13225
|
-
* content:
|
|
13226
|
-
* text/markdown:
|
|
13227
|
-
* schema:
|
|
13228
|
-
* type: string
|
|
13229
|
-
* 404:
|
|
13230
|
-
* description: Book not found.
|
|
13231
|
-
*/
|
|
13232
|
-
app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
|
|
13547
|
+
app.get(`/books/*`, async (request, response) => {
|
|
13233
13548
|
try {
|
|
13234
13549
|
if (collection === null) {
|
|
13235
13550
|
response.status(500).send('No collection nor books available');
|
|
@@ -13248,9 +13563,7 @@ function startRemoteServer(options) {
|
|
|
13248
13563
|
.send(source.content);
|
|
13249
13564
|
}
|
|
13250
13565
|
catch (error) {
|
|
13251
|
-
|
|
13252
|
-
throw error;
|
|
13253
|
-
}
|
|
13566
|
+
assertsError(error);
|
|
13254
13567
|
response
|
|
13255
13568
|
.status(404)
|
|
13256
13569
|
.send({ error: serializeError(error) });
|
|
@@ -13283,26 +13596,10 @@ function startRemoteServer(options) {
|
|
|
13283
13596
|
};
|
|
13284
13597
|
}
|
|
13285
13598
|
}
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
* /executions:
|
|
13289
|
-
* get:
|
|
13290
|
-
* summary: List all executions
|
|
13291
|
-
* description: Returns a list of all running execution tasks.
|
|
13292
|
-
* responses:
|
|
13293
|
-
* 200:
|
|
13294
|
-
* description: A list of execution tasks.
|
|
13295
|
-
* content:
|
|
13296
|
-
* application/json:
|
|
13297
|
-
* schema:
|
|
13298
|
-
* type: array
|
|
13299
|
-
* items:
|
|
13300
|
-
* type: object
|
|
13301
|
-
*/
|
|
13302
|
-
app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
|
|
13303
|
-
response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
|
|
13599
|
+
app.get(`/executions`, async (request, response) => {
|
|
13600
|
+
response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)) /* <- TODO: satisfies paths['/executions']['get']['responses']['200']['content']['application/json'] */);
|
|
13304
13601
|
});
|
|
13305
|
-
app.get(
|
|
13602
|
+
app.get(`/executions/last`, async (request, response) => {
|
|
13306
13603
|
// TODO: [🤬] Filter only for user
|
|
13307
13604
|
if (runningExecutionTasks.length === 0) {
|
|
13308
13605
|
response.status(404).send('No execution tasks found');
|
|
@@ -13311,7 +13608,7 @@ function startRemoteServer(options) {
|
|
|
13311
13608
|
const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
|
|
13312
13609
|
response.send(exportExecutionTask(lastExecutionTask, true));
|
|
13313
13610
|
});
|
|
13314
|
-
app.get(
|
|
13611
|
+
app.get(`/executions/:taskId`, async (request, response) => {
|
|
13315
13612
|
const { taskId } = request.params;
|
|
13316
13613
|
// TODO: [🤬] Filter only for user
|
|
13317
13614
|
const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
|
|
@@ -13323,39 +13620,12 @@ function startRemoteServer(options) {
|
|
|
13323
13620
|
}
|
|
13324
13621
|
response.send(exportExecutionTask(executionTask, true));
|
|
13325
13622
|
});
|
|
13326
|
-
|
|
13327
|
-
* @swagger
|
|
13328
|
-
* /executions/new:
|
|
13329
|
-
* post:
|
|
13330
|
-
* summary: Start a new execution
|
|
13331
|
-
* description: Starts a new execution task for a given pipeline.
|
|
13332
|
-
* requestBody:
|
|
13333
|
-
* required: true
|
|
13334
|
-
* content:
|
|
13335
|
-
* application/json:
|
|
13336
|
-
* schema:
|
|
13337
|
-
* type: object
|
|
13338
|
-
* properties:
|
|
13339
|
-
* pipelineUrl:
|
|
13340
|
-
* type: string
|
|
13341
|
-
* inputParameters:
|
|
13342
|
-
* type: object
|
|
13343
|
-
* identification:
|
|
13344
|
-
* type: object
|
|
13345
|
-
* responses:
|
|
13346
|
-
* 200:
|
|
13347
|
-
* description: The newly created execution task.
|
|
13348
|
-
* content:
|
|
13349
|
-
* application/json:
|
|
13350
|
-
* schema:
|
|
13351
|
-
* type: object
|
|
13352
|
-
* 400:
|
|
13353
|
-
* description: Invalid input.
|
|
13354
|
-
*/
|
|
13355
|
-
app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
|
|
13623
|
+
app.post(`/executions/new`, async (request, response) => {
|
|
13356
13624
|
try {
|
|
13357
13625
|
const { inputParameters, identification /* <- [🤬] */ } = request.body;
|
|
13358
|
-
const pipelineUrl = request.body
|
|
13626
|
+
const pipelineUrl = request.body
|
|
13627
|
+
.pipelineUrl /* <- TODO: as paths['/executions/new']['post']['requestBody']['content']['application/json'] */ ||
|
|
13628
|
+
request.body.book;
|
|
13359
13629
|
// TODO: [🧠] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
|
|
13360
13630
|
const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));
|
|
13361
13631
|
if (pipeline === undefined) {
|
|
@@ -13369,7 +13639,7 @@ function startRemoteServer(options) {
|
|
|
13369
13639
|
await forTime(10);
|
|
13370
13640
|
// <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
|
|
13371
13641
|
// <- TODO: Put this into configuration
|
|
13372
|
-
response.send(executionTask);
|
|
13642
|
+
response.send(executionTask /* <- TODO: satisfies paths['/executions/new']['post']['responses']['200']['content']['application/json'] */);
|
|
13373
13643
|
/*/
|
|
13374
13644
|
executionTask.asObservable().subscribe({
|
|
13375
13645
|
next(partialResult) {
|
|
@@ -13389,19 +13659,24 @@ function startRemoteServer(options) {
|
|
|
13389
13659
|
*/
|
|
13390
13660
|
}
|
|
13391
13661
|
catch (error) {
|
|
13392
|
-
|
|
13393
|
-
throw error;
|
|
13394
|
-
}
|
|
13662
|
+
assertsError(error);
|
|
13395
13663
|
response.status(400).send({ error: serializeError(error) });
|
|
13396
13664
|
}
|
|
13397
13665
|
});
|
|
13666
|
+
/**
|
|
13667
|
+
* Catch-all handler for unmatched routes
|
|
13668
|
+
*/
|
|
13669
|
+
app.use((request, response) => {
|
|
13670
|
+
response.status(404).send(`URL "${request.originalUrl}" was not found on Promptbook server.`);
|
|
13671
|
+
});
|
|
13398
13672
|
const httpServer = http.createServer(app);
|
|
13399
13673
|
const server = new Server(httpServer, {
|
|
13400
|
-
path:
|
|
13401
|
-
transports: [
|
|
13674
|
+
path: '/socket.io',
|
|
13675
|
+
transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
|
|
13402
13676
|
cors: {
|
|
13403
13677
|
origin: '*',
|
|
13404
13678
|
methods: ['GET', 'POST'],
|
|
13679
|
+
// <- TODO: [🌡] Allow to pass
|
|
13405
13680
|
},
|
|
13406
13681
|
});
|
|
13407
13682
|
server.on('connection', (socket) => {
|
|
@@ -13455,9 +13730,7 @@ function startRemoteServer(options) {
|
|
|
13455
13730
|
socket.emit('prompt-response', { promptResult } /* <- Note: [🤛] */);
|
|
13456
13731
|
}
|
|
13457
13732
|
catch (error) {
|
|
13458
|
-
|
|
13459
|
-
throw error;
|
|
13460
|
-
}
|
|
13733
|
+
assertsError(error);
|
|
13461
13734
|
socket.emit('error', serializeError(error) /* <- Note: [🤛] */);
|
|
13462
13735
|
}
|
|
13463
13736
|
finally {
|
|
@@ -13479,9 +13752,7 @@ function startRemoteServer(options) {
|
|
|
13479
13752
|
socket.emit('listModels-response', { models } /* <- Note: [🤛] */);
|
|
13480
13753
|
}
|
|
13481
13754
|
catch (error) {
|
|
13482
|
-
|
|
13483
|
-
throw error;
|
|
13484
|
-
}
|
|
13755
|
+
assertsError(error);
|
|
13485
13756
|
socket.emit('error', serializeError(error));
|
|
13486
13757
|
}
|
|
13487
13758
|
finally {
|
|
@@ -13502,9 +13773,7 @@ function startRemoteServer(options) {
|
|
|
13502
13773
|
socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [🤛] */);
|
|
13503
13774
|
}
|
|
13504
13775
|
catch (error) {
|
|
13505
|
-
|
|
13506
|
-
throw error;
|
|
13507
|
-
}
|
|
13776
|
+
assertsError(error);
|
|
13508
13777
|
socket.emit('error', serializeError(error));
|
|
13509
13778
|
// <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
|
|
13510
13779
|
}
|
|
@@ -13552,8 +13821,7 @@ function startRemoteServer(options) {
|
|
|
13552
13821
|
};
|
|
13553
13822
|
}
|
|
13554
13823
|
/**
|
|
13555
|
-
* TODO:
|
|
13556
|
-
* TODO: [👩🏾🤝🧑🏾] Allow to pass custom fetch function here - PromptbookFetch
|
|
13824
|
+
* TODO: [🌡] Add CORS and security - probbably via `helmet`
|
|
13557
13825
|
* TODO: Split this file into multiple functions - handler for each request
|
|
13558
13826
|
* TODO: Maybe use `$exportJson`
|
|
13559
13827
|
* TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
|
|
@@ -13612,9 +13880,9 @@ function $initializeStartServerCommand(program) {
|
|
|
13612
13880
|
if (url !== null) {
|
|
13613
13881
|
rootUrl = suffixUrl(url, '/books');
|
|
13614
13882
|
}
|
|
13615
|
-
|
|
13616
|
-
|
|
13617
|
-
|
|
13883
|
+
if (url !== null && url.pathname !== '/' && url.pathname !== '') {
|
|
13884
|
+
console.error(colors.red(`URL of the server can not have path, but got "${url.pathname}"`));
|
|
13885
|
+
process.exit(1);
|
|
13618
13886
|
}
|
|
13619
13887
|
// TODO: DRY [◽]
|
|
13620
13888
|
const prepareAndScrapeOptions = {
|
|
@@ -13622,7 +13890,7 @@ function $initializeStartServerCommand(program) {
|
|
|
13622
13890
|
isCacheReloaded,
|
|
13623
13891
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13624
13892
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13625
|
-
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13893
|
+
const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13626
13894
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13627
13895
|
const tools = {
|
|
13628
13896
|
llm,
|
|
@@ -13641,7 +13909,6 @@ function $initializeStartServerCommand(program) {
|
|
|
13641
13909
|
});
|
|
13642
13910
|
// console.log(path, await collection.listPipelines());
|
|
13643
13911
|
const server = startRemoteServer({
|
|
13644
|
-
rootPath,
|
|
13645
13912
|
port,
|
|
13646
13913
|
isAnonymousModeAllowed,
|
|
13647
13914
|
isApplicationModeAllowed: true,
|
|
@@ -13654,6 +13921,7 @@ function $initializeStartServerCommand(program) {
|
|
|
13654
13921
|
TODO_USE({ appId, userId });
|
|
13655
13922
|
return llm;
|
|
13656
13923
|
},
|
|
13924
|
+
// <- TODO: [🧠][0] Maybe pass here strategy
|
|
13657
13925
|
});
|
|
13658
13926
|
keepUnused(server);
|
|
13659
13927
|
// Note: Already logged by `startRemoteServer`
|
|
@@ -13695,7 +13963,7 @@ function $initializeTestCommand(program) {
|
|
|
13695
13963
|
isCacheReloaded,
|
|
13696
13964
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13697
13965
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13698
|
-
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13966
|
+
const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13699
13967
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13700
13968
|
tools = {
|
|
13701
13969
|
llm,
|
|
@@ -13734,9 +14002,7 @@ function $initializeTestCommand(program) {
|
|
|
13734
14002
|
}
|
|
13735
14003
|
}
|
|
13736
14004
|
catch (error) {
|
|
13737
|
-
|
|
13738
|
-
throw error;
|
|
13739
|
-
}
|
|
14005
|
+
assertsError(error);
|
|
13740
14006
|
console.info(colors.red(`Pipeline is not valid ${filename}`));
|
|
13741
14007
|
console.error(colors.bgRed(`${error.name} in ${basename(__filename)}`));
|
|
13742
14008
|
console.error(colors.red(error.stack || error.message));
|
|
@@ -13960,7 +14226,25 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
|
|
|
13960
14226
|
output: computeUsage(`$2.40 / 1M tokens`),
|
|
13961
14227
|
},
|
|
13962
14228
|
},
|
|
13963
|
-
|
|
14229
|
+
{
|
|
14230
|
+
modelVariant: 'CHAT',
|
|
14231
|
+
modelTitle: 'Claude 3.7 Sonnet',
|
|
14232
|
+
modelName: 'claude-3-7-sonnet-20250219',
|
|
14233
|
+
pricing: {
|
|
14234
|
+
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14235
|
+
output: computeUsage(`$15.00 / 1M tokens`),
|
|
14236
|
+
},
|
|
14237
|
+
},
|
|
14238
|
+
{
|
|
14239
|
+
modelVariant: 'CHAT',
|
|
14240
|
+
modelTitle: 'Claude 3.5 Haiku',
|
|
14241
|
+
modelName: 'claude-3-5-haiku-20241022',
|
|
14242
|
+
pricing: {
|
|
14243
|
+
prompt: computeUsage(`$0.25 / 1M tokens`),
|
|
14244
|
+
output: computeUsage(`$1.25 / 1M tokens`),
|
|
14245
|
+
},
|
|
14246
|
+
},
|
|
14247
|
+
// <- [🕕]
|
|
13964
14248
|
],
|
|
13965
14249
|
});
|
|
13966
14250
|
/**
|
|
@@ -14725,7 +15009,6 @@ const OPENAI_MODELS = exportJson({
|
|
|
14725
15009
|
prompt: computeUsage(`$5.00 / 1M tokens`),
|
|
14726
15010
|
output: computeUsage(`$15.00 / 1M tokens`),
|
|
14727
15011
|
},
|
|
14728
|
-
//TODO: [main] !!3 Add gpt-4o-mini-2024-07-18 and all others to be up to date
|
|
14729
15012
|
},
|
|
14730
15013
|
/**/
|
|
14731
15014
|
/**/
|
|
@@ -14740,6 +15023,17 @@ const OPENAI_MODELS = exportJson({
|
|
|
14740
15023
|
},
|
|
14741
15024
|
/**/
|
|
14742
15025
|
/**/
|
|
15026
|
+
{
|
|
15027
|
+
modelVariant: 'CHAT',
|
|
15028
|
+
modelTitle: 'gpt-4o-mini',
|
|
15029
|
+
modelName: 'gpt-4o-mini',
|
|
15030
|
+
pricing: {
|
|
15031
|
+
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
15032
|
+
output: computeUsage(`$9.00 / 1M tokens`),
|
|
15033
|
+
},
|
|
15034
|
+
},
|
|
15035
|
+
/**/
|
|
15036
|
+
/**/
|
|
14743
15037
|
{
|
|
14744
15038
|
modelVariant: 'CHAT',
|
|
14745
15039
|
modelTitle: 'o1-preview',
|
|
@@ -14819,6 +15113,7 @@ const OPENAI_MODELS = exportJson({
|
|
|
14819
15113
|
},
|
|
14820
15114
|
},
|
|
14821
15115
|
/**/
|
|
15116
|
+
// <- [🕕]
|
|
14822
15117
|
],
|
|
14823
15118
|
});
|
|
14824
15119
|
/**
|
|
@@ -15387,11 +15682,17 @@ const createDeepseekExecutionTools = Object.assign((options) => {
|
|
|
15387
15682
|
description: 'Implementation of Deepseek models',
|
|
15388
15683
|
vercelProvider: deepseekVercelProvider,
|
|
15389
15684
|
availableModels: [
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15685
|
+
{
|
|
15686
|
+
modelName: 'deepseek-chat',
|
|
15687
|
+
modelVariant: 'CHAT',
|
|
15688
|
+
},
|
|
15689
|
+
{
|
|
15690
|
+
modelName: 'deepseek-reasoner',
|
|
15691
|
+
modelVariant: 'CHAT',
|
|
15692
|
+
},
|
|
15693
|
+
// <- [🕕]
|
|
15393
15694
|
// <- TODO: How picking of the default model looks like in `createExecutionToolsFromVercelProvider`
|
|
15394
|
-
]
|
|
15695
|
+
],
|
|
15395
15696
|
...options,
|
|
15396
15697
|
});
|
|
15397
15698
|
}, {
|
|
@@ -15489,6 +15790,10 @@ const createGoogleExecutionTools = Object.assign((options) => {
|
|
|
15489
15790
|
vercelProvider: googleGeminiVercelProvider,
|
|
15490
15791
|
availableModels: [
|
|
15491
15792
|
// TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
|
|
15793
|
+
'gemini-2.5-pro-preview-03-25',
|
|
15794
|
+
'gemini-2.0-flash',
|
|
15795
|
+
'gemini-2.0-flash-lite',
|
|
15796
|
+
'gemini-2.0-flash-thinking-exp-01-21',
|
|
15492
15797
|
'gemini-1.5-flash',
|
|
15493
15798
|
'gemini-1.5-flash-latest',
|
|
15494
15799
|
'gemini-1.5-flash-001',
|
|
@@ -15504,6 +15809,7 @@ const createGoogleExecutionTools = Object.assign((options) => {
|
|
|
15504
15809
|
'gemini-1.5-pro-002',
|
|
15505
15810
|
'gemini-1.5-pro-exp-0827',
|
|
15506
15811
|
'gemini-1.0-pro',
|
|
15812
|
+
// <- [🕕]
|
|
15507
15813
|
].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
|
|
15508
15814
|
...options,
|
|
15509
15815
|
});
|
|
@@ -15783,6 +16089,7 @@ class OpenAiExecutionTools {
|
|
|
15783
16089
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15784
16090
|
}
|
|
15785
16091
|
const rawResponse = await client.chat.completions.create(rawRequest).catch((error) => {
|
|
16092
|
+
assertsError(error);
|
|
15786
16093
|
if (this.options.isVerbose) {
|
|
15787
16094
|
console.info(colors.bgRed('error'), error);
|
|
15788
16095
|
}
|
|
@@ -15859,6 +16166,7 @@ class OpenAiExecutionTools {
|
|
|
15859
16166
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15860
16167
|
}
|
|
15861
16168
|
const rawResponse = await client.completions.create(rawRequest).catch((error) => {
|
|
16169
|
+
assertsError(error);
|
|
15862
16170
|
if (this.options.isVerbose) {
|
|
15863
16171
|
console.info(colors.bgRed('error'), error);
|
|
15864
16172
|
}
|
|
@@ -15922,6 +16230,7 @@ class OpenAiExecutionTools {
|
|
|
15922
16230
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15923
16231
|
}
|
|
15924
16232
|
const rawResponse = await client.embeddings.create(rawRequest).catch((error) => {
|
|
16233
|
+
assertsError(error);
|
|
15925
16234
|
if (this.options.isVerbose) {
|
|
15926
16235
|
console.info(colors.bgRed('error'), error);
|
|
15927
16236
|
}
|