@promptbook/node 0.112.0-71 → 0.112.0-72
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/esm/index.es.js +1403 -1272
- package/esm/index.es.js.map +1 -1
- package/esm/src/book-3.0/Book.d.ts +6 -0
- package/esm/src/book-components/Chat/utils/getToolCallChipletInfo.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agent/agentRunCliOptions.d.ts +12 -2
- package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -0
- package/esm/src/cli/cli-commands/run/prepareRunCommandResources.d.ts +20 -0
- package/esm/src/cli/cli-commands/run/resolveRunInputParameters.d.ts +12 -0
- package/esm/src/cli/cli-commands/run/runCommandAction.d.ts +21 -0
- package/esm/src/cli/cli-commands/run/runPipelineExecution.d.ts +14 -0
- package/esm/src/cli/cli-commands/run.d.ts +1 -1
- package/esm/src/conversion/parsePipeline/applyPipelineHead.d.ts +8 -0
- package/esm/src/conversion/parsePipeline/createInitialPipelineJson.d.ts +8 -0
- package/esm/src/conversion/parsePipeline/createUniqueSectionNameResolver.d.ts +14 -0
- package/esm/src/conversion/parsePipeline/defineParameter.d.ts +8 -0
- package/esm/src/conversion/parsePipeline/extractPipelineDescription.d.ts +6 -0
- package/esm/src/conversion/parsePipeline/finalizeParsedPipeline.d.ts +8 -0
- package/esm/src/conversion/parsePipeline/getPipelineIdentification.d.ts +7 -0
- package/esm/src/conversion/parsePipeline/parsePreparedPipelineSections.d.ts +18 -0
- package/esm/src/conversion/parsePipeline/preparePipelineString.d.ts +8 -0
- package/esm/src/conversion/parsePipeline/processPipelineSection.d.ts +9 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +1403 -1272
- package/umd/index.umd.js.map +1 -1
- package/umd/src/book-3.0/Book.d.ts +6 -0
- package/umd/src/book-components/Chat/utils/getToolCallChipletInfo.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agent/agentRunCliOptions.d.ts +12 -2
- package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -0
- package/umd/src/cli/cli-commands/run/prepareRunCommandResources.d.ts +20 -0
- package/umd/src/cli/cli-commands/run/resolveRunInputParameters.d.ts +12 -0
- package/umd/src/cli/cli-commands/run/runCommandAction.d.ts +21 -0
- package/umd/src/cli/cli-commands/run/runPipelineExecution.d.ts +14 -0
- package/umd/src/cli/cli-commands/run.d.ts +1 -1
- package/umd/src/conversion/parsePipeline/applyPipelineHead.d.ts +8 -0
- package/umd/src/conversion/parsePipeline/createInitialPipelineJson.d.ts +8 -0
- package/umd/src/conversion/parsePipeline/createUniqueSectionNameResolver.d.ts +14 -0
- package/umd/src/conversion/parsePipeline/defineParameter.d.ts +8 -0
- package/umd/src/conversion/parsePipeline/extractPipelineDescription.d.ts +6 -0
- package/umd/src/conversion/parsePipeline/finalizeParsedPipeline.d.ts +8 -0
- package/umd/src/conversion/parsePipeline/getPipelineIdentification.d.ts +7 -0
- package/umd/src/conversion/parsePipeline/parsePreparedPipelineSections.d.ts +18 -0
- package/umd/src/conversion/parsePipeline/preparePipelineString.d.ts +8 -0
- package/umd/src/conversion/parsePipeline/processPipelineSection.d.ts +9 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -35,7 +35,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
35
35
|
* @generated
|
|
36
36
|
* @see https://github.com/webgptorg/promptbook
|
|
37
37
|
*/
|
|
38
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
38
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-72';
|
|
39
39
|
/**
|
|
40
40
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
41
41
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -7608,118 +7608,75 @@ async function preparePipeline(pipeline, tools, options) {
|
|
|
7608
7608
|
*/
|
|
7609
7609
|
|
|
7610
7610
|
/**
|
|
7611
|
-
*
|
|
7612
|
-
*
|
|
7613
|
-
* There is is distinction between task types and section types
|
|
7614
|
-
* - Every section in markdown has its SectionType
|
|
7615
|
-
* - Some sections are tasks but other can be non-task sections
|
|
7616
|
-
*
|
|
7617
|
-
* @public exported from `@promptbook/core`
|
|
7618
|
-
*/
|
|
7619
|
-
const TaskTypes = [
|
|
7620
|
-
'PROMPT',
|
|
7621
|
-
'SIMPLE',
|
|
7622
|
-
'SCRIPT',
|
|
7623
|
-
'DIALOG',
|
|
7624
|
-
// <- [🅱]
|
|
7625
|
-
];
|
|
7626
|
-
|
|
7627
|
-
/**
|
|
7628
|
-
* All available sections which are not tasks
|
|
7629
|
-
*
|
|
7630
|
-
* @public exported from `@promptbook/core`
|
|
7631
|
-
*/
|
|
7632
|
-
const NonTaskSectionTypes = ['EXAMPLE', 'KNOWLEDGE', 'INSTRUMENT', 'ACTION'];
|
|
7633
|
-
/**
|
|
7634
|
-
* All available section types
|
|
7635
|
-
*
|
|
7636
|
-
* There is is distinction between task types and section types
|
|
7637
|
-
* - Every section in markdown has its SectionType
|
|
7638
|
-
* - Some sections are tasks but other can be non-task sections
|
|
7611
|
+
* Parses the boilerplate command
|
|
7639
7612
|
*
|
|
7640
|
-
*
|
|
7641
|
-
*/
|
|
7642
|
-
const SectionTypes = [
|
|
7643
|
-
...TaskTypes.map((TaskType) => `${TaskType}_TASK`),
|
|
7644
|
-
...NonTaskSectionTypes,
|
|
7645
|
-
];
|
|
7646
|
-
|
|
7647
|
-
/**
|
|
7648
|
-
* Parses the knowledge command
|
|
7613
|
+
* Note: @@ This command is used as boilerplate for new commands - it should NOT be used in any `.book` file
|
|
7649
7614
|
*
|
|
7650
7615
|
* @see `documentationUrl` for more details
|
|
7651
7616
|
*
|
|
7652
|
-
* @
|
|
7617
|
+
* @private within the commands folder
|
|
7653
7618
|
*/
|
|
7654
|
-
const
|
|
7619
|
+
const boilerplateCommandParser = {
|
|
7655
7620
|
/**
|
|
7656
7621
|
* Name of the command
|
|
7657
7622
|
*/
|
|
7658
|
-
name: '
|
|
7623
|
+
name: 'BOILERPLATE',
|
|
7624
|
+
/**
|
|
7625
|
+
* Aliases for the BOILERPLATE command
|
|
7626
|
+
*/
|
|
7627
|
+
aliasNames: ['BP'],
|
|
7659
7628
|
/**
|
|
7660
7629
|
* BOILERPLATE command can be used in:
|
|
7661
7630
|
*/
|
|
7662
7631
|
isUsedInPipelineHead: true,
|
|
7663
|
-
isUsedInPipelineTask:
|
|
7632
|
+
isUsedInPipelineTask: true,
|
|
7664
7633
|
/**
|
|
7665
|
-
* Description of the
|
|
7634
|
+
* Description of the BOILERPLATE command
|
|
7666
7635
|
*/
|
|
7667
|
-
description:
|
|
7636
|
+
description: `@@`,
|
|
7668
7637
|
/**
|
|
7669
7638
|
* Link to documentation
|
|
7670
7639
|
*/
|
|
7671
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions
|
|
7640
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
|
|
7672
7641
|
/**
|
|
7673
|
-
* Example usages of the
|
|
7642
|
+
* Example usages of the BOILERPLATE command
|
|
7674
7643
|
*/
|
|
7675
|
-
examples: [
|
|
7676
|
-
'KNOWLEDGE https://www.pavolhejny.com/',
|
|
7677
|
-
'KNOWLEDGE ./hejny-cv.txt',
|
|
7678
|
-
'KNOWLEDGE ./hejny-cv.md',
|
|
7679
|
-
'KNOWLEDGE ./hejny-cv.pdf',
|
|
7680
|
-
'KNOWLEDGE ./hejny-cv.docx',
|
|
7681
|
-
// <- TODO: [😿] Allow ONLY files scoped in the (sub)directory NOT ../ and test it
|
|
7682
|
-
],
|
|
7644
|
+
examples: ['BOILERPLATE foo', 'BOILERPLATE bar', 'BP foo', 'BP bar'],
|
|
7683
7645
|
/**
|
|
7684
|
-
* Parses the
|
|
7646
|
+
* Parses the BOILERPLATE command
|
|
7685
7647
|
*/
|
|
7686
7648
|
parse(input) {
|
|
7687
7649
|
const { args } = input;
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
throw new ParseError(`Source is not defined`);
|
|
7691
|
-
}
|
|
7692
|
-
// TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
|
|
7693
|
-
if (knowledgeSourceContent.startsWith('http://')) {
|
|
7694
|
-
throw new ParseError(`Source is not secure`);
|
|
7695
|
-
}
|
|
7696
|
-
if (!(isValidFilePath(knowledgeSourceContent) || isValidUrl(knowledgeSourceContent))) {
|
|
7697
|
-
throw new ParseError(`Source not valid`);
|
|
7650
|
+
if (args.length !== 1) {
|
|
7651
|
+
throw new ParseError(`BOILERPLATE command requires exactly one argument`);
|
|
7698
7652
|
}
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
throw new ParseError(`Source cannot be outside of the .book.md folder`);
|
|
7653
|
+
const value = args[0].toLowerCase();
|
|
7654
|
+
if (value.includes('brr')) {
|
|
7655
|
+
throw new ParseError(`BOILERPLATE value can not contain brr`);
|
|
7703
7656
|
}
|
|
7704
7657
|
return {
|
|
7705
|
-
type: '
|
|
7706
|
-
|
|
7658
|
+
type: 'BOILERPLATE',
|
|
7659
|
+
value,
|
|
7707
7660
|
};
|
|
7708
7661
|
},
|
|
7709
7662
|
/**
|
|
7710
|
-
* Apply the
|
|
7663
|
+
* Apply the BOILERPLATE command to the `pipelineJson`
|
|
7711
7664
|
*
|
|
7712
7665
|
* Note: `$` is used to indicate that this function mutates given `pipelineJson`
|
|
7713
7666
|
*/
|
|
7714
7667
|
$applyToPipelineJson(command, $pipelineJson) {
|
|
7715
|
-
|
|
7716
|
-
$pipelineJson.knowledgeSources.push({
|
|
7717
|
-
name: knowledgeSourceContentToName(knowledgeSourceContent),
|
|
7718
|
-
knowledgeSourceContent,
|
|
7719
|
-
});
|
|
7668
|
+
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7720
7669
|
},
|
|
7721
7670
|
/**
|
|
7722
|
-
*
|
|
7671
|
+
* Apply the BOILERPLATE command to the `pipelineJson`
|
|
7672
|
+
*
|
|
7673
|
+
* Note: `$` is used to indicate that this function mutates given `taskJson`
|
|
7674
|
+
*/
|
|
7675
|
+
$applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
7676
|
+
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7677
|
+
},
|
|
7678
|
+
/**
|
|
7679
|
+
* Converts the BOILERPLATE command back to string
|
|
7723
7680
|
*
|
|
7724
7681
|
* Note: This is used in `pipelineJsonToString` utility
|
|
7725
7682
|
*/
|
|
@@ -7727,354 +7684,77 @@ const knowledgeCommandParser = {
|
|
|
7727
7684
|
return `---`; // <- TODO: [🛋] Implement
|
|
7728
7685
|
},
|
|
7729
7686
|
/**
|
|
7730
|
-
* Reads the
|
|
7687
|
+
* Reads the BOILERPLATE command from the `PipelineJson`
|
|
7731
7688
|
*
|
|
7732
7689
|
* Note: This is used in `pipelineJsonToString` utility
|
|
7733
7690
|
*/
|
|
7734
7691
|
takeFromPipelineJson(pipelineJson) {
|
|
7735
|
-
throw new
|
|
7692
|
+
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7693
|
+
},
|
|
7694
|
+
/**
|
|
7695
|
+
* Reads the BOILERPLATE command from the `TaskJson`
|
|
7696
|
+
*
|
|
7697
|
+
* Note: This is used in `pipelineJsonToString` utility
|
|
7698
|
+
*/
|
|
7699
|
+
takeFromTaskJson($taskJson) {
|
|
7700
|
+
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7736
7701
|
},
|
|
7737
7702
|
};
|
|
7738
|
-
// Note: [⛱] There are two types of KNOWLEDGE commands *...(read more in [⛱])*
|
|
7739
7703
|
|
|
7740
7704
|
/**
|
|
7741
|
-
* Parses the
|
|
7705
|
+
* Parses the BOOK_VERSION command
|
|
7742
7706
|
*
|
|
7743
7707
|
* @see `documentationUrl` for more details
|
|
7744
7708
|
*
|
|
7745
7709
|
* @public exported from `@promptbook/editable`
|
|
7746
7710
|
*/
|
|
7747
|
-
const
|
|
7711
|
+
const bookVersionCommandParser = {
|
|
7748
7712
|
/**
|
|
7749
7713
|
* Name of the command
|
|
7750
7714
|
*/
|
|
7751
|
-
name: '
|
|
7752
|
-
|
|
7753
|
-
* Aliases for the SECTION command
|
|
7754
|
-
*/
|
|
7755
|
-
aliasNames: [
|
|
7756
|
-
'PROMPT',
|
|
7757
|
-
'SIMPLE',
|
|
7758
|
-
'SCRIPT',
|
|
7759
|
-
'DIALOG',
|
|
7760
|
-
'SAMPLE',
|
|
7761
|
-
'EXAMPLE',
|
|
7762
|
-
'KNOWLEDGE',
|
|
7763
|
-
'INSTRUMENT',
|
|
7764
|
-
'ACTION', // <- Note: [⛱]
|
|
7765
|
-
],
|
|
7766
|
-
/**
|
|
7767
|
-
* Aliases for the SECTION command
|
|
7768
|
-
*/
|
|
7769
|
-
deprecatedNames: ['TEMPLATE', 'BLOCK', 'EXECUTE'],
|
|
7715
|
+
name: 'BOOK_VERSION',
|
|
7716
|
+
aliasNames: ['PTBK_VERSION', 'PROMPTBOOK_VERSION', 'BOOK'],
|
|
7770
7717
|
/**
|
|
7771
7718
|
* BOILERPLATE command can be used in:
|
|
7772
7719
|
*/
|
|
7773
|
-
isUsedInPipelineHead:
|
|
7774
|
-
isUsedInPipelineTask:
|
|
7720
|
+
isUsedInPipelineHead: true,
|
|
7721
|
+
isUsedInPipelineTask: false,
|
|
7775
7722
|
/**
|
|
7776
|
-
* Description of the
|
|
7723
|
+
* Description of the BOOK_VERSION command
|
|
7777
7724
|
*/
|
|
7778
|
-
description: `
|
|
7725
|
+
description: `Which version of the Book language is the .book.md using`,
|
|
7779
7726
|
/**
|
|
7780
7727
|
* Link to documentation
|
|
7781
7728
|
*/
|
|
7782
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/
|
|
7729
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/69',
|
|
7783
7730
|
/**
|
|
7784
|
-
* Example usages of the
|
|
7731
|
+
* Example usages of the BOOK_VERSION command
|
|
7785
7732
|
*/
|
|
7786
|
-
examples: [
|
|
7787
|
-
// Short form:
|
|
7788
|
-
'PROMPT',
|
|
7789
|
-
'SIMPLE',
|
|
7790
|
-
'SCRIPT',
|
|
7791
|
-
'DIALOG',
|
|
7792
|
-
// <- [🅱]
|
|
7793
|
-
'EXAMPLE',
|
|
7794
|
-
'KNOWLEDGE',
|
|
7795
|
-
'INSTRUMENT',
|
|
7796
|
-
'ACTION',
|
|
7797
|
-
// -----------------
|
|
7798
|
-
// Recommended (reversed) form:
|
|
7799
|
-
'PROMPT SECTION',
|
|
7800
|
-
'SIMPLE SECTION',
|
|
7801
|
-
'SCRIPT SECTION',
|
|
7802
|
-
'DIALOG SECTION',
|
|
7803
|
-
// <- [🅱]
|
|
7804
|
-
'EXAMPLE SECTION',
|
|
7805
|
-
'KNOWLEDGE SECTION',
|
|
7806
|
-
'INSTRUMENT SECTION',
|
|
7807
|
-
'ACTION SECTION',
|
|
7808
|
-
// -----------------
|
|
7809
|
-
// Standard form:
|
|
7810
|
-
'SECTION PROMPT',
|
|
7811
|
-
'SECTION SIMPLE',
|
|
7812
|
-
'SECTION SCRIPT',
|
|
7813
|
-
'SECTION DIALOG',
|
|
7814
|
-
// <- [🅱]
|
|
7815
|
-
'SECTION EXAMPLE',
|
|
7816
|
-
'SECTION KNOWLEDGE',
|
|
7817
|
-
'SECTION INSTRUMENT',
|
|
7818
|
-
'SECTION ACTION',
|
|
7819
|
-
],
|
|
7820
|
-
// TODO: [♓️] order: -10 /* <- Note: Putting before other commands */
|
|
7733
|
+
examples: [`BOOK VERSION ${BOOK_LANGUAGE_VERSION}`, `BOOK ${BOOK_LANGUAGE_VERSION}`],
|
|
7821
7734
|
/**
|
|
7822
|
-
* Parses the
|
|
7735
|
+
* Parses the BOOK_VERSION command
|
|
7823
7736
|
*/
|
|
7824
7737
|
parse(input) {
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
if (
|
|
7831
|
-
throw new ParseError(
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
${block(SectionTypes.join(', '))}
|
|
7836
|
-
`));
|
|
7738
|
+
const { args } = input;
|
|
7739
|
+
const bookVersion = args.pop();
|
|
7740
|
+
if (bookVersion === undefined) {
|
|
7741
|
+
throw new ParseError(`Version is required`);
|
|
7742
|
+
}
|
|
7743
|
+
if (!isValidPromptbookVersion(bookVersion)) {
|
|
7744
|
+
throw new ParseError(`Invalid Promptbook version "${bookVersion}"`);
|
|
7745
|
+
}
|
|
7746
|
+
if (args.length > 0 && !(((args.length === 1 && args[0]) || '').toUpperCase() === 'VERSION')) {
|
|
7747
|
+
throw new ParseError(`Can not have more than one Promptbook version`);
|
|
7837
7748
|
}
|
|
7838
|
-
const taskType = taskTypes[0];
|
|
7839
7749
|
return {
|
|
7840
|
-
type: '
|
|
7841
|
-
|
|
7750
|
+
type: 'BOOK_VERSION',
|
|
7751
|
+
bookVersion: bookVersion,
|
|
7842
7752
|
};
|
|
7843
7753
|
},
|
|
7844
7754
|
/**
|
|
7845
|
-
* Apply the
|
|
7755
|
+
* Apply the BOOK_VERSION command to the `pipelineJson`
|
|
7846
7756
|
*
|
|
7847
|
-
* Note: `$` is used to indicate that this function mutates given `
|
|
7848
|
-
*/
|
|
7849
|
-
$applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
7850
|
-
if ($taskJson.isSectionTypeSet === true) {
|
|
7851
|
-
throw new ParseError(spaceTrim$1(`
|
|
7852
|
-
Section type is already defined in the section.
|
|
7853
|
-
It can be defined only once.
|
|
7854
|
-
`));
|
|
7855
|
-
}
|
|
7856
|
-
$taskJson.isSectionTypeSet = true;
|
|
7857
|
-
// TODO: [🍧][💩] Rearrange better - but at bottom and unwrap from function
|
|
7858
|
-
const expectResultingParameterName = () => {
|
|
7859
|
-
if ($taskJson.resultingParameterName) {
|
|
7860
|
-
return;
|
|
7861
|
-
}
|
|
7862
|
-
throw new ParseError(`Task section and example section must end with return statement -> {parameterName}`);
|
|
7863
|
-
};
|
|
7864
|
-
if ($taskJson.content === undefined) {
|
|
7865
|
-
throw new UnexpectedError(`Content is missing in the taskJson - probably commands are applied in wrong order`);
|
|
7866
|
-
}
|
|
7867
|
-
if (command.taskType === 'EXAMPLE') {
|
|
7868
|
-
expectResultingParameterName();
|
|
7869
|
-
const parameter = $pipelineJson.parameters.find((param) => param.name === $taskJson.resultingParameterName);
|
|
7870
|
-
if (parameter === undefined) {
|
|
7871
|
-
// TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
|
|
7872
|
-
throw new ParseError(`Parameter \`{${$taskJson.resultingParameterName}}\` is not defined so can not define example value of it`);
|
|
7873
|
-
}
|
|
7874
|
-
parameter.exampleValues = parameter.exampleValues || [];
|
|
7875
|
-
parameter.exampleValues.push($taskJson.content);
|
|
7876
|
-
$taskJson.isTask = false;
|
|
7877
|
-
return;
|
|
7878
|
-
}
|
|
7879
|
-
if (command.taskType === 'KNOWLEDGE') {
|
|
7880
|
-
knowledgeCommandParser.$applyToPipelineJson({
|
|
7881
|
-
type: 'KNOWLEDGE',
|
|
7882
|
-
knowledgeSourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
|
|
7883
|
-
}, $pipelineJson);
|
|
7884
|
-
$taskJson.isTask = false;
|
|
7885
|
-
return;
|
|
7886
|
-
}
|
|
7887
|
-
if (command.taskType === 'ACTION') {
|
|
7888
|
-
console.error(new NotYetImplementedError('Actions are not implemented yet'));
|
|
7889
|
-
$taskJson.isTask = false;
|
|
7890
|
-
return;
|
|
7891
|
-
}
|
|
7892
|
-
if (command.taskType === 'INSTRUMENT') {
|
|
7893
|
-
console.error(new NotYetImplementedError('Instruments are not implemented yet'));
|
|
7894
|
-
$taskJson.isTask = false;
|
|
7895
|
-
return;
|
|
7896
|
-
}
|
|
7897
|
-
expectResultingParameterName();
|
|
7898
|
-
$taskJson.taskType = command.taskType;
|
|
7899
|
-
$taskJson.isTask = true;
|
|
7900
|
-
},
|
|
7901
|
-
/**
|
|
7902
|
-
* Converts the SECTION command back to string
|
|
7903
|
-
*
|
|
7904
|
-
* Note: This is used in `pipelineJsonToString` utility
|
|
7905
|
-
*/
|
|
7906
|
-
stringify(command) {
|
|
7907
|
-
return `---`; // <- TODO: [🛋] Implement
|
|
7908
|
-
},
|
|
7909
|
-
/**
|
|
7910
|
-
* Reads the SECTION command from the `TaskJson`
|
|
7911
|
-
*
|
|
7912
|
-
* Note: This is used in `pipelineJsonToString` utility
|
|
7913
|
-
*/
|
|
7914
|
-
takeFromTaskJson($taskJson) {
|
|
7915
|
-
throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
|
|
7916
|
-
},
|
|
7917
|
-
};
|
|
7918
|
-
/**
|
|
7919
|
-
* Note: [⛱] There are two types of KNOWLEDGE, ACTION and INSTRUMENT commands:
|
|
7920
|
-
* 1) There are commands `KNOWLEDGE`, `ACTION` and `INSTRUMENT` used in the pipeline head, they just define the knowledge, action or instrument as single line after the command
|
|
7921
|
-
* - KNOWLEDGE Look at https://en.wikipedia.org/wiki/Artificial_intelligence
|
|
7922
|
-
* 2) `KNOWLEDGE SECTION` which has short form `KNOWLEDGE` is used in the sectiom, does not refer the line itself, but the content of the section block
|
|
7923
|
-
* - KNOWLEDGE SECTION
|
|
7924
|
-
*
|
|
7925
|
-
* ```
|
|
7926
|
-
* Look at https://en.wikipedia.org/wiki/Artificial_intelligence
|
|
7927
|
-
* ```
|
|
7928
|
-
*/
|
|
7929
|
-
|
|
7930
|
-
/**
|
|
7931
|
-
* Parses the boilerplate command
|
|
7932
|
-
*
|
|
7933
|
-
* Note: @@ This command is used as boilerplate for new commands - it should NOT be used in any `.book` file
|
|
7934
|
-
*
|
|
7935
|
-
* @see `documentationUrl` for more details
|
|
7936
|
-
*
|
|
7937
|
-
* @private within the commands folder
|
|
7938
|
-
*/
|
|
7939
|
-
const boilerplateCommandParser = {
|
|
7940
|
-
/**
|
|
7941
|
-
* Name of the command
|
|
7942
|
-
*/
|
|
7943
|
-
name: 'BOILERPLATE',
|
|
7944
|
-
/**
|
|
7945
|
-
* Aliases for the BOILERPLATE command
|
|
7946
|
-
*/
|
|
7947
|
-
aliasNames: ['BP'],
|
|
7948
|
-
/**
|
|
7949
|
-
* BOILERPLATE command can be used in:
|
|
7950
|
-
*/
|
|
7951
|
-
isUsedInPipelineHead: true,
|
|
7952
|
-
isUsedInPipelineTask: true,
|
|
7953
|
-
/**
|
|
7954
|
-
* Description of the BOILERPLATE command
|
|
7955
|
-
*/
|
|
7956
|
-
description: `@@`,
|
|
7957
|
-
/**
|
|
7958
|
-
* Link to documentation
|
|
7959
|
-
*/
|
|
7960
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
|
|
7961
|
-
/**
|
|
7962
|
-
* Example usages of the BOILERPLATE command
|
|
7963
|
-
*/
|
|
7964
|
-
examples: ['BOILERPLATE foo', 'BOILERPLATE bar', 'BP foo', 'BP bar'],
|
|
7965
|
-
/**
|
|
7966
|
-
* Parses the BOILERPLATE command
|
|
7967
|
-
*/
|
|
7968
|
-
parse(input) {
|
|
7969
|
-
const { args } = input;
|
|
7970
|
-
if (args.length !== 1) {
|
|
7971
|
-
throw new ParseError(`BOILERPLATE command requires exactly one argument`);
|
|
7972
|
-
}
|
|
7973
|
-
const value = args[0].toLowerCase();
|
|
7974
|
-
if (value.includes('brr')) {
|
|
7975
|
-
throw new ParseError(`BOILERPLATE value can not contain brr`);
|
|
7976
|
-
}
|
|
7977
|
-
return {
|
|
7978
|
-
type: 'BOILERPLATE',
|
|
7979
|
-
value,
|
|
7980
|
-
};
|
|
7981
|
-
},
|
|
7982
|
-
/**
|
|
7983
|
-
* Apply the BOILERPLATE command to the `pipelineJson`
|
|
7984
|
-
*
|
|
7985
|
-
* Note: `$` is used to indicate that this function mutates given `pipelineJson`
|
|
7986
|
-
*/
|
|
7987
|
-
$applyToPipelineJson(command, $pipelineJson) {
|
|
7988
|
-
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7989
|
-
},
|
|
7990
|
-
/**
|
|
7991
|
-
* Apply the BOILERPLATE command to the `pipelineJson`
|
|
7992
|
-
*
|
|
7993
|
-
* Note: `$` is used to indicate that this function mutates given `taskJson`
|
|
7994
|
-
*/
|
|
7995
|
-
$applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
7996
|
-
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
7997
|
-
},
|
|
7998
|
-
/**
|
|
7999
|
-
* Converts the BOILERPLATE command back to string
|
|
8000
|
-
*
|
|
8001
|
-
* Note: This is used in `pipelineJsonToString` utility
|
|
8002
|
-
*/
|
|
8003
|
-
stringify(command) {
|
|
8004
|
-
return `---`; // <- TODO: [🛋] Implement
|
|
8005
|
-
},
|
|
8006
|
-
/**
|
|
8007
|
-
* Reads the BOILERPLATE command from the `PipelineJson`
|
|
8008
|
-
*
|
|
8009
|
-
* Note: This is used in `pipelineJsonToString` utility
|
|
8010
|
-
*/
|
|
8011
|
-
takeFromPipelineJson(pipelineJson) {
|
|
8012
|
-
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
8013
|
-
},
|
|
8014
|
-
/**
|
|
8015
|
-
* Reads the BOILERPLATE command from the `TaskJson`
|
|
8016
|
-
*
|
|
8017
|
-
* Note: This is used in `pipelineJsonToString` utility
|
|
8018
|
-
*/
|
|
8019
|
-
takeFromTaskJson($taskJson) {
|
|
8020
|
-
throw new ParseError(`BOILERPLATE command is only for testing purposes and should not be used in the .book.md file`);
|
|
8021
|
-
},
|
|
8022
|
-
};
|
|
8023
|
-
|
|
8024
|
-
/**
|
|
8025
|
-
* Parses the BOOK_VERSION command
|
|
8026
|
-
*
|
|
8027
|
-
* @see `documentationUrl` for more details
|
|
8028
|
-
*
|
|
8029
|
-
* @public exported from `@promptbook/editable`
|
|
8030
|
-
*/
|
|
8031
|
-
const bookVersionCommandParser = {
|
|
8032
|
-
/**
|
|
8033
|
-
* Name of the command
|
|
8034
|
-
*/
|
|
8035
|
-
name: 'BOOK_VERSION',
|
|
8036
|
-
aliasNames: ['PTBK_VERSION', 'PROMPTBOOK_VERSION', 'BOOK'],
|
|
8037
|
-
/**
|
|
8038
|
-
* BOILERPLATE command can be used in:
|
|
8039
|
-
*/
|
|
8040
|
-
isUsedInPipelineHead: true,
|
|
8041
|
-
isUsedInPipelineTask: false,
|
|
8042
|
-
/**
|
|
8043
|
-
* Description of the BOOK_VERSION command
|
|
8044
|
-
*/
|
|
8045
|
-
description: `Which version of the Book language is the .book.md using`,
|
|
8046
|
-
/**
|
|
8047
|
-
* Link to documentation
|
|
8048
|
-
*/
|
|
8049
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/69',
|
|
8050
|
-
/**
|
|
8051
|
-
* Example usages of the BOOK_VERSION command
|
|
8052
|
-
*/
|
|
8053
|
-
examples: [`BOOK VERSION ${BOOK_LANGUAGE_VERSION}`, `BOOK ${BOOK_LANGUAGE_VERSION}`],
|
|
8054
|
-
/**
|
|
8055
|
-
* Parses the BOOK_VERSION command
|
|
8056
|
-
*/
|
|
8057
|
-
parse(input) {
|
|
8058
|
-
const { args } = input;
|
|
8059
|
-
const bookVersion = args.pop();
|
|
8060
|
-
if (bookVersion === undefined) {
|
|
8061
|
-
throw new ParseError(`Version is required`);
|
|
8062
|
-
}
|
|
8063
|
-
if (!isValidPromptbookVersion(bookVersion)) {
|
|
8064
|
-
throw new ParseError(`Invalid Promptbook version "${bookVersion}"`);
|
|
8065
|
-
}
|
|
8066
|
-
if (args.length > 0 && !(((args.length === 1 && args[0]) || '').toUpperCase() === 'VERSION')) {
|
|
8067
|
-
throw new ParseError(`Can not have more than one Promptbook version`);
|
|
8068
|
-
}
|
|
8069
|
-
return {
|
|
8070
|
-
type: 'BOOK_VERSION',
|
|
8071
|
-
bookVersion: bookVersion,
|
|
8072
|
-
};
|
|
8073
|
-
},
|
|
8074
|
-
/**
|
|
8075
|
-
* Apply the BOOK_VERSION command to the `pipelineJson`
|
|
8076
|
-
*
|
|
8077
|
-
* Note: `$` is used to indicate that this function mutates given `pipelineJson`
|
|
7757
|
+
* Note: `$` is used to indicate that this function mutates given `pipelineJson`
|
|
8078
7758
|
*/
|
|
8079
7759
|
$applyToPipelineJson(command, $pipelineJson) {
|
|
8080
7760
|
// TODO: Warn if the version is overridden
|
|
@@ -9157,63 +8837,156 @@ const jokerCommandParser = {
|
|
|
9157
8837
|
};
|
|
9158
8838
|
|
|
9159
8839
|
/**
|
|
9160
|
-
*
|
|
9161
|
-
*
|
|
9162
|
-
* @see {@link ModelVariant}
|
|
9163
|
-
*
|
|
9164
|
-
* @public exported from `@promptbook/core`
|
|
9165
|
-
*/
|
|
9166
|
-
const MODEL_VARIANTS = [
|
|
9167
|
-
'COMPLETION',
|
|
9168
|
-
'CHAT',
|
|
9169
|
-
'IMAGE_GENERATION',
|
|
9170
|
-
'EMBEDDING' /* <- TODO [🏳] */ /* <- [🤖] */,
|
|
9171
|
-
];
|
|
9172
|
-
|
|
9173
|
-
/**
|
|
9174
|
-
* Parses the model command
|
|
8840
|
+
* Parses the knowledge command
|
|
9175
8841
|
*
|
|
9176
8842
|
* @see `documentationUrl` for more details
|
|
9177
|
-
* @deprecated Option to manually set the model requirements is not recommended to use, use `PERSONA` instead
|
|
9178
8843
|
*
|
|
9179
8844
|
* @public exported from `@promptbook/editable`
|
|
9180
8845
|
*/
|
|
9181
|
-
const
|
|
8846
|
+
const knowledgeCommandParser = {
|
|
9182
8847
|
/**
|
|
9183
8848
|
* Name of the command
|
|
9184
8849
|
*/
|
|
9185
|
-
name: '
|
|
8850
|
+
name: 'KNOWLEDGE',
|
|
9186
8851
|
/**
|
|
9187
8852
|
* BOILERPLATE command can be used in:
|
|
9188
8853
|
*/
|
|
9189
8854
|
isUsedInPipelineHead: true,
|
|
9190
|
-
isUsedInPipelineTask:
|
|
8855
|
+
isUsedInPipelineTask: false,
|
|
9191
8856
|
/**
|
|
9192
|
-
* Description of the
|
|
8857
|
+
* Description of the KNOWLEDGE command
|
|
9193
8858
|
*/
|
|
9194
|
-
description: `Tells which
|
|
8859
|
+
description: `Tells promptbook which external knowledge to use`,
|
|
9195
8860
|
/**
|
|
9196
8861
|
* Link to documentation
|
|
9197
8862
|
*/
|
|
9198
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/
|
|
8863
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
|
|
9199
8864
|
/**
|
|
9200
|
-
* Example usages of the
|
|
8865
|
+
* Example usages of the KNOWLEDGE command
|
|
9201
8866
|
*/
|
|
9202
|
-
examples: [
|
|
8867
|
+
examples: [
|
|
8868
|
+
'KNOWLEDGE https://www.pavolhejny.com/',
|
|
8869
|
+
'KNOWLEDGE ./hejny-cv.txt',
|
|
8870
|
+
'KNOWLEDGE ./hejny-cv.md',
|
|
8871
|
+
'KNOWLEDGE ./hejny-cv.pdf',
|
|
8872
|
+
'KNOWLEDGE ./hejny-cv.docx',
|
|
8873
|
+
// <- TODO: [😿] Allow ONLY files scoped in the (sub)directory NOT ../ and test it
|
|
8874
|
+
],
|
|
9203
8875
|
/**
|
|
9204
|
-
* Parses the
|
|
8876
|
+
* Parses the KNOWLEDGE command
|
|
9205
8877
|
*/
|
|
9206
8878
|
parse(input) {
|
|
9207
|
-
const { args
|
|
9208
|
-
const
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
// TODO:
|
|
9213
|
-
if (
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
8879
|
+
const { args } = input;
|
|
8880
|
+
const knowledgeSourceContent = spaceTrim$1(args[0] || '');
|
|
8881
|
+
if (knowledgeSourceContent === '') {
|
|
8882
|
+
throw new ParseError(`Source is not defined`);
|
|
8883
|
+
}
|
|
8884
|
+
// TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
|
|
8885
|
+
if (knowledgeSourceContent.startsWith('http://')) {
|
|
8886
|
+
throw new ParseError(`Source is not secure`);
|
|
8887
|
+
}
|
|
8888
|
+
if (!(isValidFilePath(knowledgeSourceContent) || isValidUrl(knowledgeSourceContent))) {
|
|
8889
|
+
throw new ParseError(`Source not valid`);
|
|
8890
|
+
}
|
|
8891
|
+
if (knowledgeSourceContent.startsWith('../') ||
|
|
8892
|
+
knowledgeSourceContent.startsWith('/') ||
|
|
8893
|
+
/^[A-Z]:[\\/]+/i.test(knowledgeSourceContent)) {
|
|
8894
|
+
throw new ParseError(`Source cannot be outside of the .book.md folder`);
|
|
8895
|
+
}
|
|
8896
|
+
return {
|
|
8897
|
+
type: 'KNOWLEDGE',
|
|
8898
|
+
knowledgeSourceContent,
|
|
8899
|
+
};
|
|
8900
|
+
},
|
|
8901
|
+
/**
|
|
8902
|
+
* Apply the KNOWLEDGE command to the `pipelineJson`
|
|
8903
|
+
*
|
|
8904
|
+
* Note: `$` is used to indicate that this function mutates given `pipelineJson`
|
|
8905
|
+
*/
|
|
8906
|
+
$applyToPipelineJson(command, $pipelineJson) {
|
|
8907
|
+
const { knowledgeSourceContent } = command;
|
|
8908
|
+
$pipelineJson.knowledgeSources.push({
|
|
8909
|
+
name: knowledgeSourceContentToName(knowledgeSourceContent),
|
|
8910
|
+
knowledgeSourceContent,
|
|
8911
|
+
});
|
|
8912
|
+
},
|
|
8913
|
+
/**
|
|
8914
|
+
* Converts the KNOWLEDGE command back to string
|
|
8915
|
+
*
|
|
8916
|
+
* Note: This is used in `pipelineJsonToString` utility
|
|
8917
|
+
*/
|
|
8918
|
+
stringify(command) {
|
|
8919
|
+
return `---`; // <- TODO: [🛋] Implement
|
|
8920
|
+
},
|
|
8921
|
+
/**
|
|
8922
|
+
* Reads the KNOWLEDGE command from the `PipelineJson`
|
|
8923
|
+
*
|
|
8924
|
+
* Note: This is used in `pipelineJsonToString` utility
|
|
8925
|
+
*/
|
|
8926
|
+
takeFromPipelineJson(pipelineJson) {
|
|
8927
|
+
throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
|
|
8928
|
+
},
|
|
8929
|
+
};
|
|
8930
|
+
// Note: [⛱] There are two types of KNOWLEDGE commands *...(read more in [⛱])*
|
|
8931
|
+
|
|
8932
|
+
/**
|
|
8933
|
+
* Constant for model variants.
|
|
8934
|
+
*
|
|
8935
|
+
* @see {@link ModelVariant}
|
|
8936
|
+
*
|
|
8937
|
+
* @public exported from `@promptbook/core`
|
|
8938
|
+
*/
|
|
8939
|
+
const MODEL_VARIANTS = [
|
|
8940
|
+
'COMPLETION',
|
|
8941
|
+
'CHAT',
|
|
8942
|
+
'IMAGE_GENERATION',
|
|
8943
|
+
'EMBEDDING' /* <- TODO [🏳] */ /* <- [🤖] */,
|
|
8944
|
+
];
|
|
8945
|
+
|
|
8946
|
+
/**
|
|
8947
|
+
* Parses the model command
|
|
8948
|
+
*
|
|
8949
|
+
* @see `documentationUrl` for more details
|
|
8950
|
+
* @deprecated Option to manually set the model requirements is not recommended to use, use `PERSONA` instead
|
|
8951
|
+
*
|
|
8952
|
+
* @public exported from `@promptbook/editable`
|
|
8953
|
+
*/
|
|
8954
|
+
const modelCommandParser = {
|
|
8955
|
+
/**
|
|
8956
|
+
* Name of the command
|
|
8957
|
+
*/
|
|
8958
|
+
name: 'MODEL',
|
|
8959
|
+
/**
|
|
8960
|
+
* BOILERPLATE command can be used in:
|
|
8961
|
+
*/
|
|
8962
|
+
isUsedInPipelineHead: true,
|
|
8963
|
+
isUsedInPipelineTask: true,
|
|
8964
|
+
/**
|
|
8965
|
+
* Description of the MODEL command
|
|
8966
|
+
*/
|
|
8967
|
+
description: `Tells which \`modelRequirements\` (for example which model) to use for the prompt task execution`,
|
|
8968
|
+
/**
|
|
8969
|
+
* Link to documentation
|
|
8970
|
+
*/
|
|
8971
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/67',
|
|
8972
|
+
/**
|
|
8973
|
+
* Example usages of the MODEL command
|
|
8974
|
+
*/
|
|
8975
|
+
examples: ['MODEL VARIANT Chat', 'MODEL NAME `gpt-4`'],
|
|
8976
|
+
/**
|
|
8977
|
+
* Parses the MODEL command
|
|
8978
|
+
*/
|
|
8979
|
+
parse(input) {
|
|
8980
|
+
const { args, normalized } = input;
|
|
8981
|
+
const availableVariantsMessage = spaceTrim$1((block) => `
|
|
8982
|
+
Available variants are:
|
|
8983
|
+
${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
|
|
8984
|
+
`);
|
|
8985
|
+
// TODO: Make this more elegant and dynamically
|
|
8986
|
+
if (normalized.startsWith('MODEL_VARIANT')) {
|
|
8987
|
+
if (normalized === 'MODEL_VARIANT_CHAT') {
|
|
8988
|
+
return {
|
|
8989
|
+
type: 'MODEL',
|
|
9217
8990
|
key: 'modelVariant',
|
|
9218
8991
|
value: 'CHAT',
|
|
9219
8992
|
};
|
|
@@ -9690,69 +9463,296 @@ const postprocessCommandParser = {
|
|
|
9690
9463
|
};
|
|
9691
9464
|
|
|
9692
9465
|
/**
|
|
9693
|
-
*
|
|
9466
|
+
* All available task types
|
|
9467
|
+
*
|
|
9468
|
+
* There is is distinction between task types and section types
|
|
9469
|
+
* - Every section in markdown has its SectionType
|
|
9470
|
+
* - Some sections are tasks but other can be non-task sections
|
|
9471
|
+
*
|
|
9472
|
+
* @public exported from `@promptbook/core`
|
|
9473
|
+
*/
|
|
9474
|
+
const TaskTypes = [
|
|
9475
|
+
'PROMPT',
|
|
9476
|
+
'SIMPLE',
|
|
9477
|
+
'SCRIPT',
|
|
9478
|
+
'DIALOG',
|
|
9479
|
+
// <- [🅱]
|
|
9480
|
+
];
|
|
9481
|
+
|
|
9482
|
+
/**
|
|
9483
|
+
* All available sections which are not tasks
|
|
9484
|
+
*
|
|
9485
|
+
* @public exported from `@promptbook/core`
|
|
9486
|
+
*/
|
|
9487
|
+
const NonTaskSectionTypes = ['EXAMPLE', 'KNOWLEDGE', 'INSTRUMENT', 'ACTION'];
|
|
9488
|
+
/**
|
|
9489
|
+
* All available section types
|
|
9490
|
+
*
|
|
9491
|
+
* There is is distinction between task types and section types
|
|
9492
|
+
* - Every section in markdown has its SectionType
|
|
9493
|
+
* - Some sections are tasks but other can be non-task sections
|
|
9494
|
+
*
|
|
9495
|
+
* @public exported from `@promptbook/core`
|
|
9496
|
+
*/
|
|
9497
|
+
const SectionTypes = [
|
|
9498
|
+
...TaskTypes.map((TaskType) => `${TaskType}_TASK`),
|
|
9499
|
+
...NonTaskSectionTypes,
|
|
9500
|
+
];
|
|
9501
|
+
|
|
9502
|
+
/**
|
|
9503
|
+
* Parses the section command
|
|
9694
9504
|
*
|
|
9695
9505
|
* @see `documentationUrl` for more details
|
|
9696
9506
|
*
|
|
9697
9507
|
* @public exported from `@promptbook/editable`
|
|
9698
9508
|
*/
|
|
9699
|
-
const
|
|
9509
|
+
const sectionCommandParser = {
|
|
9700
9510
|
/**
|
|
9701
9511
|
* Name of the command
|
|
9702
9512
|
*/
|
|
9703
|
-
name: '
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
aliasNames: [
|
|
9708
|
-
|
|
9513
|
+
name: 'SECTION',
|
|
9514
|
+
/**
|
|
9515
|
+
* Aliases for the SECTION command
|
|
9516
|
+
*/
|
|
9517
|
+
aliasNames: [
|
|
9518
|
+
'PROMPT',
|
|
9519
|
+
'SIMPLE',
|
|
9520
|
+
'SCRIPT',
|
|
9521
|
+
'DIALOG',
|
|
9522
|
+
'SAMPLE',
|
|
9523
|
+
'EXAMPLE',
|
|
9524
|
+
'KNOWLEDGE',
|
|
9525
|
+
'INSTRUMENT',
|
|
9526
|
+
'ACTION', // <- Note: [⛱]
|
|
9527
|
+
],
|
|
9528
|
+
/**
|
|
9529
|
+
* Aliases for the SECTION command
|
|
9530
|
+
*/
|
|
9531
|
+
deprecatedNames: ['TEMPLATE', 'BLOCK', 'EXECUTE'],
|
|
9709
9532
|
/**
|
|
9710
9533
|
* BOILERPLATE command can be used in:
|
|
9711
9534
|
*/
|
|
9712
|
-
isUsedInPipelineHead:
|
|
9713
|
-
isUsedInPipelineTask:
|
|
9535
|
+
isUsedInPipelineHead: false,
|
|
9536
|
+
isUsedInPipelineTask: true,
|
|
9714
9537
|
/**
|
|
9715
|
-
* Description of the
|
|
9538
|
+
* Description of the SECTION command
|
|
9716
9539
|
*/
|
|
9717
|
-
description: `
|
|
9540
|
+
description: `Defines the purpose of the markdown section - if its a task and which type or something else`,
|
|
9718
9541
|
/**
|
|
9719
9542
|
* Link to documentation
|
|
9720
9543
|
*/
|
|
9721
|
-
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/
|
|
9544
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
|
|
9722
9545
|
/**
|
|
9723
|
-
* Example usages of the
|
|
9546
|
+
* Example usages of the SECTION command
|
|
9724
9547
|
*/
|
|
9725
9548
|
examples: [
|
|
9726
|
-
|
|
9727
|
-
'
|
|
9728
|
-
'
|
|
9549
|
+
// Short form:
|
|
9550
|
+
'PROMPT',
|
|
9551
|
+
'SIMPLE',
|
|
9552
|
+
'SCRIPT',
|
|
9553
|
+
'DIALOG',
|
|
9554
|
+
// <- [🅱]
|
|
9555
|
+
'EXAMPLE',
|
|
9556
|
+
'KNOWLEDGE',
|
|
9557
|
+
'INSTRUMENT',
|
|
9558
|
+
'ACTION',
|
|
9559
|
+
// -----------------
|
|
9560
|
+
// Recommended (reversed) form:
|
|
9561
|
+
'PROMPT SECTION',
|
|
9562
|
+
'SIMPLE SECTION',
|
|
9563
|
+
'SCRIPT SECTION',
|
|
9564
|
+
'DIALOG SECTION',
|
|
9565
|
+
// <- [🅱]
|
|
9566
|
+
'EXAMPLE SECTION',
|
|
9567
|
+
'KNOWLEDGE SECTION',
|
|
9568
|
+
'INSTRUMENT SECTION',
|
|
9569
|
+
'ACTION SECTION',
|
|
9570
|
+
// -----------------
|
|
9571
|
+
// Standard form:
|
|
9572
|
+
'SECTION PROMPT',
|
|
9573
|
+
'SECTION SIMPLE',
|
|
9574
|
+
'SECTION SCRIPT',
|
|
9575
|
+
'SECTION DIALOG',
|
|
9576
|
+
// <- [🅱]
|
|
9577
|
+
'SECTION EXAMPLE',
|
|
9578
|
+
'SECTION KNOWLEDGE',
|
|
9579
|
+
'SECTION INSTRUMENT',
|
|
9580
|
+
'SECTION ACTION',
|
|
9729
9581
|
],
|
|
9582
|
+
// TODO: [♓️] order: -10 /* <- Note: Putting before other commands */
|
|
9730
9583
|
/**
|
|
9731
|
-
* Parses the
|
|
9584
|
+
* Parses the SECTION command
|
|
9732
9585
|
*/
|
|
9733
9586
|
parse(input) {
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
}
|
|
9743
|
-
if (args.length > 0) {
|
|
9744
|
-
throw new ParseError(`Can not have more than one pipeline URL`);
|
|
9745
|
-
}
|
|
9746
|
-
/*
|
|
9747
|
-
TODO: [🐠 Maybe more info from `isValidPipelineUrl`:
|
|
9748
|
-
if (pipelineUrl.protocol !== 'https:') {
|
|
9749
|
-
throw new ParseError(`Protocol must be HTTPS`);
|
|
9750
|
-
}
|
|
9587
|
+
let { normalized } = input;
|
|
9588
|
+
normalized = normalized.split('SAMPLE').join('EXAMPLE');
|
|
9589
|
+
normalized = normalized.split('EXECUTE_').join('');
|
|
9590
|
+
normalized = normalized.split('DIALOGUE').join('DIALOG');
|
|
9591
|
+
const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
|
|
9592
|
+
if (taskTypes.length !== 1) {
|
|
9593
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
9594
|
+
Unknown section type "${normalized}"
|
|
9751
9595
|
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9596
|
+
Supported section types are:
|
|
9597
|
+
${block(SectionTypes.join(', '))}
|
|
9598
|
+
`));
|
|
9599
|
+
}
|
|
9600
|
+
const taskType = taskTypes[0];
|
|
9601
|
+
return {
|
|
9602
|
+
type: 'SECTION',
|
|
9603
|
+
taskType,
|
|
9604
|
+
};
|
|
9605
|
+
},
|
|
9606
|
+
/**
|
|
9607
|
+
* Apply the SECTION command to the `pipelineJson`
|
|
9608
|
+
*
|
|
9609
|
+
* Note: `$` is used to indicate that this function mutates given `taskJson`
|
|
9610
|
+
*/
|
|
9611
|
+
$applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
9612
|
+
if ($taskJson.isSectionTypeSet === true) {
|
|
9613
|
+
throw new ParseError(spaceTrim$1(`
|
|
9614
|
+
Section type is already defined in the section.
|
|
9615
|
+
It can be defined only once.
|
|
9616
|
+
`));
|
|
9617
|
+
}
|
|
9618
|
+
$taskJson.isSectionTypeSet = true;
|
|
9619
|
+
// TODO: [🍧][💩] Rearrange better - but at bottom and unwrap from function
|
|
9620
|
+
const expectResultingParameterName = () => {
|
|
9621
|
+
if ($taskJson.resultingParameterName) {
|
|
9622
|
+
return;
|
|
9623
|
+
}
|
|
9624
|
+
throw new ParseError(`Task section and example section must end with return statement -> {parameterName}`);
|
|
9625
|
+
};
|
|
9626
|
+
if ($taskJson.content === undefined) {
|
|
9627
|
+
throw new UnexpectedError(`Content is missing in the taskJson - probably commands are applied in wrong order`);
|
|
9628
|
+
}
|
|
9629
|
+
if (command.taskType === 'EXAMPLE') {
|
|
9630
|
+
expectResultingParameterName();
|
|
9631
|
+
const parameter = $pipelineJson.parameters.find((param) => param.name === $taskJson.resultingParameterName);
|
|
9632
|
+
if (parameter === undefined) {
|
|
9633
|
+
// TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
|
|
9634
|
+
throw new ParseError(`Parameter \`{${$taskJson.resultingParameterName}}\` is not defined so can not define example value of it`);
|
|
9635
|
+
}
|
|
9636
|
+
parameter.exampleValues = parameter.exampleValues || [];
|
|
9637
|
+
parameter.exampleValues.push($taskJson.content);
|
|
9638
|
+
$taskJson.isTask = false;
|
|
9639
|
+
return;
|
|
9640
|
+
}
|
|
9641
|
+
if (command.taskType === 'KNOWLEDGE') {
|
|
9642
|
+
knowledgeCommandParser.$applyToPipelineJson({
|
|
9643
|
+
type: 'KNOWLEDGE',
|
|
9644
|
+
knowledgeSourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
|
|
9645
|
+
}, $pipelineJson);
|
|
9646
|
+
$taskJson.isTask = false;
|
|
9647
|
+
return;
|
|
9648
|
+
}
|
|
9649
|
+
if (command.taskType === 'ACTION') {
|
|
9650
|
+
console.error(new NotYetImplementedError('Actions are not implemented yet'));
|
|
9651
|
+
$taskJson.isTask = false;
|
|
9652
|
+
return;
|
|
9653
|
+
}
|
|
9654
|
+
if (command.taskType === 'INSTRUMENT') {
|
|
9655
|
+
console.error(new NotYetImplementedError('Instruments are not implemented yet'));
|
|
9656
|
+
$taskJson.isTask = false;
|
|
9657
|
+
return;
|
|
9658
|
+
}
|
|
9659
|
+
expectResultingParameterName();
|
|
9660
|
+
$taskJson.taskType = command.taskType;
|
|
9661
|
+
$taskJson.isTask = true;
|
|
9662
|
+
},
|
|
9663
|
+
/**
|
|
9664
|
+
* Converts the SECTION command back to string
|
|
9665
|
+
*
|
|
9666
|
+
* Note: This is used in `pipelineJsonToString` utility
|
|
9667
|
+
*/
|
|
9668
|
+
stringify(command) {
|
|
9669
|
+
return `---`; // <- TODO: [🛋] Implement
|
|
9670
|
+
},
|
|
9671
|
+
/**
|
|
9672
|
+
* Reads the SECTION command from the `TaskJson`
|
|
9673
|
+
*
|
|
9674
|
+
* Note: This is used in `pipelineJsonToString` utility
|
|
9675
|
+
*/
|
|
9676
|
+
takeFromTaskJson($taskJson) {
|
|
9677
|
+
throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
|
|
9678
|
+
},
|
|
9679
|
+
};
|
|
9680
|
+
/**
|
|
9681
|
+
* Note: [⛱] There are two types of KNOWLEDGE, ACTION and INSTRUMENT commands:
|
|
9682
|
+
* 1) There are commands `KNOWLEDGE`, `ACTION` and `INSTRUMENT` used in the pipeline head, they just define the knowledge, action or instrument as single line after the command
|
|
9683
|
+
* - KNOWLEDGE Look at https://en.wikipedia.org/wiki/Artificial_intelligence
|
|
9684
|
+
* 2) `KNOWLEDGE SECTION` which has short form `KNOWLEDGE` is used in the sectiom, does not refer the line itself, but the content of the section block
|
|
9685
|
+
* - KNOWLEDGE SECTION
|
|
9686
|
+
*
|
|
9687
|
+
* ```
|
|
9688
|
+
* Look at https://en.wikipedia.org/wiki/Artificial_intelligence
|
|
9689
|
+
* ```
|
|
9690
|
+
*/
|
|
9691
|
+
|
|
9692
|
+
/**
|
|
9693
|
+
* Parses the url command
|
|
9694
|
+
*
|
|
9695
|
+
* @see `documentationUrl` for more details
|
|
9696
|
+
*
|
|
9697
|
+
* @public exported from `@promptbook/editable`
|
|
9698
|
+
*/
|
|
9699
|
+
const urlCommandParser = {
|
|
9700
|
+
/**
|
|
9701
|
+
* Name of the command
|
|
9702
|
+
*/
|
|
9703
|
+
name: 'URL',
|
|
9704
|
+
aliasNames: ['PIPELINE_URL'],
|
|
9705
|
+
/*
|
|
9706
|
+
Note: [🛵] No need for this alias name because it is already preprocessed
|
|
9707
|
+
aliasNames: ['HTTPS'],
|
|
9708
|
+
*/
|
|
9709
|
+
/**
|
|
9710
|
+
* BOILERPLATE command can be used in:
|
|
9711
|
+
*/
|
|
9712
|
+
isUsedInPipelineHead: true,
|
|
9713
|
+
isUsedInPipelineTask: false,
|
|
9714
|
+
/**
|
|
9715
|
+
* Description of the URL command
|
|
9716
|
+
*/
|
|
9717
|
+
description: `Declares unique URL for the pipeline`,
|
|
9718
|
+
/**
|
|
9719
|
+
* Link to documentation
|
|
9720
|
+
*/
|
|
9721
|
+
documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/70',
|
|
9722
|
+
/**
|
|
9723
|
+
* Example usages of the URL command
|
|
9724
|
+
*/
|
|
9725
|
+
examples: [
|
|
9726
|
+
'PIPELINE URL https://promptbook.studio/library/write-cv.book',
|
|
9727
|
+
'URL https://promptbook.studio/library/write-cv.book',
|
|
9728
|
+
'https://promptbook.studio/library/write-cv.book',
|
|
9729
|
+
],
|
|
9730
|
+
/**
|
|
9731
|
+
* Parses the URL command
|
|
9732
|
+
*/
|
|
9733
|
+
parse(input) {
|
|
9734
|
+
const { args } = input;
|
|
9735
|
+
const pipelineUrl = args.pop();
|
|
9736
|
+
if (pipelineUrl === undefined) {
|
|
9737
|
+
throw new ParseError(`URL is required`);
|
|
9738
|
+
}
|
|
9739
|
+
// TODO: [🧠][🚲] This should be maybe tested as logic not parse
|
|
9740
|
+
if (!isValidPipelineUrl(pipelineUrl)) {
|
|
9741
|
+
throw new ParseError(`Invalid pipeline URL "${pipelineUrl}"`);
|
|
9742
|
+
}
|
|
9743
|
+
if (args.length > 0) {
|
|
9744
|
+
throw new ParseError(`Can not have more than one pipeline URL`);
|
|
9745
|
+
}
|
|
9746
|
+
/*
|
|
9747
|
+
TODO: [🐠 Maybe more info from `isValidPipelineUrl`:
|
|
9748
|
+
if (pipelineUrl.protocol !== 'https:') {
|
|
9749
|
+
throw new ParseError(`Protocol must be HTTPS`);
|
|
9750
|
+
}
|
|
9751
|
+
|
|
9752
|
+
if (pipelineUrl.hash !== '') {
|
|
9753
|
+
throw new ParseError(
|
|
9754
|
+
spaceTrim(
|
|
9755
|
+
`
|
|
9756
9756
|
URL must not contain hash
|
|
9757
9757
|
Hash is used for identification of the section of the pipeline
|
|
9758
9758
|
`,
|
|
@@ -10143,85 +10143,321 @@ function parseCommandVariant(input) {
|
|
|
10143
10143
|
}
|
|
10144
10144
|
|
|
10145
10145
|
/**
|
|
10146
|
-
*
|
|
10146
|
+
* Utility function to extract all list items from markdown
|
|
10147
10147
|
*
|
|
10148
|
-
*
|
|
10149
|
-
*
|
|
10148
|
+
* Note: It works with both ul and ol
|
|
10149
|
+
* Note: It omits list items in code blocks
|
|
10150
|
+
* Note: It flattens nested lists
|
|
10151
|
+
* Note: It can not work with html syntax and comments
|
|
10150
10152
|
*
|
|
10151
|
-
* @
|
|
10153
|
+
* @param markdown any valid markdown
|
|
10154
|
+
* @returns An array of strings, each representing an individual list item found in the markdown
|
|
10155
|
+
*
|
|
10156
|
+
* @public exported from `@promptbook/markdown-utils`
|
|
10152
10157
|
*/
|
|
10153
|
-
function
|
|
10154
|
-
const
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
pipelineInterface.inputParameters.push(deepClone(parameter));
|
|
10158
|
+
function extractAllListItemsFromMarkdown(markdown) {
|
|
10159
|
+
const lines = markdown.split(/\r?\n/);
|
|
10160
|
+
const listItems = [];
|
|
10161
|
+
let isInCodeBlock = false;
|
|
10162
|
+
for (const line of lines) {
|
|
10163
|
+
const trimmedLine = line.trim();
|
|
10164
|
+
if (trimmedLine.startsWith('```')) {
|
|
10165
|
+
isInCodeBlock = !isInCodeBlock;
|
|
10162
10166
|
}
|
|
10163
|
-
if (
|
|
10164
|
-
|
|
10167
|
+
if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
|
|
10168
|
+
const listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
|
|
10169
|
+
listItems.push(listItem);
|
|
10165
10170
|
}
|
|
10166
10171
|
}
|
|
10167
|
-
|
|
10168
|
-
pipelineInterface[key].sort(({ name: name1 }, { name: name2 }) => name1.localeCompare(name2));
|
|
10169
|
-
}
|
|
10170
|
-
return exportJson({
|
|
10171
|
-
name: `pipelineInterface`,
|
|
10172
|
-
message: `Result of \`getPipelineInterface\``,
|
|
10173
|
-
order: ['inputParameters', 'outputParameters'],
|
|
10174
|
-
value: pipelineInterface,
|
|
10175
|
-
});
|
|
10172
|
+
return listItems;
|
|
10176
10173
|
}
|
|
10177
10174
|
|
|
10178
10175
|
/**
|
|
10179
|
-
*
|
|
10180
|
-
*
|
|
10181
|
-
* @deprecated https://github.com/webgptorg/promptbook/pull/186
|
|
10182
|
-
* @see https://github.com/webgptorg/promptbook/discussions/171
|
|
10176
|
+
* Builds a short file/url identification block for parse errors.
|
|
10183
10177
|
*
|
|
10184
|
-
* @
|
|
10178
|
+
* @private internal utility of `parsePipeline`
|
|
10185
10179
|
*/
|
|
10186
|
-
function
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
return false;
|
|
10192
|
-
}
|
|
10193
|
-
for (const parameter of parameters1) {
|
|
10194
|
-
const matchingParameter = parameters2.find(({ name }) => name === parameter.name);
|
|
10195
|
-
if (!matchingParameter) {
|
|
10196
|
-
return false;
|
|
10197
|
-
}
|
|
10198
|
-
// Note: Do not compare description, it is not relevant for compatibility
|
|
10199
|
-
if (matchingParameter.isInput !== parameter.isInput) {
|
|
10200
|
-
return false;
|
|
10201
|
-
}
|
|
10202
|
-
if (matchingParameter.isOutput !== parameter.isOutput) {
|
|
10203
|
-
return false;
|
|
10204
|
-
}
|
|
10205
|
-
}
|
|
10180
|
+
function getPipelineIdentification($pipelineJson) {
|
|
10181
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
10182
|
+
const pipelineIdentificationParts = [];
|
|
10183
|
+
if ($pipelineJson.sourceFile !== undefined) {
|
|
10184
|
+
pipelineIdentificationParts.push(`File: ${$pipelineJson.sourceFile}`);
|
|
10206
10185
|
}
|
|
10207
|
-
|
|
10186
|
+
if ($pipelineJson.pipelineUrl !== undefined) {
|
|
10187
|
+
pipelineIdentificationParts.push(`Url: ${$pipelineJson.pipelineUrl}`);
|
|
10188
|
+
}
|
|
10189
|
+
return pipelineIdentificationParts.join('\n');
|
|
10208
10190
|
}
|
|
10209
10191
|
|
|
10210
10192
|
/**
|
|
10211
|
-
*
|
|
10212
|
-
*
|
|
10213
|
-
* @deprecated https://github.com/webgptorg/promptbook/pull/186
|
|
10214
|
-
* @see https://github.com/webgptorg/promptbook/discussions/171
|
|
10215
|
-
* @returns `true` if the pipeline implements the interface, `false` otherwise.
|
|
10193
|
+
* Merges one parameter declaration into the mutable pipeline parameter list.
|
|
10216
10194
|
*
|
|
10217
|
-
* @
|
|
10195
|
+
* @private internal utility of `parsePipeline`
|
|
10218
10196
|
*/
|
|
10219
|
-
function
|
|
10220
|
-
const {
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10197
|
+
function defineParameter($pipelineJson, parameterCommand) {
|
|
10198
|
+
const { parameterName, parameterDescription, isInput, isOutput } = parameterCommand;
|
|
10199
|
+
if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
|
|
10200
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
10201
|
+
Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
|
|
10202
|
+
|
|
10203
|
+
${block(getPipelineIdentification($pipelineJson))}
|
|
10204
|
+
`) /* <- TODO: [🚞] */);
|
|
10205
|
+
}
|
|
10206
|
+
const existingParameter = $pipelineJson.parameters.find((parameter) => parameter.name === parameterName);
|
|
10207
|
+
if (existingParameter &&
|
|
10208
|
+
existingParameter.description &&
|
|
10209
|
+
existingParameter.description !== parameterDescription &&
|
|
10210
|
+
parameterDescription) {
|
|
10211
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
10212
|
+
Parameter \`{${parameterName}}\` is defined multiple times with different description:
|
|
10213
|
+
|
|
10214
|
+
${block(getPipelineIdentification($pipelineJson))}
|
|
10215
|
+
|
|
10216
|
+
First definition:
|
|
10217
|
+
${block(existingParameter.description || '[undefined]')}
|
|
10218
|
+
|
|
10219
|
+
Second definition:
|
|
10220
|
+
${block(parameterDescription || '[undefined]')}
|
|
10221
|
+
`));
|
|
10222
|
+
}
|
|
10223
|
+
if (existingParameter) {
|
|
10224
|
+
if (parameterDescription) {
|
|
10225
|
+
existingParameter.description = parameterDescription;
|
|
10226
|
+
}
|
|
10227
|
+
existingParameter.isInput = existingParameter.isInput || isInput;
|
|
10228
|
+
existingParameter.isOutput = existingParameter.isOutput || isOutput;
|
|
10229
|
+
return;
|
|
10230
|
+
}
|
|
10231
|
+
$pipelineJson.parameters.push({
|
|
10232
|
+
name: parameterName,
|
|
10233
|
+
description: parameterDescription || undefined,
|
|
10234
|
+
isInput,
|
|
10235
|
+
isOutput,
|
|
10236
|
+
});
|
|
10237
|
+
}
|
|
10238
|
+
|
|
10239
|
+
/**
|
|
10240
|
+
* Removes fenced code blocks when deriving human-readable section descriptions.
|
|
10241
|
+
*
|
|
10242
|
+
* @private internal utility of `extractPipelineDescription`
|
|
10243
|
+
*/
|
|
10244
|
+
const DESCRIPTION_CODE_BLOCK_REGEXP = /^```.*^```/gms;
|
|
10245
|
+
/**
|
|
10246
|
+
* Removes blockquote lines when deriving human-readable section descriptions.
|
|
10247
|
+
*
|
|
10248
|
+
* @private internal utility of `extractPipelineDescription`
|
|
10249
|
+
*/
|
|
10250
|
+
const DESCRIPTION_BLOCKQUOTE_REGEXP = /^>.*$/gm;
|
|
10251
|
+
/**
|
|
10252
|
+
* Removes list items and return statements when deriving human-readable section descriptions.
|
|
10253
|
+
*
|
|
10254
|
+
* @private internal utility of `extractPipelineDescription`
|
|
10255
|
+
*/
|
|
10256
|
+
const DESCRIPTION_LIST_ITEM_REGEXP = /^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm;
|
|
10257
|
+
/**
|
|
10258
|
+
* Extracts the plain-text description from a head or task section body.
|
|
10259
|
+
*
|
|
10260
|
+
* @private internal utility of `parsePipeline`
|
|
10261
|
+
*/
|
|
10262
|
+
function extractPipelineDescription(sectionContent) {
|
|
10263
|
+
let description = sectionContent;
|
|
10264
|
+
description = description.split(DESCRIPTION_CODE_BLOCK_REGEXP).join('');
|
|
10265
|
+
description = description.split(DESCRIPTION_BLOCKQUOTE_REGEXP).join('');
|
|
10266
|
+
description = description.split(DESCRIPTION_LIST_ITEM_REGEXP).join('');
|
|
10267
|
+
description = spaceTrim$1(description);
|
|
10268
|
+
if (description === '') {
|
|
10269
|
+
return undefined;
|
|
10270
|
+
}
|
|
10271
|
+
return description;
|
|
10272
|
+
}
|
|
10273
|
+
|
|
10274
|
+
/**
|
|
10275
|
+
* Applies the pipeline head title, description, and head-level commands.
|
|
10276
|
+
*
|
|
10277
|
+
* @private internal utility of `parsePipeline`
|
|
10278
|
+
*/
|
|
10279
|
+
function applyPipelineHead(pipelineHead, $pipelineJson) {
|
|
10280
|
+
$pipelineJson.title = pipelineHead.title;
|
|
10281
|
+
$pipelineJson.description = extractPipelineDescription(pipelineHead.content);
|
|
10282
|
+
for (const listItem of extractAllListItemsFromMarkdown(pipelineHead.content)) {
|
|
10283
|
+
applyPipelineHeadCommand(listItem, $pipelineJson);
|
|
10284
|
+
}
|
|
10285
|
+
}
|
|
10286
|
+
/**
|
|
10287
|
+
* Parses and applies one command declared in the pipeline head.
|
|
10288
|
+
*
|
|
10289
|
+
* @private internal utility of `applyPipelineHead`
|
|
10290
|
+
*/
|
|
10291
|
+
function applyPipelineHeadCommand(listItem, $pipelineJson) {
|
|
10292
|
+
const command = parseCommand(listItem, 'PIPELINE_HEAD');
|
|
10293
|
+
const commandParser = getParserForCommand(command);
|
|
10294
|
+
if (commandParser.isUsedInPipelineHead !== true /* <- Note: [🦦][4] */) {
|
|
10295
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
10296
|
+
Command \`${command.type}\` is not allowed in the head of the pipeline ONLY at the pipeline task
|
|
10297
|
+
|
|
10298
|
+
${block(getPipelineIdentification($pipelineJson))}
|
|
10299
|
+
`)); // <- TODO: [🚞]
|
|
10300
|
+
}
|
|
10301
|
+
try {
|
|
10302
|
+
commandParser.$applyToPipelineJson(command, $pipelineJson);
|
|
10303
|
+
// <- Note: [🦦] Its strange that this assertion must be here, [🦦][4] should do this assertion implicitly
|
|
10304
|
+
}
|
|
10305
|
+
catch (error) {
|
|
10306
|
+
if (!(error instanceof ParseError)) {
|
|
10307
|
+
throw error;
|
|
10308
|
+
}
|
|
10309
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
10310
|
+
Command ${command.type} failed to apply to the pipeline
|
|
10311
|
+
|
|
10312
|
+
The error:
|
|
10313
|
+
${block(error.message)}
|
|
10314
|
+
|
|
10315
|
+
Raw command:
|
|
10316
|
+
- ${listItem}
|
|
10317
|
+
|
|
10318
|
+
Usage of ${command.type}:
|
|
10319
|
+
${block(commandParser.examples.map((example) => `- ${example}`).join('\n'))}
|
|
10320
|
+
|
|
10321
|
+
${block(getPipelineIdentification($pipelineJson))}
|
|
10322
|
+
`)); // <- TODO: [🚞]
|
|
10323
|
+
}
|
|
10324
|
+
if (command.type === 'PARAMETER') {
|
|
10325
|
+
defineParameter($pipelineJson, command);
|
|
10326
|
+
// <- Note: [🍣]
|
|
10327
|
+
}
|
|
10328
|
+
}
|
|
10329
|
+
|
|
10330
|
+
/**
|
|
10331
|
+
* Creates the mutable pipeline JSON structure used throughout parsing.
|
|
10332
|
+
*
|
|
10333
|
+
* @private internal utility of `parsePipeline`
|
|
10334
|
+
*/
|
|
10335
|
+
function createInitialPipelineJson(pipelineString) {
|
|
10336
|
+
return {
|
|
10337
|
+
title: DEFAULT_BOOK_TITLE,
|
|
10338
|
+
parameters: [],
|
|
10339
|
+
tasks: [],
|
|
10340
|
+
knowledgeSources: [],
|
|
10341
|
+
knowledgePieces: [],
|
|
10342
|
+
personas: [],
|
|
10343
|
+
preparations: [],
|
|
10344
|
+
sources: [
|
|
10345
|
+
{
|
|
10346
|
+
type: 'BOOK',
|
|
10347
|
+
path: null,
|
|
10348
|
+
// <- TODO: !!6 Pass here path of the file
|
|
10349
|
+
content: pipelineString,
|
|
10350
|
+
},
|
|
10351
|
+
],
|
|
10352
|
+
};
|
|
10353
|
+
}
|
|
10354
|
+
|
|
10355
|
+
/**
|
|
10356
|
+
* Creates stable unique task names for duplicate section titles.
|
|
10357
|
+
*
|
|
10358
|
+
* @private internal utility of `parsePipeline`
|
|
10359
|
+
*/
|
|
10360
|
+
function createUniqueSectionNameResolver(pipelineSections) {
|
|
10361
|
+
const sectionCounts = {};
|
|
10362
|
+
for (const pipelineSection of pipelineSections) {
|
|
10363
|
+
const sectionName = titleToName(pipelineSection.title);
|
|
10364
|
+
if (sectionCounts[sectionName] === undefined) {
|
|
10365
|
+
sectionCounts[sectionName] = { count: 0, currentIndex: 0 };
|
|
10366
|
+
}
|
|
10367
|
+
sectionCounts[sectionName].count++;
|
|
10368
|
+
}
|
|
10369
|
+
return (title) => {
|
|
10370
|
+
const sectionName = titleToName(title);
|
|
10371
|
+
const sectionCount = sectionCounts[sectionName];
|
|
10372
|
+
if (sectionCount.count === 1) {
|
|
10373
|
+
return sectionName;
|
|
10374
|
+
}
|
|
10375
|
+
const nameWithSuffix = `${sectionName}-${sectionCount.currentIndex}`;
|
|
10376
|
+
sectionCount.currentIndex++;
|
|
10377
|
+
return nameWithSuffix;
|
|
10378
|
+
};
|
|
10379
|
+
}
|
|
10380
|
+
|
|
10381
|
+
/**
|
|
10382
|
+
* Extracts the interface (input and output parameters) from a pipeline.
|
|
10383
|
+
*
|
|
10384
|
+
* @deprecated https://github.com/webgptorg/promptbook/pull/186
|
|
10385
|
+
* @see https://github.com/webgptorg/promptbook/discussions/171
|
|
10386
|
+
*
|
|
10387
|
+
* @public exported from `@promptbook/core`
|
|
10388
|
+
*/
|
|
10389
|
+
function getPipelineInterface(pipeline) {
|
|
10390
|
+
const pipelineInterface = {
|
|
10391
|
+
inputParameters: [],
|
|
10392
|
+
outputParameters: [],
|
|
10393
|
+
};
|
|
10394
|
+
for (const parameter of pipeline.parameters) {
|
|
10395
|
+
const { isInput, isOutput } = parameter;
|
|
10396
|
+
if (isInput) {
|
|
10397
|
+
pipelineInterface.inputParameters.push(deepClone(parameter));
|
|
10398
|
+
}
|
|
10399
|
+
if (isOutput) {
|
|
10400
|
+
pipelineInterface.outputParameters.push(deepClone(parameter));
|
|
10401
|
+
}
|
|
10402
|
+
}
|
|
10403
|
+
for (const key of ['inputParameters', 'outputParameters']) {
|
|
10404
|
+
pipelineInterface[key].sort(({ name: name1 }, { name: name2 }) => name1.localeCompare(name2));
|
|
10405
|
+
}
|
|
10406
|
+
return exportJson({
|
|
10407
|
+
name: `pipelineInterface`,
|
|
10408
|
+
message: `Result of \`getPipelineInterface\``,
|
|
10409
|
+
order: ['inputParameters', 'outputParameters'],
|
|
10410
|
+
value: pipelineInterface,
|
|
10411
|
+
});
|
|
10412
|
+
}
|
|
10413
|
+
|
|
10414
|
+
/**
|
|
10415
|
+
* Checks if two pipeline interfaces are structurally identical.
|
|
10416
|
+
*
|
|
10417
|
+
* @deprecated https://github.com/webgptorg/promptbook/pull/186
|
|
10418
|
+
* @see https://github.com/webgptorg/promptbook/discussions/171
|
|
10419
|
+
*
|
|
10420
|
+
* @public exported from `@promptbook/core`
|
|
10421
|
+
*/
|
|
10422
|
+
function isPipelineInterfacesEqual(pipelineInterface1, pipelineInterface2) {
|
|
10423
|
+
for (const whichParameters of ['inputParameters', 'outputParameters']) {
|
|
10424
|
+
const parameters1 = pipelineInterface1[whichParameters]; // <- Note: `isPipelineInterfacesEqual` is just temporary solution, no need to fix this
|
|
10425
|
+
const parameters2 = pipelineInterface2[whichParameters];
|
|
10426
|
+
if (parameters1.length !== parameters2.length) {
|
|
10427
|
+
return false;
|
|
10428
|
+
}
|
|
10429
|
+
for (const parameter of parameters1) {
|
|
10430
|
+
const matchingParameter = parameters2.find(({ name }) => name === parameter.name);
|
|
10431
|
+
if (!matchingParameter) {
|
|
10432
|
+
return false;
|
|
10433
|
+
}
|
|
10434
|
+
// Note: Do not compare description, it is not relevant for compatibility
|
|
10435
|
+
if (matchingParameter.isInput !== parameter.isInput) {
|
|
10436
|
+
return false;
|
|
10437
|
+
}
|
|
10438
|
+
if (matchingParameter.isOutput !== parameter.isOutput) {
|
|
10439
|
+
return false;
|
|
10440
|
+
}
|
|
10441
|
+
}
|
|
10442
|
+
}
|
|
10443
|
+
return true;
|
|
10444
|
+
}
|
|
10445
|
+
|
|
10446
|
+
/**
|
|
10447
|
+
* Checks if a given pipeline satisfies the requirements of a specified pipeline interface.
|
|
10448
|
+
*
|
|
10449
|
+
* @deprecated https://github.com/webgptorg/promptbook/pull/186
|
|
10450
|
+
* @see https://github.com/webgptorg/promptbook/discussions/171
|
|
10451
|
+
* @returns `true` if the pipeline implements the interface, `false` otherwise.
|
|
10452
|
+
*
|
|
10453
|
+
* @public exported from `@promptbook/core`
|
|
10454
|
+
*/
|
|
10455
|
+
function isPipelineImplementingInterface(options) {
|
|
10456
|
+
const { pipeline, pipelineInterface } = options;
|
|
10457
|
+
return isPipelineInterfacesEqual(getPipelineInterface(pipeline), pipelineInterface);
|
|
10458
|
+
}
|
|
10459
|
+
|
|
10460
|
+
/**
|
|
10225
10461
|
* Set formfactor based on the pipeline interface e
|
|
10226
10462
|
*
|
|
10227
10463
|
* @private
|
|
@@ -10403,197 +10639,125 @@ const HIGH_LEVEL_ABSTRACTIONS = [
|
|
|
10403
10639
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
10404
10640
|
|
|
10405
10641
|
/**
|
|
10406
|
-
*
|
|
10642
|
+
* Applies postprocessing and exports the parsed pipeline JSON.
|
|
10407
10643
|
*
|
|
10408
|
-
* @private internal
|
|
10644
|
+
* @private internal utility of `parsePipeline`
|
|
10409
10645
|
*/
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10646
|
+
function finalizeParsedPipeline($pipelineJson) {
|
|
10647
|
+
applyImplicitParameterDirections($pipelineJson);
|
|
10648
|
+
removeUndefinedValuesFromPipeline($pipelineJson);
|
|
10649
|
+
applySyncHighLevelAbstractions($pipelineJson);
|
|
10650
|
+
ensurePipelineFormfactor($pipelineJson);
|
|
10651
|
+
return exportParsedPipelineJson($pipelineJson);
|
|
10652
|
+
}
|
|
10413
10653
|
/**
|
|
10414
|
-
*
|
|
10654
|
+
* Applies default INPUT/OUTPUT flags when the author did not specify them explicitly.
|
|
10415
10655
|
*
|
|
10416
|
-
* @
|
|
10656
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10417
10657
|
*/
|
|
10418
|
-
|
|
10658
|
+
function applyImplicitParameterDirections($pipelineJson) {
|
|
10659
|
+
markImplicitInputParameters($pipelineJson);
|
|
10660
|
+
markImplicitOutputParameters($pipelineJson);
|
|
10661
|
+
}
|
|
10419
10662
|
/**
|
|
10420
|
-
*
|
|
10421
|
-
*
|
|
10422
|
-
* Note: [🔂] This function is idempotent.
|
|
10663
|
+
* Marks non-result parameters as pipeline inputs when no input was declared.
|
|
10423
10664
|
*
|
|
10424
|
-
* @
|
|
10665
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10425
10666
|
*/
|
|
10426
|
-
function
|
|
10427
|
-
if (
|
|
10428
|
-
return
|
|
10667
|
+
function markImplicitInputParameters($pipelineJson) {
|
|
10668
|
+
if ($pipelineJson.parameters.some((parameter) => parameter.isInput)) {
|
|
10669
|
+
return;
|
|
10429
10670
|
}
|
|
10430
|
-
const
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
//
|
|
10436
|
-
|
|
10437
|
-
|
|
10438
|
-
if (line.trim() === '') {
|
|
10439
|
-
trailingEmptyLines++;
|
|
10440
|
-
}
|
|
10441
|
-
else {
|
|
10442
|
-
break;
|
|
10671
|
+
for (const parameter of $pipelineJson.parameters) {
|
|
10672
|
+
const isThisParameterResulting = $pipelineJson.tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
10673
|
+
if (!isThisParameterResulting) {
|
|
10674
|
+
parameter.isInput = true;
|
|
10675
|
+
// <- TODO: [💔] Why this is making typescript error in vscode but not in cli
|
|
10676
|
+
// > Type 'true' is not assignable to type 'false'.ts(2322)
|
|
10677
|
+
// > (property) isInput: false
|
|
10678
|
+
// > The parameter is input of the pipeline The parameter is NOT input of the pipeline
|
|
10443
10679
|
}
|
|
10444
10680
|
}
|
|
10445
|
-
if (trailingEmptyLines >= PADDING_LINES) {
|
|
10446
|
-
return content;
|
|
10447
|
-
}
|
|
10448
|
-
const linesToAdd = PADDING_LINES - trailingEmptyLines;
|
|
10449
|
-
return (content + '\n'.repeat(linesToAdd));
|
|
10450
10681
|
}
|
|
10451
|
-
// TODO: [🧠] Maybe export
|
|
10452
|
-
|
|
10453
10682
|
/**
|
|
10454
|
-
*
|
|
10455
|
-
*
|
|
10456
|
-
* @param {string} content - The string to remove comments from.
|
|
10457
|
-
* @returns {string} The input string with all comments removed.
|
|
10458
|
-
*
|
|
10459
|
-
* @public exported from `@promptbook/markdown-utils`
|
|
10460
|
-
*/
|
|
10461
|
-
function removeMarkdownComments(content) {
|
|
10462
|
-
return spaceTrim$1(content.replace(/<!--(.*?)-->/gs, ''));
|
|
10463
|
-
}
|
|
10464
|
-
|
|
10465
|
-
/**
|
|
10466
|
-
* Utility to determine if a pipeline string is in flat format.
|
|
10467
|
-
* A flat pipeline is a simple text without proper structure (headers, blocks, etc).
|
|
10468
|
-
*
|
|
10469
|
-
* @public exported from `@promptbook/editable`
|
|
10470
|
-
*/
|
|
10471
|
-
function isFlatPipeline(pipelineString) {
|
|
10472
|
-
pipelineString = removeMarkdownComments(pipelineString);
|
|
10473
|
-
pipelineString = spaceTrim$1(pipelineString);
|
|
10474
|
-
const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
|
|
10475
|
-
//const isLastLineReturnStatement = pipelineString.split(/\r?\n/).pop()!.split('`').join('').startsWith('->');
|
|
10476
|
-
const isBacktickBlockUsed = pipelineString.includes('```');
|
|
10477
|
-
const isQuoteBlocksUsed = /^>\s+/m.test(pipelineString);
|
|
10478
|
-
const isBlocksUsed = isBacktickBlockUsed || isQuoteBlocksUsed;
|
|
10479
|
-
// TODO: [🧉] Also (double)check
|
|
10480
|
-
// > const usedCommands
|
|
10481
|
-
// > const isBlocksUsed
|
|
10482
|
-
// > const returnStatementCount
|
|
10483
|
-
const isFlat = !isMarkdownBeginningWithHeadline && !isBlocksUsed; /* && isLastLineReturnStatement */
|
|
10484
|
-
return isFlat;
|
|
10485
|
-
}
|
|
10486
|
-
|
|
10487
|
-
/**
|
|
10488
|
-
* Converts a pipeline structure to its string representation.
|
|
10489
|
-
*
|
|
10490
|
-
* Transforms a flat, simple pipeline into a properly formatted pipeline string
|
|
10491
|
-
* with sections for title, prompt, and return statement.
|
|
10683
|
+
* Marks every non-input parameter as output when no output was declared.
|
|
10492
10684
|
*
|
|
10493
|
-
* @
|
|
10685
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10494
10686
|
*/
|
|
10495
|
-
function
|
|
10496
|
-
if (
|
|
10497
|
-
return
|
|
10498
|
-
}
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
// Note: Last line is return statement
|
|
10505
|
-
returnStatement = potentialReturnStatement;
|
|
10506
|
-
}
|
|
10507
|
-
else {
|
|
10508
|
-
// Note: Last line is not a return statement
|
|
10509
|
-
returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
|
|
10510
|
-
pipelineStringLines.push(potentialReturnStatement);
|
|
10511
|
-
}
|
|
10512
|
-
const prompt = spaceTrim$1(pipelineStringLines.join('\n'));
|
|
10513
|
-
let quotedPrompt;
|
|
10514
|
-
if (prompt.split(/\r?\n/).length <= 1) {
|
|
10515
|
-
quotedPrompt = `> ${prompt}`;
|
|
10516
|
-
}
|
|
10517
|
-
else {
|
|
10518
|
-
quotedPrompt = spaceTrim$1((block) => `
|
|
10519
|
-
\`\`\`
|
|
10520
|
-
${block(prompt.split('`').join('\\`'))}
|
|
10521
|
-
\`\`\`
|
|
10522
|
-
`);
|
|
10687
|
+
function markImplicitOutputParameters($pipelineJson) {
|
|
10688
|
+
if ($pipelineJson.parameters.some((parameter) => parameter.isOutput)) {
|
|
10689
|
+
return;
|
|
10690
|
+
}
|
|
10691
|
+
for (const parameter of $pipelineJson.parameters) {
|
|
10692
|
+
if (!parameter.isInput) {
|
|
10693
|
+
parameter.isOutput = true;
|
|
10694
|
+
// <- TODO: [💔]
|
|
10695
|
+
}
|
|
10523
10696
|
}
|
|
10524
|
-
pipelineString = validatePipelineString(spaceTrim$1((block) => `
|
|
10525
|
-
# ${DEFAULT_BOOK_TITLE}
|
|
10526
|
-
|
|
10527
|
-
## Prompt
|
|
10528
|
-
|
|
10529
|
-
${block(quotedPrompt)}
|
|
10530
|
-
|
|
10531
|
-
${returnStatement}
|
|
10532
|
-
`));
|
|
10533
|
-
// <- TODO: Maybe use book` notation
|
|
10534
|
-
return padBook(pipelineString);
|
|
10535
10697
|
}
|
|
10536
|
-
// TODO: Unit test
|
|
10537
|
-
|
|
10538
10698
|
/**
|
|
10539
|
-
*
|
|
10540
|
-
*
|
|
10541
|
-
* Note: It works with both ul and ol
|
|
10542
|
-
* Note: It omits list items in code blocks
|
|
10543
|
-
* Note: It flattens nested lists
|
|
10544
|
-
* Note: It can not work with html syntax and comments
|
|
10699
|
+
* Removes `undefined` properties from serialized tasks and parameters.
|
|
10545
10700
|
*
|
|
10546
|
-
* @
|
|
10547
|
-
|
|
10701
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10702
|
+
*/
|
|
10703
|
+
function removeUndefinedValuesFromPipeline($pipelineJson) {
|
|
10704
|
+
$pipelineJson.tasks.forEach(removeUndefinedProperties);
|
|
10705
|
+
$pipelineJson.parameters.forEach(removeUndefinedProperties);
|
|
10706
|
+
}
|
|
10707
|
+
/**
|
|
10708
|
+
* Deletes all own properties with `undefined` values from a mutable JSON entity.
|
|
10548
10709
|
*
|
|
10549
|
-
* @
|
|
10710
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10550
10711
|
*/
|
|
10551
|
-
function
|
|
10552
|
-
const
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
for (const line of lines) {
|
|
10556
|
-
const trimmedLine = line.trim();
|
|
10557
|
-
if (trimmedLine.startsWith('```')) {
|
|
10558
|
-
isInCodeBlock = !isInCodeBlock;
|
|
10559
|
-
}
|
|
10560
|
-
if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
|
|
10561
|
-
const listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
|
|
10562
|
-
listItems.push(listItem);
|
|
10712
|
+
function removeUndefinedProperties(entity) {
|
|
10713
|
+
for (const [key, value] of Object.entries(entity)) {
|
|
10714
|
+
if (value === undefined) {
|
|
10715
|
+
delete entity[key];
|
|
10563
10716
|
}
|
|
10564
10717
|
}
|
|
10565
|
-
return listItems;
|
|
10566
10718
|
}
|
|
10567
|
-
|
|
10568
10719
|
/**
|
|
10569
|
-
*
|
|
10570
|
-
*
|
|
10571
|
-
* - When there are multiple or no code blocks the function throws a `ParseError`
|
|
10572
|
-
*
|
|
10573
|
-
* Note: There are multiple similar functions:
|
|
10574
|
-
* - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
|
|
10575
|
-
* - `extractJsonBlock` extracts exactly one valid JSON code block
|
|
10576
|
-
* - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
|
|
10577
|
-
* - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
|
|
10720
|
+
* Applies all sync-only high-level abstractions after parsing.
|
|
10578
10721
|
*
|
|
10579
|
-
* @
|
|
10580
|
-
|
|
10581
|
-
|
|
10722
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10723
|
+
*/
|
|
10724
|
+
function applySyncHighLevelAbstractions($pipelineJson) {
|
|
10725
|
+
for (const highLevelAbstraction of HIGH_LEVEL_ABSTRACTIONS.filter(({ type }) => type === 'SYNC')) {
|
|
10726
|
+
highLevelAbstraction.$applyToPipelineJson($pipelineJson);
|
|
10727
|
+
}
|
|
10728
|
+
}
|
|
10729
|
+
/**
|
|
10730
|
+
* Ensures parsed pipelines always have the default `GENERIC` formfactor.
|
|
10582
10731
|
*
|
|
10583
|
-
* @
|
|
10732
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10584
10733
|
*/
|
|
10585
|
-
function
|
|
10586
|
-
|
|
10587
|
-
if (
|
|
10588
|
-
|
|
10589
|
-
There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
|
|
10590
|
-
|
|
10591
|
-
${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
|
|
10592
|
-
`));
|
|
10734
|
+
function ensurePipelineFormfactor($pipelineJson) {
|
|
10735
|
+
// Note: [🔆] If formfactor is still not set, set it to 'GENERIC'
|
|
10736
|
+
if ($pipelineJson.formfactorName === undefined) {
|
|
10737
|
+
$pipelineJson.formfactorName = 'GENERIC';
|
|
10593
10738
|
}
|
|
10594
|
-
return codeBlocks[0];
|
|
10595
10739
|
}
|
|
10596
|
-
|
|
10740
|
+
/**
|
|
10741
|
+
* Finalizes ordering and exports the parsed pipeline JSON.
|
|
10742
|
+
*
|
|
10743
|
+
* @private internal utility of `finalizeParsedPipeline`
|
|
10744
|
+
*/
|
|
10745
|
+
function exportParsedPipelineJson($pipelineJson) {
|
|
10746
|
+
return exportJson({
|
|
10747
|
+
name: 'pipelineJson',
|
|
10748
|
+
message: `Result of \`parsePipeline\``,
|
|
10749
|
+
order: ORDER_OF_PIPELINE_JSON,
|
|
10750
|
+
value: {
|
|
10751
|
+
formfactorName: 'GENERIC',
|
|
10752
|
+
// <- Note: [🔆] Setting `formfactorName` is redundant to satisfy the typescript
|
|
10753
|
+
...$pipelineJson,
|
|
10754
|
+
},
|
|
10755
|
+
});
|
|
10756
|
+
}
|
|
10757
|
+
// TODO: Use spaceTrim more effectively
|
|
10758
|
+
// TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
|
|
10759
|
+
// TODO: [♈] Probably move expectations from tasks to parameters
|
|
10760
|
+
// TODO: [🍙] Make some standard order of json properties
|
|
10597
10761
|
|
|
10598
10762
|
/**
|
|
10599
10763
|
* Parses markdown section to title its level and content
|
|
@@ -10665,213 +10829,24 @@ function splitMarkdownIntoSections(markdown) {
|
|
|
10665
10829
|
currentType = 'MARKDOWN';
|
|
10666
10830
|
}
|
|
10667
10831
|
}
|
|
10668
|
-
else if (currentType === 'COMMENT') {
|
|
10669
|
-
buffer.push(line);
|
|
10670
|
-
if (line.includes('-->')) {
|
|
10671
|
-
currentType = 'MARKDOWN';
|
|
10672
|
-
}
|
|
10673
|
-
}
|
|
10674
|
-
}
|
|
10675
|
-
finishSection();
|
|
10676
|
-
return sections;
|
|
10677
|
-
}
|
|
10678
|
-
/**
|
|
10679
|
-
* TODO: [🏛] This can be part of markdown builder
|
|
10680
|
-
* Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
|
|
10681
|
-
* sophisticated implementation of this function through parsing markdown into JSON structure
|
|
10682
|
-
* and flattening the actual structure
|
|
10683
|
-
* NOW we are working just with markdown string and its good enough
|
|
10684
|
-
*/
|
|
10685
|
-
|
|
10686
|
-
/**
|
|
10687
|
-
* Normalizes the markdown by flattening the structure
|
|
10688
|
-
*
|
|
10689
|
-
* - It always have h1 - if there is no h1 in the markdown, it will be added `DEFAULT_BOOK_TITLE`
|
|
10690
|
-
* - All other headings are normalized to h2
|
|
10691
|
-
*
|
|
10692
|
-
* @public exported from `@promptbook/markdown-utils`
|
|
10693
|
-
*/
|
|
10694
|
-
function flattenMarkdown(markdown) {
|
|
10695
|
-
const sections = splitMarkdownIntoSections(markdown);
|
|
10696
|
-
if (sections.length === 0) {
|
|
10697
|
-
return `# ${DEFAULT_BOOK_TITLE}`;
|
|
10698
|
-
}
|
|
10699
|
-
let flattenedMarkdown = '';
|
|
10700
|
-
const parsedSections = sections.map(parseMarkdownSection);
|
|
10701
|
-
const firstSection = parsedSections.shift();
|
|
10702
|
-
if (firstSection.level === 1) {
|
|
10703
|
-
flattenedMarkdown += `# ${firstSection.title}` + `\n\n`;
|
|
10704
|
-
flattenedMarkdown += firstSection.content + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
10705
|
-
}
|
|
10706
|
-
else {
|
|
10707
|
-
parsedSections.unshift(firstSection);
|
|
10708
|
-
flattenedMarkdown += `# ${DEFAULT_BOOK_TITLE}` + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
10709
|
-
}
|
|
10710
|
-
for (const { title, content } of parsedSections) {
|
|
10711
|
-
flattenedMarkdown += `## ${title}` + `\n\n`;
|
|
10712
|
-
flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
10713
|
-
}
|
|
10714
|
-
return spaceTrim$1(flattenedMarkdown);
|
|
10715
|
-
}
|
|
10716
|
-
/**
|
|
10717
|
-
* TODO: [🏛] This can be part of markdown builder
|
|
10718
|
-
* Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
|
|
10719
|
-
* sophisticated implementation of this function through parsing markdown into JSON structure
|
|
10720
|
-
* and flattening the actual structure
|
|
10721
|
-
* NOW we are working just with markdown string and its good enough
|
|
10722
|
-
*/
|
|
10723
|
-
|
|
10724
|
-
/**
|
|
10725
|
-
* Normalizes inline parameter mentions wrapped in code spans before markdown flattening.
|
|
10726
|
-
*
|
|
10727
|
-
* @private internal utility of `parsePipeline`
|
|
10728
|
-
*/
|
|
10729
|
-
const INLINE_CODE_PARAMETER_REGEXP = /`\{(?<parameterName>[a-z0-9_]+)\}`/gi;
|
|
10730
|
-
/**
|
|
10731
|
-
* Normalizes inline return statements wrapped in code spans before markdown flattening.
|
|
10732
|
-
*
|
|
10733
|
-
* @private internal utility of `parsePipeline`
|
|
10734
|
-
*/
|
|
10735
|
-
const INLINE_CODE_RETURN_PARAMETER_REGEXP = /`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi;
|
|
10736
|
-
/**
|
|
10737
|
-
* Matches the trailing return statement of a task section.
|
|
10738
|
-
*
|
|
10739
|
-
* @private internal utility of `parsePipeline`
|
|
10740
|
-
*/
|
|
10741
|
-
const RESULTING_PARAMETER_LINE_REGEXP = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im;
|
|
10742
|
-
/**
|
|
10743
|
-
* Removes fenced code blocks when deriving human-readable section descriptions.
|
|
10744
|
-
*
|
|
10745
|
-
* @private internal utility of `parsePipeline`
|
|
10746
|
-
*/
|
|
10747
|
-
const DESCRIPTION_CODE_BLOCK_REGEXP = /^```.*^```/gms;
|
|
10748
|
-
/**
|
|
10749
|
-
* Removes blockquote lines when deriving human-readable section descriptions.
|
|
10750
|
-
*
|
|
10751
|
-
* @private internal utility of `parsePipeline`
|
|
10752
|
-
*/
|
|
10753
|
-
const DESCRIPTION_BLOCKQUOTE_REGEXP = /^>.*$/gm;
|
|
10754
|
-
/**
|
|
10755
|
-
* Removes list items and return statements when deriving human-readable section descriptions.
|
|
10756
|
-
*
|
|
10757
|
-
* @private internal utility of `parsePipeline`
|
|
10758
|
-
*/
|
|
10759
|
-
const DESCRIPTION_LIST_ITEM_REGEXP = /^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm;
|
|
10760
|
-
/**
|
|
10761
|
-
* Compile pipeline from string (markdown) format to JSON format synchronously
|
|
10762
|
-
*
|
|
10763
|
-
* Note: There are 3 similar functions:
|
|
10764
|
-
* - `compilePipeline` **(preferred)** - which properly compiles the promptbook and uses embedding for external knowledge
|
|
10765
|
-
* - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
|
|
10766
|
-
* - `preparePipeline` - just one step in the compilation process
|
|
10767
|
-
*
|
|
10768
|
-
* Note: This function does not validate logic of the pipeline only the parsing
|
|
10769
|
-
* Note: This function acts as compilation process
|
|
10770
|
-
*
|
|
10771
|
-
* @param pipelineString {Promptbook} in string markdown format (.book.md)
|
|
10772
|
-
* @returns {Promptbook} compiled in JSON format (.bookc)
|
|
10773
|
-
* @throws {ParseError} if the promptbook string is not valid
|
|
10774
|
-
*
|
|
10775
|
-
* @public exported from `@promptbook/core`
|
|
10776
|
-
*/
|
|
10777
|
-
function parsePipeline(pipelineString) {
|
|
10778
|
-
const $pipelineJson = createInitialPipelineJson(pipelineString);
|
|
10779
|
-
const preparedPipelineString = preparePipelineString(pipelineString, $pipelineJson);
|
|
10780
|
-
const { pipelineHead, pipelineSections } = parsePreparedPipelineSections(preparedPipelineString, $pipelineJson);
|
|
10781
|
-
const getUniqueSectionName = createUniqueSectionNameResolver(pipelineSections);
|
|
10782
|
-
applyPipelineHead(pipelineHead, $pipelineJson);
|
|
10783
|
-
for (const pipelineSection of pipelineSections) {
|
|
10784
|
-
processPipelineSection(pipelineSection, $pipelineJson, getUniqueSectionName);
|
|
10785
|
-
}
|
|
10786
|
-
applyImplicitParameterDirections($pipelineJson);
|
|
10787
|
-
removeUndefinedValuesFromPipeline($pipelineJson);
|
|
10788
|
-
applySyncHighLevelAbstractions($pipelineJson);
|
|
10789
|
-
ensurePipelineFormfactor($pipelineJson);
|
|
10790
|
-
return exportParsedPipelineJson($pipelineJson);
|
|
10791
|
-
}
|
|
10792
|
-
/**
|
|
10793
|
-
* Creates the mutable pipeline JSON structure used throughout parsing.
|
|
10794
|
-
*
|
|
10795
|
-
* @private internal utility of `parsePipeline`
|
|
10796
|
-
*/
|
|
10797
|
-
function createInitialPipelineJson(pipelineString) {
|
|
10798
|
-
return {
|
|
10799
|
-
title: DEFAULT_BOOK_TITLE,
|
|
10800
|
-
parameters: [],
|
|
10801
|
-
tasks: [],
|
|
10802
|
-
knowledgeSources: [],
|
|
10803
|
-
knowledgePieces: [],
|
|
10804
|
-
personas: [],
|
|
10805
|
-
preparations: [],
|
|
10806
|
-
sources: [
|
|
10807
|
-
{
|
|
10808
|
-
type: 'BOOK',
|
|
10809
|
-
path: null,
|
|
10810
|
-
// <- TODO: !!6 Pass here path of the file
|
|
10811
|
-
content: pipelineString,
|
|
10812
|
-
},
|
|
10813
|
-
],
|
|
10814
|
-
};
|
|
10815
|
-
}
|
|
10816
|
-
/**
|
|
10817
|
-
* Builds a short file/url identification block for parse errors.
|
|
10818
|
-
*
|
|
10819
|
-
* @private internal utility of `parsePipeline`
|
|
10820
|
-
*/
|
|
10821
|
-
function getPipelineIdentification($pipelineJson) {
|
|
10822
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
10823
|
-
const pipelineIdentificationParts = [];
|
|
10824
|
-
if ($pipelineJson.sourceFile !== undefined) {
|
|
10825
|
-
pipelineIdentificationParts.push(`File: ${$pipelineJson.sourceFile}`);
|
|
10826
|
-
}
|
|
10827
|
-
if ($pipelineJson.pipelineUrl !== undefined) {
|
|
10828
|
-
pipelineIdentificationParts.push(`Url: ${$pipelineJson.pipelineUrl}`);
|
|
10832
|
+
else if (currentType === 'COMMENT') {
|
|
10833
|
+
buffer.push(line);
|
|
10834
|
+
if (line.includes('-->')) {
|
|
10835
|
+
currentType = 'MARKDOWN';
|
|
10836
|
+
}
|
|
10837
|
+
}
|
|
10829
10838
|
}
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
/**
|
|
10833
|
-
* Removes shebang/comments and normalizes markdown into a parseable pipeline form.
|
|
10834
|
-
*
|
|
10835
|
-
* @private internal utility of `parsePipeline`
|
|
10836
|
-
*/
|
|
10837
|
-
function preparePipelineString(pipelineString, $pipelineJson) {
|
|
10838
|
-
pipelineString = removePipelineShebang(pipelineString, $pipelineJson);
|
|
10839
|
-
pipelineString = removeMarkdownComments(pipelineString);
|
|
10840
|
-
pipelineString = spaceTrim$1(pipelineString);
|
|
10841
|
-
// <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
|
|
10842
|
-
pipelineString = deflatePipeline(pipelineString);
|
|
10843
|
-
pipelineString = flattenMarkdown(pipelineString);
|
|
10844
|
-
pipelineString = pipelineString.replaceAll(INLINE_CODE_PARAMETER_REGEXP, '{$<parameterName>}');
|
|
10845
|
-
pipelineString = pipelineString.replaceAll(INLINE_CODE_RETURN_PARAMETER_REGEXP, '-> {$<parameterName>}');
|
|
10846
|
-
return pipelineString;
|
|
10839
|
+
finishSection();
|
|
10840
|
+
return sections;
|
|
10847
10841
|
}
|
|
10848
10842
|
/**
|
|
10849
|
-
*
|
|
10850
|
-
*
|
|
10851
|
-
*
|
|
10843
|
+
* TODO: [🏛] This can be part of markdown builder
|
|
10844
|
+
* Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
|
|
10845
|
+
* sophisticated implementation of this function through parsing markdown into JSON structure
|
|
10846
|
+
* and flattening the actual structure
|
|
10847
|
+
* NOW we are working just with markdown string and its good enough
|
|
10852
10848
|
*/
|
|
10853
|
-
function removePipelineShebang(pipelineString, $pipelineJson) {
|
|
10854
|
-
if (!pipelineString.startsWith('#!')) {
|
|
10855
|
-
return pipelineString;
|
|
10856
|
-
}
|
|
10857
|
-
const [shebangLine, ...restLines] = pipelineString.split(/\r?\n/);
|
|
10858
|
-
const isBookShebang = (shebangLine || '').includes('ptbk');
|
|
10859
|
-
if (!isBookShebang) {
|
|
10860
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
10861
|
-
It seems that you try to parse a book file which has non-standard shebang line for book files:
|
|
10862
|
-
Shebang line must contain 'ptbk'
|
|
10863
|
-
|
|
10864
|
-
You have:
|
|
10865
|
-
${block(shebangLine || '(empty line)')}
|
|
10866
|
-
|
|
10867
|
-
It should look like this:
|
|
10868
|
-
#!/usr/bin/env ptbk
|
|
10869
10849
|
|
|
10870
|
-
${block(getPipelineIdentification($pipelineJson))}
|
|
10871
|
-
`));
|
|
10872
|
-
}
|
|
10873
|
-
return validatePipelineString(restLines.join('\n'));
|
|
10874
|
-
}
|
|
10875
10850
|
/**
|
|
10876
10851
|
* Splits the prepared markdown into the pipeline head and task sections.
|
|
10877
10852
|
*
|
|
@@ -10888,7 +10863,7 @@ function parsePreparedPipelineSections(pipelineString, $pipelineJson) {
|
|
|
10888
10863
|
/**
|
|
10889
10864
|
* Ensures the flattened markdown has exactly one h1 head followed by only h2 sections.
|
|
10890
10865
|
*
|
|
10891
|
-
* @private internal utility of `
|
|
10866
|
+
* @private internal utility of `parsePreparedPipelineSections`
|
|
10892
10867
|
*/
|
|
10893
10868
|
function assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipelineJson) {
|
|
10894
10869
|
if (pipelineHead === undefined) {
|
|
@@ -10919,148 +10894,270 @@ function assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipeli
|
|
|
10919
10894
|
`));
|
|
10920
10895
|
}
|
|
10921
10896
|
}
|
|
10897
|
+
|
|
10922
10898
|
/**
|
|
10923
|
-
*
|
|
10899
|
+
* Number of padding lines to add at the end of the book content
|
|
10924
10900
|
*
|
|
10925
|
-
* @
|
|
10901
|
+
* @public exported from `@promptbook/core`
|
|
10926
10902
|
*/
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10903
|
+
const PADDING_LINES = 11;
|
|
10904
|
+
/**
|
|
10905
|
+
* A function that adds padding to the book content
|
|
10906
|
+
*
|
|
10907
|
+
* Note: [🔂] This function is idempotent.
|
|
10908
|
+
*
|
|
10909
|
+
* @public exported from `@promptbook/core`
|
|
10910
|
+
*/
|
|
10911
|
+
function padBook(content) {
|
|
10912
|
+
if (!content) {
|
|
10913
|
+
return '\n'.repeat(PADDING_LINES);
|
|
10914
|
+
}
|
|
10915
|
+
const lines = content.split(/\r?\n/);
|
|
10916
|
+
let trailingEmptyLines = 0;
|
|
10917
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
10918
|
+
const line = lines[i];
|
|
10919
|
+
if (line === undefined) {
|
|
10920
|
+
// Note: This should not happen in reality, but it's here to satisfy TypeScript's noUncheckedIndexedAccess option
|
|
10921
|
+
continue;
|
|
10922
|
+
}
|
|
10923
|
+
if (line.trim() === '') {
|
|
10924
|
+
trailingEmptyLines++;
|
|
10925
|
+
}
|
|
10926
|
+
else {
|
|
10927
|
+
break;
|
|
10928
|
+
}
|
|
10929
|
+
}
|
|
10930
|
+
if (trailingEmptyLines >= PADDING_LINES) {
|
|
10931
|
+
return content;
|
|
10932
10932
|
}
|
|
10933
|
+
const linesToAdd = PADDING_LINES - trailingEmptyLines;
|
|
10934
|
+
return (content + '\n'.repeat(linesToAdd));
|
|
10933
10935
|
}
|
|
10936
|
+
// TODO: [🧠] Maybe export
|
|
10937
|
+
|
|
10934
10938
|
/**
|
|
10935
|
-
*
|
|
10939
|
+
* Removes Markdown (or HTML) comments
|
|
10936
10940
|
*
|
|
10937
|
-
* @
|
|
10941
|
+
* @param {string} content - The string to remove comments from.
|
|
10942
|
+
* @returns {string} The input string with all comments removed.
|
|
10943
|
+
*
|
|
10944
|
+
* @public exported from `@promptbook/markdown-utils`
|
|
10938
10945
|
*/
|
|
10939
|
-
function
|
|
10940
|
-
|
|
10941
|
-
description = description.split(DESCRIPTION_CODE_BLOCK_REGEXP).join('');
|
|
10942
|
-
description = description.split(DESCRIPTION_BLOCKQUOTE_REGEXP).join('');
|
|
10943
|
-
description = description.split(DESCRIPTION_LIST_ITEM_REGEXP).join('');
|
|
10944
|
-
description = spaceTrim$1(description);
|
|
10945
|
-
if (description === '') {
|
|
10946
|
-
return undefined;
|
|
10947
|
-
}
|
|
10948
|
-
return description;
|
|
10946
|
+
function removeMarkdownComments(content) {
|
|
10947
|
+
return spaceTrim$1(content.replace(/<!--(.*?)-->/gs, ''));
|
|
10949
10948
|
}
|
|
10949
|
+
|
|
10950
10950
|
/**
|
|
10951
|
-
*
|
|
10951
|
+
* Utility to determine if a pipeline string is in flat format.
|
|
10952
|
+
* A flat pipeline is a simple text without proper structure (headers, blocks, etc).
|
|
10952
10953
|
*
|
|
10953
|
-
* @
|
|
10954
|
+
* @public exported from `@promptbook/editable`
|
|
10954
10955
|
*/
|
|
10955
|
-
function
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10956
|
+
function isFlatPipeline(pipelineString) {
|
|
10957
|
+
pipelineString = removeMarkdownComments(pipelineString);
|
|
10958
|
+
pipelineString = spaceTrim$1(pipelineString);
|
|
10959
|
+
const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
|
|
10960
|
+
//const isLastLineReturnStatement = pipelineString.split(/\r?\n/).pop()!.split('`').join('').startsWith('->');
|
|
10961
|
+
const isBacktickBlockUsed = pipelineString.includes('```');
|
|
10962
|
+
const isQuoteBlocksUsed = /^>\s+/m.test(pipelineString);
|
|
10963
|
+
const isBlocksUsed = isBacktickBlockUsed || isQuoteBlocksUsed;
|
|
10964
|
+
// TODO: [🧉] Also (double)check
|
|
10965
|
+
// > const usedCommands
|
|
10966
|
+
// > const isBlocksUsed
|
|
10967
|
+
// > const returnStatementCount
|
|
10968
|
+
const isFlat = !isMarkdownBeginningWithHeadline && !isBlocksUsed; /* && isLastLineReturnStatement */
|
|
10969
|
+
return isFlat;
|
|
10970
|
+
}
|
|
10961
10971
|
|
|
10962
|
-
|
|
10963
|
-
|
|
10972
|
+
/**
|
|
10973
|
+
* Converts a pipeline structure to its string representation.
|
|
10974
|
+
*
|
|
10975
|
+
* Transforms a flat, simple pipeline into a properly formatted pipeline string
|
|
10976
|
+
* with sections for title, prompt, and return statement.
|
|
10977
|
+
*
|
|
10978
|
+
* @public exported from `@promptbook/editable`
|
|
10979
|
+
*/
|
|
10980
|
+
function deflatePipeline(pipelineString) {
|
|
10981
|
+
if (!isFlatPipeline(pipelineString)) {
|
|
10982
|
+
return pipelineString;
|
|
10964
10983
|
}
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10984
|
+
pipelineString = spaceTrim$1(pipelineString);
|
|
10985
|
+
const pipelineStringLines = pipelineString.split(/\r?\n/);
|
|
10986
|
+
const potentialReturnStatement = pipelineStringLines.pop();
|
|
10987
|
+
let returnStatement;
|
|
10988
|
+
if (/(-|=)>\s*\{.*\}/.test(potentialReturnStatement)) {
|
|
10989
|
+
// Note: Last line is return statement
|
|
10990
|
+
returnStatement = potentialReturnStatement;
|
|
10991
|
+
}
|
|
10992
|
+
else {
|
|
10993
|
+
// Note: Last line is not a return statement
|
|
10994
|
+
returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
|
|
10995
|
+
pipelineStringLines.push(potentialReturnStatement);
|
|
10996
|
+
}
|
|
10997
|
+
const prompt = spaceTrim$1(pipelineStringLines.join('\n'));
|
|
10998
|
+
let quotedPrompt;
|
|
10999
|
+
if (prompt.split(/\r?\n/).length <= 1) {
|
|
11000
|
+
quotedPrompt = `> ${prompt}`;
|
|
11001
|
+
}
|
|
11002
|
+
else {
|
|
11003
|
+
quotedPrompt = spaceTrim$1((block) => `
|
|
11004
|
+
\`\`\`
|
|
11005
|
+
${block(prompt.split('`').join('\\`'))}
|
|
11006
|
+
\`\`\`
|
|
11007
|
+
`);
|
|
11008
|
+
}
|
|
11009
|
+
pipelineString = validatePipelineString(spaceTrim$1((block) => `
|
|
11010
|
+
# ${DEFAULT_BOOK_TITLE}
|
|
11011
|
+
|
|
11012
|
+
## Prompt
|
|
11013
|
+
|
|
11014
|
+
${block(quotedPrompt)}
|
|
11015
|
+
|
|
11016
|
+
${returnStatement}
|
|
11017
|
+
`));
|
|
11018
|
+
// <- TODO: Maybe use book` notation
|
|
11019
|
+
return padBook(pipelineString);
|
|
11020
|
+
}
|
|
11021
|
+
// TODO: Unit test
|
|
11022
|
+
|
|
11023
|
+
/**
|
|
11024
|
+
* Normalizes the markdown by flattening the structure
|
|
11025
|
+
*
|
|
11026
|
+
* - It always have h1 - if there is no h1 in the markdown, it will be added `DEFAULT_BOOK_TITLE`
|
|
11027
|
+
* - All other headings are normalized to h2
|
|
11028
|
+
*
|
|
11029
|
+
* @public exported from `@promptbook/markdown-utils`
|
|
11030
|
+
*/
|
|
11031
|
+
function flattenMarkdown(markdown) {
|
|
11032
|
+
const sections = splitMarkdownIntoSections(markdown);
|
|
11033
|
+
if (sections.length === 0) {
|
|
11034
|
+
return `# ${DEFAULT_BOOK_TITLE}`;
|
|
11035
|
+
}
|
|
11036
|
+
let flattenedMarkdown = '';
|
|
11037
|
+
const parsedSections = sections.map(parseMarkdownSection);
|
|
11038
|
+
const firstSection = parsedSections.shift();
|
|
11039
|
+
if (firstSection.level === 1) {
|
|
11040
|
+
flattenedMarkdown += `# ${firstSection.title}` + `\n\n`;
|
|
11041
|
+
flattenedMarkdown += firstSection.content + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
11042
|
+
}
|
|
11043
|
+
else {
|
|
11044
|
+
parsedSections.unshift(firstSection);
|
|
11045
|
+
flattenedMarkdown += `# ${DEFAULT_BOOK_TITLE}` + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
11046
|
+
}
|
|
11047
|
+
for (const { title, content } of parsedSections) {
|
|
11048
|
+
flattenedMarkdown += `## ${title}` + `\n\n`;
|
|
11049
|
+
flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
11050
|
+
}
|
|
11051
|
+
return spaceTrim$1(flattenedMarkdown);
|
|
11052
|
+
}
|
|
11053
|
+
/**
|
|
11054
|
+
* TODO: [🏛] This can be part of markdown builder
|
|
11055
|
+
* Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
|
|
11056
|
+
* sophisticated implementation of this function through parsing markdown into JSON structure
|
|
11057
|
+
* and flattening the actual structure
|
|
11058
|
+
* NOW we are working just with markdown string and its good enough
|
|
11059
|
+
*/
|
|
11060
|
+
|
|
11061
|
+
/**
|
|
11062
|
+
* Normalizes inline parameter mentions wrapped in code spans before markdown flattening.
|
|
11063
|
+
*
|
|
11064
|
+
* @private internal utility of `preparePipelineString`
|
|
11065
|
+
*/
|
|
11066
|
+
const INLINE_CODE_PARAMETER_REGEXP = /`\{(?<parameterName>[a-z0-9_]+)\}`/gi;
|
|
11067
|
+
/**
|
|
11068
|
+
* Normalizes inline return statements wrapped in code spans before markdown flattening.
|
|
11069
|
+
*
|
|
11070
|
+
* @private internal utility of `preparePipelineString`
|
|
11071
|
+
*/
|
|
11072
|
+
const INLINE_CODE_RETURN_PARAMETER_REGEXP = /`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi;
|
|
11073
|
+
/**
|
|
11074
|
+
* Removes shebang/comments and normalizes markdown into a parseable pipeline form.
|
|
11075
|
+
*
|
|
11076
|
+
* @private internal utility of `parsePipeline`
|
|
11077
|
+
*/
|
|
11078
|
+
function preparePipelineString(pipelineString, $pipelineJson) {
|
|
11079
|
+
pipelineString = removePipelineShebang(pipelineString, $pipelineJson);
|
|
11080
|
+
pipelineString = removeMarkdownComments(pipelineString);
|
|
11081
|
+
pipelineString = spaceTrim$1(pipelineString);
|
|
11082
|
+
// <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
|
|
11083
|
+
pipelineString = deflatePipeline(pipelineString);
|
|
11084
|
+
pipelineString = flattenMarkdown(pipelineString);
|
|
11085
|
+
pipelineString = pipelineString.replaceAll(INLINE_CODE_PARAMETER_REGEXP, '{$<parameterName>}');
|
|
11086
|
+
pipelineString = pipelineString.replaceAll(INLINE_CODE_RETURN_PARAMETER_REGEXP, '-> {$<parameterName>}');
|
|
11087
|
+
return pipelineString;
|
|
11088
|
+
}
|
|
11089
|
+
/**
|
|
11090
|
+
* Validates and removes the optional `#!` shebang line for `.book` files.
|
|
11091
|
+
*
|
|
11092
|
+
* @private internal utility of `preparePipelineString`
|
|
11093
|
+
*/
|
|
11094
|
+
function removePipelineShebang(pipelineString, $pipelineJson) {
|
|
11095
|
+
if (!pipelineString.startsWith('#!')) {
|
|
11096
|
+
return pipelineString;
|
|
10968
11097
|
}
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
}
|
|
11098
|
+
const [shebangLine, ...restLines] = pipelineString.split(/\r?\n/);
|
|
11099
|
+
const isBookShebang = (shebangLine || '').includes('ptbk');
|
|
11100
|
+
if (!isBookShebang) {
|
|
10973
11101
|
throw new ParseError(spaceTrim$1((block) => `
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
The error:
|
|
10977
|
-
${block(error.message)}
|
|
11102
|
+
It seems that you try to parse a book file which has non-standard shebang line for book files:
|
|
11103
|
+
Shebang line must contain 'ptbk'
|
|
10978
11104
|
|
|
10979
|
-
|
|
10980
|
-
|
|
11105
|
+
You have:
|
|
11106
|
+
${block(shebangLine || '(empty line)')}
|
|
10981
11107
|
|
|
10982
|
-
|
|
10983
|
-
|
|
11108
|
+
It should look like this:
|
|
11109
|
+
#!/usr/bin/env ptbk
|
|
10984
11110
|
|
|
10985
11111
|
${block(getPipelineIdentification($pipelineJson))}
|
|
10986
|
-
|
|
10987
|
-
}
|
|
10988
|
-
if (command.type === 'PARAMETER') {
|
|
10989
|
-
defineParameter($pipelineJson, command);
|
|
10990
|
-
// <- Note: [🍣]
|
|
11112
|
+
`));
|
|
10991
11113
|
}
|
|
11114
|
+
return validatePipelineString(restLines.join('\n'));
|
|
10992
11115
|
}
|
|
11116
|
+
|
|
10993
11117
|
/**
|
|
10994
|
-
*
|
|
11118
|
+
* Supported script languages
|
|
10995
11119
|
*
|
|
10996
|
-
* @private internal
|
|
11120
|
+
* @private internal base for `ScriptLanguage`
|
|
10997
11121
|
*/
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
|
|
11001
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
11002
|
-
Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
|
|
11122
|
+
const SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
|
|
11123
|
+
// <- TODO: [🏥] DRY
|
|
11003
11124
|
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11125
|
+
/**
|
|
11126
|
+
* Extracts exactly ONE code block from markdown.
|
|
11127
|
+
*
|
|
11128
|
+
* - When there are multiple or no code blocks the function throws a `ParseError`
|
|
11129
|
+
*
|
|
11130
|
+
* Note: There are multiple similar functions:
|
|
11131
|
+
* - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
|
|
11132
|
+
* - `extractJsonBlock` extracts exactly one valid JSON code block
|
|
11133
|
+
* - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
|
|
11134
|
+
* - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
|
|
11135
|
+
*
|
|
11136
|
+
* @param markdown any valid markdown
|
|
11137
|
+
* @returns code block with language and content
|
|
11138
|
+
* @throws {ParseError} if there is not exactly one code block in the markdown
|
|
11139
|
+
*
|
|
11140
|
+
* @public exported from `@promptbook/markdown-utils`
|
|
11141
|
+
*/
|
|
11142
|
+
function extractOneBlockFromMarkdown(markdown) {
|
|
11143
|
+
const codeBlocks = extractAllBlocksFromMarkdown(markdown);
|
|
11144
|
+
if (codeBlocks.length !== 1) {
|
|
11012
11145
|
throw new ParseError(spaceTrim$1((block) => `
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
${block(getPipelineIdentification($pipelineJson))}
|
|
11016
|
-
|
|
11017
|
-
First definition:
|
|
11018
|
-
${block(existingParameter.description || '[undefined]')}
|
|
11146
|
+
There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
|
|
11019
11147
|
|
|
11020
|
-
|
|
11021
|
-
${block(parameterDescription || '[undefined]')}
|
|
11148
|
+
${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
|
|
11022
11149
|
`));
|
|
11023
11150
|
}
|
|
11024
|
-
|
|
11025
|
-
if (parameterDescription) {
|
|
11026
|
-
existingParameter.description = parameterDescription;
|
|
11027
|
-
}
|
|
11028
|
-
existingParameter.isInput = existingParameter.isInput || isInput;
|
|
11029
|
-
existingParameter.isOutput = existingParameter.isOutput || isOutput;
|
|
11030
|
-
return;
|
|
11031
|
-
}
|
|
11032
|
-
$pipelineJson.parameters.push({
|
|
11033
|
-
name: parameterName,
|
|
11034
|
-
description: parameterDescription || undefined,
|
|
11035
|
-
isInput,
|
|
11036
|
-
isOutput,
|
|
11037
|
-
});
|
|
11151
|
+
return codeBlocks[0];
|
|
11038
11152
|
}
|
|
11153
|
+
// TODO: [🍓][🌻] Decide of this is internal utility, external util OR validator/postprocessor
|
|
11154
|
+
|
|
11039
11155
|
/**
|
|
11040
|
-
*
|
|
11156
|
+
* Matches the trailing return statement of a task section.
|
|
11041
11157
|
*
|
|
11042
|
-
* @private internal utility of `
|
|
11158
|
+
* @private internal utility of `processPipelineSection`
|
|
11043
11159
|
*/
|
|
11044
|
-
|
|
11045
|
-
const sectionCounts = {};
|
|
11046
|
-
for (const pipelineSection of pipelineSections) {
|
|
11047
|
-
const sectionName = titleToName(pipelineSection.title);
|
|
11048
|
-
if (sectionCounts[sectionName] === undefined) {
|
|
11049
|
-
sectionCounts[sectionName] = { count: 0, currentIndex: 0 };
|
|
11050
|
-
}
|
|
11051
|
-
sectionCounts[sectionName].count++;
|
|
11052
|
-
}
|
|
11053
|
-
return (title) => {
|
|
11054
|
-
const sectionName = titleToName(title);
|
|
11055
|
-
const sectionCount = sectionCounts[sectionName];
|
|
11056
|
-
if (sectionCount.count === 1) {
|
|
11057
|
-
return sectionName;
|
|
11058
|
-
}
|
|
11059
|
-
const nameWithSuffix = `${sectionName}-${sectionCount.currentIndex}`;
|
|
11060
|
-
sectionCount.currentIndex++;
|
|
11061
|
-
return nameWithSuffix;
|
|
11062
|
-
};
|
|
11063
|
-
}
|
|
11160
|
+
const RESULTING_PARAMETER_LINE_REGEXP = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im;
|
|
11064
11161
|
/**
|
|
11065
11162
|
* Parses, applies, and persists one h2 task section.
|
|
11066
11163
|
*
|
|
@@ -11080,7 +11177,7 @@ function processPipelineSection(pipelineSection, $pipelineJson, getUniqueSection
|
|
|
11080
11177
|
/**
|
|
11081
11178
|
* Creates the mutable task JSON shell from one markdown section.
|
|
11082
11179
|
*
|
|
11083
|
-
* @private internal utility of `
|
|
11180
|
+
* @private internal utility of `processPipelineSection`
|
|
11084
11181
|
*/
|
|
11085
11182
|
function createTaskJsonFromSection(pipelineSection, getUniqueSectionName) {
|
|
11086
11183
|
const { language, content } = extractOneBlockFromMarkdown(pipelineSection.content);
|
|
@@ -11108,7 +11205,7 @@ function createTaskJsonFromSection(pipelineSection, getUniqueSectionName) {
|
|
|
11108
11205
|
/**
|
|
11109
11206
|
* Extracts the optional trailing `-> {parameter}` statement from a section body.
|
|
11110
11207
|
*
|
|
11111
|
-
* @private internal utility of `
|
|
11208
|
+
* @private internal utility of `processPipelineSection`
|
|
11112
11209
|
*/
|
|
11113
11210
|
function extractResultingParameterName(sectionContent) {
|
|
11114
11211
|
var _a;
|
|
@@ -11119,7 +11216,7 @@ function extractResultingParameterName(sectionContent) {
|
|
|
11119
11216
|
/**
|
|
11120
11217
|
* Parses all list-item commands declared inside one task section.
|
|
11121
11218
|
*
|
|
11122
|
-
* @private internal utility of `
|
|
11219
|
+
* @private internal utility of `processPipelineSection`
|
|
11123
11220
|
*/
|
|
11124
11221
|
function parsePipelineTaskCommands(sectionContent) {
|
|
11125
11222
|
return extractAllListItemsFromMarkdown(sectionContent).map((listItem) => ({
|
|
@@ -11130,7 +11227,7 @@ function parsePipelineTaskCommands(sectionContent) {
|
|
|
11130
11227
|
/**
|
|
11131
11228
|
* Applies the implicit default `PROMPT_TASK` section type when no SECTION command is present.
|
|
11132
11229
|
*
|
|
11133
|
-
* @private internal utility of `
|
|
11230
|
+
* @private internal utility of `processPipelineSection`
|
|
11134
11231
|
*/
|
|
11135
11232
|
function applyDefaultTaskSectionType($taskJson, commands, $pipelineJson) {
|
|
11136
11233
|
const isSectionCommandPresent = commands.some(({ command }) => command.type === 'SECTION');
|
|
@@ -11142,7 +11239,7 @@ function applyDefaultTaskSectionType($taskJson, commands, $pipelineJson) {
|
|
|
11142
11239
|
/**
|
|
11143
11240
|
* Parses and applies one command declared inside a task section.
|
|
11144
11241
|
*
|
|
11145
|
-
* @private internal utility of `
|
|
11242
|
+
* @private internal utility of `processPipelineSection`
|
|
11146
11243
|
*/
|
|
11147
11244
|
function applyPipelineTaskCommand(commandItem, $taskJson, $pipelineJson) {
|
|
11148
11245
|
const { listItem, command } = commandItem;
|
|
@@ -11193,7 +11290,7 @@ function applyPipelineTaskCommand(commandItem, $taskJson, $pipelineJson) {
|
|
|
11193
11290
|
/**
|
|
11194
11291
|
* Validates and stores the language for SCRIPT tasks.
|
|
11195
11292
|
*
|
|
11196
|
-
* @private internal utility of `
|
|
11293
|
+
* @private internal utility of `processPipelineSection`
|
|
11197
11294
|
*/
|
|
11198
11295
|
function applyScriptTaskLanguage($taskJson, language, $pipelineJson) {
|
|
11199
11296
|
const isScriptTask = $taskJson.taskType === 'SCRIPT_TASK';
|
|
@@ -11210,7 +11307,6 @@ function applyScriptTaskLanguage($taskJson, language, $pipelineJson) {
|
|
|
11210
11307
|
if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
|
|
11211
11308
|
throw new ParseError(spaceTrim$1((block) => `
|
|
11212
11309
|
Script language ${language} is not supported.
|
|
11213
|
-
|
|
11214
11310
|
Supported languages are:
|
|
11215
11311
|
${block(SUPPORTED_SCRIPT_LANGUAGES.join(', '))}
|
|
11216
11312
|
|
|
@@ -11219,168 +11315,87 @@ function applyScriptTaskLanguage($taskJson, language, $pipelineJson) {
|
|
|
11219
11315
|
$taskJson.contentLanguage = language;
|
|
11220
11316
|
}
|
|
11221
11317
|
/**
|
|
11222
|
-
* Extracts task dependencies and ensures referenced parameters exist.
|
|
11223
|
-
*
|
|
11224
|
-
* @private internal utility of `parsePipeline`
|
|
11225
|
-
*/
|
|
11226
|
-
function registerTaskDependentParameters($taskJson, $pipelineJson) {
|
|
11227
|
-
$taskJson.dependentParameterNames = Array.from(extractParameterNamesFromTask($taskJson));
|
|
11228
|
-
for (const parameterName of $taskJson.dependentParameterNames) {
|
|
11229
|
-
// TODO: [🧠] This definition should be made first in the task
|
|
11230
|
-
defineParameter($pipelineJson, {
|
|
11231
|
-
parameterName,
|
|
11232
|
-
parameterDescription: null,
|
|
11233
|
-
isInput: false,
|
|
11234
|
-
isOutput: false,
|
|
11235
|
-
// <- Note: In this case null+false+false means that we do not know yet if it is input or output and we will set it later
|
|
11236
|
-
});
|
|
11237
|
-
}
|
|
11238
|
-
}
|
|
11239
|
-
/**
|
|
11240
|
-
* Removes transient parsing flags and persists real tasks into the pipeline JSON.
|
|
11241
|
-
*
|
|
11242
|
-
* @private internal utility of `parsePipeline`
|
|
11243
|
-
*/
|
|
11244
|
-
function persistTaskIfNeeded($taskJson, $pipelineJson) {
|
|
11245
|
-
/*
|
|
11246
|
-
// TODO: [🍧] This should be checked in `MODEL` command + better error message
|
|
11247
|
-
if ($taskJson.taskType !== 'PROMPT_TASK' && $taskJson.modelRequirements !== undefined) {
|
|
11248
|
-
throw new UnexpectedError(
|
|
11249
|
-
spaceTrim(
|
|
11250
|
-
(block) => `
|
|
11251
|
-
Model requirements are defined for the block type ${
|
|
11252
|
-
$taskJson.taskType
|
|
11253
|
-
} which is not a \`PROMPT\` task
|
|
11254
|
-
|
|
11255
|
-
This should be avoided by the \`modelCommandParser\`
|
|
11256
|
-
|
|
11257
|
-
${block(getPipelineIdentification($pipelineJson))}
|
|
11258
|
-
`,
|
|
11259
|
-
),
|
|
11260
|
-
);
|
|
11261
|
-
}
|
|
11262
|
-
*/
|
|
11263
|
-
if (!$taskJson.isTask) {
|
|
11264
|
-
return;
|
|
11265
|
-
}
|
|
11266
|
-
delete $taskJson.isSectionTypeSet;
|
|
11267
|
-
delete $taskJson.isTask;
|
|
11268
|
-
// TODO: [🍙] Maybe do reorder of `$taskJson` here
|
|
11269
|
-
$pipelineJson.tasks.push($taskJson);
|
|
11270
|
-
}
|
|
11271
|
-
/**
|
|
11272
|
-
* Applies default INPUT/OUTPUT flags when the author did not specify them explicitly.
|
|
11273
|
-
*
|
|
11274
|
-
* @private internal utility of `parsePipeline`
|
|
11275
|
-
*/
|
|
11276
|
-
function applyImplicitParameterDirections($pipelineJson) {
|
|
11277
|
-
markImplicitInputParameters($pipelineJson);
|
|
11278
|
-
markImplicitOutputParameters($pipelineJson);
|
|
11279
|
-
}
|
|
11280
|
-
/**
|
|
11281
|
-
* Marks non-result parameters as pipeline inputs when no input was declared.
|
|
11282
|
-
*
|
|
11283
|
-
* @private internal utility of `parsePipeline`
|
|
11284
|
-
*/
|
|
11285
|
-
function markImplicitInputParameters($pipelineJson) {
|
|
11286
|
-
if ($pipelineJson.parameters.some((parameter) => parameter.isInput)) {
|
|
11287
|
-
return;
|
|
11288
|
-
}
|
|
11289
|
-
for (const parameter of $pipelineJson.parameters) {
|
|
11290
|
-
const isThisParameterResulting = $pipelineJson.tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
11291
|
-
if (!isThisParameterResulting) {
|
|
11292
|
-
parameter.isInput = true;
|
|
11293
|
-
// <- TODO: [💔] Why this is making typescript error in vscode but not in cli
|
|
11294
|
-
// > Type 'true' is not assignable to type 'false'.ts(2322)
|
|
11295
|
-
// > (property) isInput: false
|
|
11296
|
-
// > The parameter is input of the pipeline The parameter is NOT input of the pipeline
|
|
11297
|
-
}
|
|
11298
|
-
}
|
|
11299
|
-
}
|
|
11300
|
-
/**
|
|
11301
|
-
* Marks every non-input parameter as output when no output was declared.
|
|
11302
|
-
*
|
|
11303
|
-
* @private internal utility of `parsePipeline`
|
|
11304
|
-
*/
|
|
11305
|
-
function markImplicitOutputParameters($pipelineJson) {
|
|
11306
|
-
if ($pipelineJson.parameters.some((parameter) => parameter.isOutput)) {
|
|
11307
|
-
return;
|
|
11308
|
-
}
|
|
11309
|
-
for (const parameter of $pipelineJson.parameters) {
|
|
11310
|
-
if (!parameter.isInput) {
|
|
11311
|
-
parameter.isOutput = true;
|
|
11312
|
-
// <- TODO: [💔]
|
|
11313
|
-
}
|
|
11314
|
-
}
|
|
11315
|
-
}
|
|
11316
|
-
/**
|
|
11317
|
-
* Removes `undefined` properties from serialized tasks and parameters.
|
|
11318
|
-
*
|
|
11319
|
-
* @private internal utility of `parsePipeline`
|
|
11320
|
-
*/
|
|
11321
|
-
function removeUndefinedValuesFromPipeline($pipelineJson) {
|
|
11322
|
-
$pipelineJson.tasks.forEach(removeUndefinedProperties);
|
|
11323
|
-
$pipelineJson.parameters.forEach(removeUndefinedProperties);
|
|
11324
|
-
}
|
|
11325
|
-
/**
|
|
11326
|
-
* Deletes all own properties with `undefined` values from a mutable JSON entity.
|
|
11327
|
-
*
|
|
11328
|
-
* @private internal utility of `parsePipeline`
|
|
11329
|
-
*/
|
|
11330
|
-
function removeUndefinedProperties(entity) {
|
|
11331
|
-
for (const [key, value] of Object.entries(entity)) {
|
|
11332
|
-
if (value === undefined) {
|
|
11333
|
-
delete entity[key];
|
|
11334
|
-
}
|
|
11335
|
-
}
|
|
11336
|
-
}
|
|
11337
|
-
/**
|
|
11338
|
-
* Applies all sync-only high-level abstractions after parsing.
|
|
11318
|
+
* Extracts task dependencies and ensures referenced parameters exist.
|
|
11339
11319
|
*
|
|
11340
|
-
* @private internal utility of `
|
|
11320
|
+
* @private internal utility of `processPipelineSection`
|
|
11341
11321
|
*/
|
|
11342
|
-
function
|
|
11343
|
-
|
|
11344
|
-
|
|
11322
|
+
function registerTaskDependentParameters($taskJson, $pipelineJson) {
|
|
11323
|
+
$taskJson.dependentParameterNames = Array.from(extractParameterNamesFromTask($taskJson));
|
|
11324
|
+
for (const parameterName of $taskJson.dependentParameterNames) {
|
|
11325
|
+
// TODO: [🧠] This definition should be made first in the task
|
|
11326
|
+
defineParameter($pipelineJson, {
|
|
11327
|
+
parameterName,
|
|
11328
|
+
parameterDescription: null,
|
|
11329
|
+
isInput: false,
|
|
11330
|
+
isOutput: false,
|
|
11331
|
+
// <- Note: In this case null+false+false means that we do not know yet if it is input or output and we will set it later
|
|
11332
|
+
});
|
|
11345
11333
|
}
|
|
11346
11334
|
}
|
|
11347
11335
|
/**
|
|
11348
|
-
*
|
|
11336
|
+
* Removes transient parsing flags and persists real tasks into the pipeline JSON.
|
|
11349
11337
|
*
|
|
11350
|
-
* @private internal utility of `
|
|
11338
|
+
* @private internal utility of `processPipelineSection`
|
|
11351
11339
|
*/
|
|
11352
|
-
function
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11340
|
+
function persistTaskIfNeeded($taskJson, $pipelineJson) {
|
|
11341
|
+
/*
|
|
11342
|
+
// TODO: [🍧] This should be checked in `MODEL` command + better error message
|
|
11343
|
+
if ($taskJson.taskType !== 'PROMPT_TASK' && $taskJson.modelRequirements !== undefined) {
|
|
11344
|
+
throw new UnexpectedError(
|
|
11345
|
+
spaceTrim(
|
|
11346
|
+
(block) => `
|
|
11347
|
+
Model requirements are defined for the block type ${
|
|
11348
|
+
$taskJson.taskType
|
|
11349
|
+
} which is not a \`PROMPT\` task
|
|
11350
|
+
|
|
11351
|
+
This should be avoided by the \`modelCommandParser\`
|
|
11352
|
+
|
|
11353
|
+
${block(getPipelineIdentification($pipelineJson))}
|
|
11354
|
+
`,
|
|
11355
|
+
),
|
|
11356
|
+
);
|
|
11357
|
+
}
|
|
11358
|
+
*/
|
|
11359
|
+
if (!$taskJson.isTask) {
|
|
11360
|
+
return;
|
|
11356
11361
|
}
|
|
11362
|
+
delete $taskJson.isSectionTypeSet;
|
|
11363
|
+
delete $taskJson.isTask;
|
|
11364
|
+
// TODO: [🍙] Maybe do reorder of `$taskJson` here
|
|
11365
|
+
$pipelineJson.tasks.push($taskJson);
|
|
11357
11366
|
}
|
|
11367
|
+
|
|
11358
11368
|
/**
|
|
11359
|
-
*
|
|
11369
|
+
* Compile pipeline from string (markdown) format to JSON format synchronously
|
|
11360
11370
|
*
|
|
11361
|
-
*
|
|
11371
|
+
* Note: There are 3 similar functions:
|
|
11372
|
+
* - `compilePipeline` **(preferred)** - which properly compiles the promptbook and uses embedding for external knowledge
|
|
11373
|
+
* - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
|
|
11374
|
+
* - `preparePipeline` - just one step in the compilation process
|
|
11375
|
+
*
|
|
11376
|
+
* Note: This function does not validate logic of the pipeline only the parsing
|
|
11377
|
+
* Note: This function acts as compilation process
|
|
11378
|
+
*
|
|
11379
|
+
* @param pipelineString {Promptbook} in string markdown format (.book.md)
|
|
11380
|
+
* @returns {Promptbook} compiled in JSON format (.bookc)
|
|
11381
|
+
* @throws {ParseError} if the promptbook string is not valid
|
|
11382
|
+
*
|
|
11383
|
+
* @public exported from `@promptbook/core`
|
|
11362
11384
|
*/
|
|
11363
|
-
function
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
});
|
|
11385
|
+
function parsePipeline(pipelineString) {
|
|
11386
|
+
const $pipelineJson = createInitialPipelineJson(pipelineString);
|
|
11387
|
+
const preparedPipelineString = preparePipelineString(pipelineString, $pipelineJson);
|
|
11388
|
+
const { pipelineHead, pipelineSections } = parsePreparedPipelineSections(preparedPipelineString, $pipelineJson);
|
|
11389
|
+
const getUniqueSectionName = createUniqueSectionNameResolver(pipelineSections);
|
|
11390
|
+
applyPipelineHead(pipelineHead, $pipelineJson);
|
|
11391
|
+
for (const pipelineSection of pipelineSections) {
|
|
11392
|
+
processPipelineSection(pipelineSection, $pipelineJson, getUniqueSectionName);
|
|
11393
|
+
}
|
|
11394
|
+
return finalizeParsedPipeline($pipelineJson);
|
|
11374
11395
|
}
|
|
11375
11396
|
// TODO: [🧠] Maybe more things here can be refactored as high-level abstractions
|
|
11376
11397
|
// TODO: [main] !!4 Warn if used only sync version
|
|
11377
11398
|
// TODO: [🚞] Report here line/column of error
|
|
11378
|
-
// TODO: Use spaceTrim more effectively
|
|
11379
|
-
// TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
|
|
11380
|
-
// TODO: [🥞] Not optimal parsing because `splitMarkdownIntoSections` is executed twice with same string, once through `flattenMarkdown` and second directly here
|
|
11381
|
-
// TODO: [♈] Probably move expectations from tasks to parameters
|
|
11382
|
-
// TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
|
|
11383
|
-
// TODO: [🍙] Make some standard order of json properties
|
|
11384
11399
|
|
|
11385
11400
|
/**
|
|
11386
11401
|
* Compile pipeline from string (markdown) format to JSON format
|
|
@@ -18128,7 +18143,9 @@ const octopus3dAvatarVisual = {
|
|
|
18128
18143
|
};
|
|
18129
18144
|
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
18130
18145
|
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
18131
|
-
const mantleRadiusZ = size *
|
|
18146
|
+
const mantleRadiusZ = size *
|
|
18147
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
18148
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
18132
18149
|
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
18133
18150
|
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
18134
18151
|
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
@@ -18214,7 +18231,11 @@ const octopus3dAvatarVisual = {
|
|
|
18214
18231
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
18215
18232
|
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
18216
18233
|
drawProjectedMouth(context, [
|
|
18217
|
-
{
|
|
18234
|
+
{
|
|
18235
|
+
x: -mouthHalfWidth,
|
|
18236
|
+
y: mouthY,
|
|
18237
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
18238
|
+
},
|
|
18218
18239
|
{
|
|
18219
18240
|
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
18220
18241
|
y: mouthY +
|
|
@@ -18223,7 +18244,11 @@ const octopus3dAvatarVisual = {
|
|
|
18223
18244
|
interaction.gazeY * size * 0.01,
|
|
18224
18245
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
18225
18246
|
},
|
|
18226
|
-
{
|
|
18247
|
+
{
|
|
18248
|
+
x: mouthHalfWidth,
|
|
18249
|
+
y: mouthY,
|
|
18250
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
18251
|
+
},
|
|
18227
18252
|
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
18228
18253
|
},
|
|
18229
18254
|
};
|
|
@@ -18384,7 +18409,8 @@ function createOctopusTentacleStrokes(options) {
|
|
|
18384
18409
|
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
18385
18410
|
};
|
|
18386
18411
|
const controlPointTwo = {
|
|
18387
|
-
x: anchorPoint.x +
|
|
18412
|
+
x: anchorPoint.x +
|
|
18413
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
18388
18414
|
y: anchorPoint.y + flowLength * 0.66,
|
|
18389
18415
|
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
18390
18416
|
};
|
|
@@ -18449,8 +18475,7 @@ function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
|
18449
18475
|
context.beginPath();
|
|
18450
18476
|
context.moveTo(startPoint.x, startPoint.y);
|
|
18451
18477
|
context.lineTo(endPoint.x, endPoint.y);
|
|
18452
|
-
context.strokeStyle =
|
|
18453
|
-
tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
18478
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
18454
18479
|
context.lineWidth = width;
|
|
18455
18480
|
context.lineCap = 'round';
|
|
18456
18481
|
context.stroke();
|
|
@@ -26645,6 +26670,212 @@ const DEFAULT_LIST_TIMEOUTS_LIMIT = 20;
|
|
|
26645
26670
|
* @private internal USE TIMEOUT constant
|
|
26646
26671
|
*/
|
|
26647
26672
|
const MAX_LIST_TIMEOUTS_LIMIT = 100;
|
|
26673
|
+
/**
|
|
26674
|
+
* Creates one formatted timeout-argument validation error.
|
|
26675
|
+
*
|
|
26676
|
+
* @private internal utility of USE TIMEOUT
|
|
26677
|
+
*/
|
|
26678
|
+
function createTimeoutToolArgsError(message) {
|
|
26679
|
+
return new PipelineExecutionError(spaceTrim$1(`
|
|
26680
|
+
${message}
|
|
26681
|
+
`));
|
|
26682
|
+
}
|
|
26683
|
+
/**
|
|
26684
|
+
* Normalizes one optional timeout id string.
|
|
26685
|
+
*
|
|
26686
|
+
* @private internal utility of USE TIMEOUT
|
|
26687
|
+
*/
|
|
26688
|
+
function normalizeOptionalTimeoutId(value) {
|
|
26689
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
26690
|
+
}
|
|
26691
|
+
/**
|
|
26692
|
+
* Parses timeout target selection for tools that accept either `timeoutId` or `allActive: true`.
|
|
26693
|
+
*
|
|
26694
|
+
* @private internal utility of USE TIMEOUT
|
|
26695
|
+
*/
|
|
26696
|
+
function parseTimeoutTargetSelection(args, options) {
|
|
26697
|
+
const timeoutId = normalizeOptionalTimeoutId(args.timeoutId);
|
|
26698
|
+
const allActive = args.allActive === true;
|
|
26699
|
+
if (timeoutId && allActive) {
|
|
26700
|
+
throw createTimeoutToolArgsError(options.bothMessage);
|
|
26701
|
+
}
|
|
26702
|
+
if (allActive) {
|
|
26703
|
+
return { allActive: true };
|
|
26704
|
+
}
|
|
26705
|
+
if (!timeoutId) {
|
|
26706
|
+
throw createTimeoutToolArgsError(options.missingMessage);
|
|
26707
|
+
}
|
|
26708
|
+
return {
|
|
26709
|
+
timeoutId,
|
|
26710
|
+
allActive: false,
|
|
26711
|
+
};
|
|
26712
|
+
}
|
|
26713
|
+
/**
|
|
26714
|
+
* Parses one explicit `dueAt` update value.
|
|
26715
|
+
*
|
|
26716
|
+
* @private internal utility of USE TIMEOUT
|
|
26717
|
+
*/
|
|
26718
|
+
function parseOptionalTimeoutDueAt(value) {
|
|
26719
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
26720
|
+
return undefined;
|
|
26721
|
+
}
|
|
26722
|
+
const normalizedDueAt = value.trim();
|
|
26723
|
+
const dueAtTimestamp = Date.parse(normalizedDueAt);
|
|
26724
|
+
if (!Number.isFinite(dueAtTimestamp)) {
|
|
26725
|
+
throw createTimeoutToolArgsError('Timeout `dueAt` must be one valid ISO timestamp.');
|
|
26726
|
+
}
|
|
26727
|
+
return new Date(dueAtTimestamp).toISOString();
|
|
26728
|
+
}
|
|
26729
|
+
/**
|
|
26730
|
+
* Parses one explicit `extendByMs` update value.
|
|
26731
|
+
*
|
|
26732
|
+
* @private internal utility of USE TIMEOUT
|
|
26733
|
+
*/
|
|
26734
|
+
function parseOptionalTimeoutExtendByMs(value) {
|
|
26735
|
+
if (typeof value !== 'number') {
|
|
26736
|
+
return undefined;
|
|
26737
|
+
}
|
|
26738
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
26739
|
+
throw createTimeoutToolArgsError('Timeout `extendByMs` must be a positive number of milliseconds.');
|
|
26740
|
+
}
|
|
26741
|
+
return Math.floor(value);
|
|
26742
|
+
}
|
|
26743
|
+
/**
|
|
26744
|
+
* Parses one explicit `recurrenceIntervalMs` update value.
|
|
26745
|
+
*
|
|
26746
|
+
* @private internal utility of USE TIMEOUT
|
|
26747
|
+
*/
|
|
26748
|
+
function parseOptionalTimeoutRecurrenceInterval(value) {
|
|
26749
|
+
if (value === null) {
|
|
26750
|
+
return null;
|
|
26751
|
+
}
|
|
26752
|
+
if (typeof value !== 'number') {
|
|
26753
|
+
return undefined;
|
|
26754
|
+
}
|
|
26755
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
26756
|
+
throw createTimeoutToolArgsError('Timeout `recurrenceIntervalMs` must be a positive number of milliseconds or `null`.');
|
|
26757
|
+
}
|
|
26758
|
+
return Math.floor(value);
|
|
26759
|
+
}
|
|
26760
|
+
/**
|
|
26761
|
+
* Parses one explicit `message` update value.
|
|
26762
|
+
*
|
|
26763
|
+
* @private internal utility of USE TIMEOUT
|
|
26764
|
+
*/
|
|
26765
|
+
function parseOptionalTimeoutMessage(value) {
|
|
26766
|
+
if (value === null) {
|
|
26767
|
+
return null;
|
|
26768
|
+
}
|
|
26769
|
+
if (typeof value !== 'string') {
|
|
26770
|
+
return undefined;
|
|
26771
|
+
}
|
|
26772
|
+
const normalizedMessage = value.trim();
|
|
26773
|
+
return normalizedMessage.length > 0 ? normalizedMessage : null;
|
|
26774
|
+
}
|
|
26775
|
+
/**
|
|
26776
|
+
* Parses one explicit `parameters` update value.
|
|
26777
|
+
*
|
|
26778
|
+
* @private internal utility of USE TIMEOUT
|
|
26779
|
+
*/
|
|
26780
|
+
function parseOptionalTimeoutParameters(value) {
|
|
26781
|
+
if (value === undefined) {
|
|
26782
|
+
return undefined;
|
|
26783
|
+
}
|
|
26784
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
26785
|
+
throw createTimeoutToolArgsError('Timeout `parameters` must be one JSON object.');
|
|
26786
|
+
}
|
|
26787
|
+
return value;
|
|
26788
|
+
}
|
|
26789
|
+
/**
|
|
26790
|
+
* Parses one explicit `paused` update value.
|
|
26791
|
+
*
|
|
26792
|
+
* @private internal utility of USE TIMEOUT
|
|
26793
|
+
*/
|
|
26794
|
+
function parseOptionalTimeoutPaused(value) {
|
|
26795
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
26796
|
+
}
|
|
26797
|
+
/**
|
|
26798
|
+
* Parses patch fields for `update_timeout`.
|
|
26799
|
+
*
|
|
26800
|
+
* @private internal utility of USE TIMEOUT
|
|
26801
|
+
*/
|
|
26802
|
+
function parseTimeoutUpdatePatch(args) {
|
|
26803
|
+
const patch = {};
|
|
26804
|
+
const dueAt = parseOptionalTimeoutDueAt(args.dueAt);
|
|
26805
|
+
const extendByMs = parseOptionalTimeoutExtendByMs(args.extendByMs);
|
|
26806
|
+
const recurrenceIntervalMs = parseOptionalTimeoutRecurrenceInterval(args.recurrenceIntervalMs);
|
|
26807
|
+
const message = parseOptionalTimeoutMessage(args.message);
|
|
26808
|
+
const parameters = parseOptionalTimeoutParameters(args.parameters);
|
|
26809
|
+
const paused = parseOptionalTimeoutPaused(args.paused);
|
|
26810
|
+
if (dueAt !== undefined) {
|
|
26811
|
+
patch.dueAt = dueAt;
|
|
26812
|
+
}
|
|
26813
|
+
if (extendByMs !== undefined) {
|
|
26814
|
+
patch.extendByMs = extendByMs;
|
|
26815
|
+
}
|
|
26816
|
+
if (patch.dueAt !== undefined && patch.extendByMs !== undefined) {
|
|
26817
|
+
throw createTimeoutToolArgsError('Timeout update cannot include both `dueAt` and `extendByMs`.');
|
|
26818
|
+
}
|
|
26819
|
+
if (recurrenceIntervalMs !== undefined) {
|
|
26820
|
+
patch.recurrenceIntervalMs = recurrenceIntervalMs;
|
|
26821
|
+
}
|
|
26822
|
+
if (message !== undefined) {
|
|
26823
|
+
patch.message = message;
|
|
26824
|
+
}
|
|
26825
|
+
if (parameters !== undefined) {
|
|
26826
|
+
patch.parameters = parameters;
|
|
26827
|
+
}
|
|
26828
|
+
if (paused !== undefined) {
|
|
26829
|
+
patch.paused = paused;
|
|
26830
|
+
}
|
|
26831
|
+
return patch;
|
|
26832
|
+
}
|
|
26833
|
+
/**
|
|
26834
|
+
* Determines whether the patch contains fields that are only supported for single-timeout updates.
|
|
26835
|
+
*
|
|
26836
|
+
* @private internal utility of USE TIMEOUT
|
|
26837
|
+
*/
|
|
26838
|
+
function hasSingleTimeoutOnlyPatchFields(patch) {
|
|
26839
|
+
return (patch.dueAt !== undefined ||
|
|
26840
|
+
patch.extendByMs !== undefined ||
|
|
26841
|
+
patch.recurrenceIntervalMs !== undefined ||
|
|
26842
|
+
patch.message !== undefined ||
|
|
26843
|
+
patch.parameters !== undefined);
|
|
26844
|
+
}
|
|
26845
|
+
/**
|
|
26846
|
+
* Parses bulk timeout update arguments.
|
|
26847
|
+
*
|
|
26848
|
+
* @private internal utility of USE TIMEOUT
|
|
26849
|
+
*/
|
|
26850
|
+
function parseBulkTimeoutUpdateArgs(patch) {
|
|
26851
|
+
if (patch.paused === undefined) {
|
|
26852
|
+
throw createTimeoutToolArgsError('Bulk timeout update with `allActive: true` requires `paused` to be explicitly set.');
|
|
26853
|
+
}
|
|
26854
|
+
if (hasSingleTimeoutOnlyPatchFields(patch)) {
|
|
26855
|
+
throw createTimeoutToolArgsError('Bulk timeout update only supports the `paused` field.');
|
|
26856
|
+
}
|
|
26857
|
+
return {
|
|
26858
|
+
allActive: true,
|
|
26859
|
+
paused: patch.paused,
|
|
26860
|
+
};
|
|
26861
|
+
}
|
|
26862
|
+
/**
|
|
26863
|
+
* Parses single-timeout update arguments.
|
|
26864
|
+
*
|
|
26865
|
+
* @private internal utility of USE TIMEOUT
|
|
26866
|
+
*/
|
|
26867
|
+
function parseSingleTimeoutUpdateArgs(timeoutId, patch) {
|
|
26868
|
+
if (!timeoutId) {
|
|
26869
|
+
throw createTimeoutToolArgsError('Timeout `timeoutId` is required for single-timeout updates.');
|
|
26870
|
+
}
|
|
26871
|
+
if (Object.keys(patch).length === 0) {
|
|
26872
|
+
throw createTimeoutToolArgsError('Timeout update must include at least one editable field.');
|
|
26873
|
+
}
|
|
26874
|
+
return {
|
|
26875
|
+
timeoutId,
|
|
26876
|
+
patch,
|
|
26877
|
+
};
|
|
26878
|
+
}
|
|
26648
26879
|
/**
|
|
26649
26880
|
* Parses and validates `USE TIMEOUT` tool arguments.
|
|
26650
26881
|
*
|
|
@@ -26671,22 +26902,14 @@ const parseTimeoutToolArgs = {
|
|
|
26671
26902
|
* Parses `cancel_timeout` input.
|
|
26672
26903
|
*/
|
|
26673
26904
|
cancel(args) {
|
|
26674
|
-
const
|
|
26675
|
-
|
|
26676
|
-
|
|
26677
|
-
|
|
26678
|
-
|
|
26679
|
-
`));
|
|
26680
|
-
}
|
|
26681
|
-
if (allActive) {
|
|
26905
|
+
const target = parseTimeoutTargetSelection(args, {
|
|
26906
|
+
bothMessage: 'Timeout cancellation must target either one `timeoutId` or `allActive: true`, not both.',
|
|
26907
|
+
missingMessage: 'Timeout `timeoutId` is required unless you pass `allActive: true`.',
|
|
26908
|
+
});
|
|
26909
|
+
if (target.allActive) {
|
|
26682
26910
|
return { allActive: true };
|
|
26683
26911
|
}
|
|
26684
|
-
|
|
26685
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26686
|
-
Timeout \`timeoutId\` is required unless you pass \`allActive: true\`.
|
|
26687
|
-
`));
|
|
26688
|
-
}
|
|
26689
|
-
return { timeoutId };
|
|
26912
|
+
return { timeoutId: target.timeoutId };
|
|
26690
26913
|
},
|
|
26691
26914
|
/**
|
|
26692
26915
|
* Parses `list_timeouts` input.
|
|
@@ -26717,106 +26940,14 @@ const parseTimeoutToolArgs = {
|
|
|
26717
26940
|
* Parses `update_timeout` input.
|
|
26718
26941
|
*/
|
|
26719
26942
|
update(args) {
|
|
26720
|
-
const
|
|
26721
|
-
|
|
26722
|
-
|
|
26723
|
-
|
|
26724
|
-
|
|
26725
|
-
|
|
26726
|
-
|
|
26727
|
-
|
|
26728
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26729
|
-
Timeout update requires one \`timeoutId\` or \`allActive: true\`.
|
|
26730
|
-
`));
|
|
26731
|
-
}
|
|
26732
|
-
const patch = {};
|
|
26733
|
-
if (typeof args.dueAt === 'string' && args.dueAt.trim().length > 0) {
|
|
26734
|
-
const normalizedDueAt = args.dueAt.trim();
|
|
26735
|
-
const dueAtTimestamp = Date.parse(normalizedDueAt);
|
|
26736
|
-
if (!Number.isFinite(dueAtTimestamp)) {
|
|
26737
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26738
|
-
Timeout \`dueAt\` must be one valid ISO timestamp.
|
|
26739
|
-
`));
|
|
26740
|
-
}
|
|
26741
|
-
patch.dueAt = new Date(dueAtTimestamp).toISOString();
|
|
26742
|
-
}
|
|
26743
|
-
if (typeof args.extendByMs === 'number') {
|
|
26744
|
-
if (!Number.isFinite(args.extendByMs) || args.extendByMs <= 0) {
|
|
26745
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26746
|
-
Timeout \`extendByMs\` must be a positive number of milliseconds.
|
|
26747
|
-
`));
|
|
26748
|
-
}
|
|
26749
|
-
patch.extendByMs = Math.floor(args.extendByMs);
|
|
26750
|
-
}
|
|
26751
|
-
if (patch.dueAt !== undefined && patch.extendByMs !== undefined) {
|
|
26752
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26753
|
-
Timeout update cannot include both \`dueAt\` and \`extendByMs\`.
|
|
26754
|
-
`));
|
|
26755
|
-
}
|
|
26756
|
-
if (args.recurrenceIntervalMs === null) {
|
|
26757
|
-
patch.recurrenceIntervalMs = null;
|
|
26758
|
-
}
|
|
26759
|
-
else if (typeof args.recurrenceIntervalMs === 'number') {
|
|
26760
|
-
if (!Number.isFinite(args.recurrenceIntervalMs) || args.recurrenceIntervalMs <= 0) {
|
|
26761
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26762
|
-
Timeout \`recurrenceIntervalMs\` must be a positive number of milliseconds or \`null\`.
|
|
26763
|
-
`));
|
|
26764
|
-
}
|
|
26765
|
-
patch.recurrenceIntervalMs = Math.floor(args.recurrenceIntervalMs);
|
|
26766
|
-
}
|
|
26767
|
-
if (args.message === null) {
|
|
26768
|
-
patch.message = null;
|
|
26769
|
-
}
|
|
26770
|
-
else if (typeof args.message === 'string') {
|
|
26771
|
-
const normalizedMessage = args.message.trim();
|
|
26772
|
-
patch.message = normalizedMessage.length > 0 ? normalizedMessage : null;
|
|
26773
|
-
}
|
|
26774
|
-
if (args.parameters !== undefined) {
|
|
26775
|
-
if (!args.parameters || typeof args.parameters !== 'object' || Array.isArray(args.parameters)) {
|
|
26776
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26777
|
-
Timeout \`parameters\` must be one JSON object.
|
|
26778
|
-
`));
|
|
26779
|
-
}
|
|
26780
|
-
patch.parameters = args.parameters;
|
|
26781
|
-
}
|
|
26782
|
-
if (typeof args.paused === 'boolean') {
|
|
26783
|
-
patch.paused = args.paused;
|
|
26784
|
-
}
|
|
26785
|
-
if (allActive) {
|
|
26786
|
-
if (patch.paused === undefined) {
|
|
26787
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26788
|
-
Bulk timeout update with \`allActive: true\` requires \`paused\` to be explicitly set.
|
|
26789
|
-
`));
|
|
26790
|
-
}
|
|
26791
|
-
const hasSingleOnlyPatch = patch.dueAt !== undefined ||
|
|
26792
|
-
patch.extendByMs !== undefined ||
|
|
26793
|
-
patch.recurrenceIntervalMs !== undefined ||
|
|
26794
|
-
patch.message !== undefined ||
|
|
26795
|
-
patch.parameters !== undefined;
|
|
26796
|
-
if (hasSingleOnlyPatch) {
|
|
26797
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26798
|
-
Bulk timeout update only supports the \`paused\` field.
|
|
26799
|
-
`));
|
|
26800
|
-
}
|
|
26801
|
-
return {
|
|
26802
|
-
allActive: true,
|
|
26803
|
-
paused: patch.paused,
|
|
26804
|
-
};
|
|
26805
|
-
}
|
|
26806
|
-
if (!timeoutId) {
|
|
26807
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26808
|
-
Timeout \`timeoutId\` is required for single-timeout updates.
|
|
26809
|
-
`));
|
|
26810
|
-
}
|
|
26811
|
-
if (Object.keys(patch).length === 0) {
|
|
26812
|
-
throw new PipelineExecutionError(spaceTrim$1(`
|
|
26813
|
-
Timeout update must include at least one editable field.
|
|
26814
|
-
`));
|
|
26815
|
-
}
|
|
26816
|
-
return {
|
|
26817
|
-
timeoutId,
|
|
26818
|
-
patch,
|
|
26819
|
-
};
|
|
26943
|
+
const target = parseTimeoutTargetSelection(args, {
|
|
26944
|
+
bothMessage: 'Timeout update must target either one `timeoutId` or `allActive: true`, not both.',
|
|
26945
|
+
missingMessage: 'Timeout update requires one `timeoutId` or `allActive: true`.',
|
|
26946
|
+
});
|
|
26947
|
+
const patch = parseTimeoutUpdatePatch(args);
|
|
26948
|
+
return target.allActive
|
|
26949
|
+
? parseBulkTimeoutUpdateArgs(patch)
|
|
26950
|
+
: parseSingleTimeoutUpdateArgs(target.timeoutId, patch);
|
|
26820
26951
|
},
|
|
26821
26952
|
};
|
|
26822
26953
|
|