@promptbook/components 0.105.0-1 → 0.105.0-3
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 +840 -243
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +6 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +4 -0
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +10 -3
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +11 -1
- package/esm/typings/src/book-2.0/agent-source/communication-samples.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.blocks.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.import.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSource.import.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSourceWithCommitments.blocks.test.d.ts +1 -0
- package/esm/typings/src/commitments/USE_TIME/USE_TIME.d.ts +40 -0
- package/esm/typings/src/commitments/USE_TIME/USE_TIME.test.d.ts +1 -0
- package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +8 -0
- package/esm/typings/src/commitments/_base/CommitmentDefinition.d.ts +8 -0
- package/esm/typings/src/commitments/index.d.ts +11 -2
- package/esm/typings/src/config.d.ts +1 -0
- package/esm/typings/src/import-plugins/$fileImportPlugins.d.ts +7 -0
- package/esm/typings/src/import-plugins/AgentFileImportPlugin.d.ts +7 -0
- package/esm/typings/src/import-plugins/FileImportPlugin.d.ts +24 -0
- package/esm/typings/src/import-plugins/JsonFileImportPlugin.d.ts +7 -0
- package/esm/typings/src/import-plugins/TextFileImportPlugin.d.ts +7 -0
- package/esm/typings/src/llm-providers/_common/utils/cache/cacheLlmTools.d.ts +2 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +2 -2
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +9 -2
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +3 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +10 -0
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/scripting/javascript/JavascriptExecutionToolsOptions.d.ts +6 -1
- package/esm/typings/src/types/ModelRequirements.d.ts +6 -12
- package/esm/typings/src/utils/execCommand/$execCommandNormalizeOptions.d.ts +2 -3
- package/esm/typings/src/utils/execCommand/ExecCommandOptions.d.ts +7 -1
- package/esm/typings/src/utils/organization/keepImported.d.ts +9 -0
- package/esm/typings/src/utils/organization/keepTypeImported.d.ts +0 -1
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +840 -243
- package/umd/index.umd.js.map +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.105.0-
|
|
38
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.105.0-3';
|
|
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
|
|
@@ -1106,6 +1106,7 @@ const PROMPTBOOK_SYNTAX_COLORS = {
|
|
|
1106
1106
|
SEPARATOR: Color.fromHex('#cccccc'),
|
|
1107
1107
|
COMMITMENT: Color.fromHex('#DA0F78'),
|
|
1108
1108
|
PARAMETER: Color.fromHex('#8e44ad'),
|
|
1109
|
+
CODE_BLOCK: Color.fromHex('#7700ffff'),
|
|
1109
1110
|
};
|
|
1110
1111
|
// <- TODO: [🧠][🈵] Using `Color` here increases the package size approx 3kb, maybe remove it
|
|
1111
1112
|
/**
|
|
@@ -3714,6 +3715,14 @@ class BaseCommitmentDefinition {
|
|
|
3714
3715
|
return this.appendToSystemMessage(requirements, commentSection);
|
|
3715
3716
|
}
|
|
3716
3717
|
}
|
|
3718
|
+
/**
|
|
3719
|
+
* Gets tool function implementations provided by this commitment
|
|
3720
|
+
*
|
|
3721
|
+
* When the `applyToAgentModelRequirements` adds tools to the requirements, this method should return the corresponding function definitions.
|
|
3722
|
+
*/
|
|
3723
|
+
getToolFunctions() {
|
|
3724
|
+
return {};
|
|
3725
|
+
}
|
|
3717
3726
|
}
|
|
3718
3727
|
|
|
3719
3728
|
/**
|
|
@@ -4346,79 +4355,6 @@ class FromCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
4346
4355
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4347
4356
|
*/
|
|
4348
4357
|
|
|
4349
|
-
/**
|
|
4350
|
-
* IMPORT commitment definition
|
|
4351
|
-
*
|
|
4352
|
-
* The IMPORT commitment tells the agent to import content from another agent at the current location.
|
|
4353
|
-
*
|
|
4354
|
-
* Example usage in agent source:
|
|
4355
|
-
*
|
|
4356
|
-
* ```book
|
|
4357
|
-
* IMPORT https://s6.ptbk.io/benjamin-white
|
|
4358
|
-
* ```
|
|
4359
|
-
*
|
|
4360
|
-
* @private [🪔] Maybe export the commitments through some package
|
|
4361
|
-
*/
|
|
4362
|
-
class ImportCommitmentDefinition extends BaseCommitmentDefinition {
|
|
4363
|
-
constructor(type = 'IMPORT') {
|
|
4364
|
-
super(type);
|
|
4365
|
-
}
|
|
4366
|
-
/**
|
|
4367
|
-
* Short one-line description of IMPORT.
|
|
4368
|
-
*/
|
|
4369
|
-
get description() {
|
|
4370
|
-
return 'Import content from another agent.';
|
|
4371
|
-
}
|
|
4372
|
-
/**
|
|
4373
|
-
* Icon for this commitment.
|
|
4374
|
-
*/
|
|
4375
|
-
get icon() {
|
|
4376
|
-
return '📥';
|
|
4377
|
-
}
|
|
4378
|
-
/**
|
|
4379
|
-
* Markdown documentation for IMPORT commitment.
|
|
4380
|
-
*/
|
|
4381
|
-
get documentation() {
|
|
4382
|
-
return spaceTrim$1(`
|
|
4383
|
-
# ${this.type}
|
|
4384
|
-
|
|
4385
|
-
Imports content from another agent at the location of the commitment.
|
|
4386
|
-
|
|
4387
|
-
## Examples
|
|
4388
|
-
|
|
4389
|
-
\`\`\`book
|
|
4390
|
-
My AI Agent
|
|
4391
|
-
|
|
4392
|
-
IMPORT https://s6.ptbk.io/benjamin-white
|
|
4393
|
-
RULE Speak only in English.
|
|
4394
|
-
\`\`\`
|
|
4395
|
-
`);
|
|
4396
|
-
}
|
|
4397
|
-
applyToAgentModelRequirements(requirements, content) {
|
|
4398
|
-
const trimmedContent = content.trim();
|
|
4399
|
-
if (!trimmedContent) {
|
|
4400
|
-
return requirements;
|
|
4401
|
-
}
|
|
4402
|
-
if (!isValidAgentUrl(trimmedContent)) {
|
|
4403
|
-
throw new Error(spaceTrim$1((block) => `
|
|
4404
|
-
Invalid agent URL in IMPORT commitment: "${trimmedContent}"
|
|
4405
|
-
|
|
4406
|
-
\`\`\`book
|
|
4407
|
-
${block(content)}
|
|
4408
|
-
\`\`\`
|
|
4409
|
-
`));
|
|
4410
|
-
}
|
|
4411
|
-
const importedAgentUrl = trimmedContent;
|
|
4412
|
-
return {
|
|
4413
|
-
...requirements,
|
|
4414
|
-
importedAgentUrls: [...(requirements.importedAgentUrls || []), importedAgentUrl],
|
|
4415
|
-
};
|
|
4416
|
-
}
|
|
4417
|
-
}
|
|
4418
|
-
/**
|
|
4419
|
-
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4420
|
-
*/
|
|
4421
|
-
|
|
4422
4358
|
/**
|
|
4423
4359
|
* GOAL commitment definition
|
|
4424
4360
|
*
|
|
@@ -4519,6 +4455,87 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
4519
4455
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4520
4456
|
*/
|
|
4521
4457
|
|
|
4458
|
+
/**
|
|
4459
|
+
* IMPORT commitment definition
|
|
4460
|
+
*
|
|
4461
|
+
* The IMPORT commitment tells the agent to import content from another agent at the current location.
|
|
4462
|
+
*
|
|
4463
|
+
* Example usage in agent source:
|
|
4464
|
+
*
|
|
4465
|
+
* ```book
|
|
4466
|
+
* IMPORT https://s6.ptbk.io/benjamin-white
|
|
4467
|
+
* ```
|
|
4468
|
+
*
|
|
4469
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
4470
|
+
*/
|
|
4471
|
+
class ImportCommitmentDefinition extends BaseCommitmentDefinition {
|
|
4472
|
+
constructor(type = 'IMPORT') {
|
|
4473
|
+
super(type);
|
|
4474
|
+
}
|
|
4475
|
+
/**
|
|
4476
|
+
* Short one-line description of IMPORT.
|
|
4477
|
+
*/
|
|
4478
|
+
get description() {
|
|
4479
|
+
return 'Import content from another agent or a generic text file.';
|
|
4480
|
+
}
|
|
4481
|
+
/**
|
|
4482
|
+
* Icon for this commitment.
|
|
4483
|
+
*/
|
|
4484
|
+
get icon() {
|
|
4485
|
+
return '📥';
|
|
4486
|
+
}
|
|
4487
|
+
/**
|
|
4488
|
+
* Markdown documentation for IMPORT commitment.
|
|
4489
|
+
*/
|
|
4490
|
+
get documentation() {
|
|
4491
|
+
return spaceTrim$1(`
|
|
4492
|
+
# ${this.type}
|
|
4493
|
+
|
|
4494
|
+
Imports content from another agent or a generic text file at the location of the commitment.
|
|
4495
|
+
|
|
4496
|
+
## Examples
|
|
4497
|
+
|
|
4498
|
+
\`\`\`book
|
|
4499
|
+
My AI Agent
|
|
4500
|
+
|
|
4501
|
+
IMPORT https://s6.ptbk.io/benjamin-white
|
|
4502
|
+
IMPORT https://example.com/some-text-file.txt
|
|
4503
|
+
IMPORT ./path/to/local-file.json
|
|
4504
|
+
RULE Speak only in English.
|
|
4505
|
+
\`\`\`
|
|
4506
|
+
`);
|
|
4507
|
+
}
|
|
4508
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
4509
|
+
const trimmedContent = content.trim();
|
|
4510
|
+
if (!trimmedContent) {
|
|
4511
|
+
return requirements;
|
|
4512
|
+
}
|
|
4513
|
+
if (isValidAgentUrl(trimmedContent)) {
|
|
4514
|
+
const importedAgentUrl = trimmedContent;
|
|
4515
|
+
return {
|
|
4516
|
+
...requirements,
|
|
4517
|
+
importedAgentUrls: [...(requirements.importedAgentUrls || []), importedAgentUrl],
|
|
4518
|
+
};
|
|
4519
|
+
}
|
|
4520
|
+
if (isValidUrl(trimmedContent) || isValidFilePath(trimmedContent)) {
|
|
4521
|
+
return {
|
|
4522
|
+
...requirements,
|
|
4523
|
+
importedFileUrls: [...(requirements.importedFileUrls || []), trimmedContent],
|
|
4524
|
+
};
|
|
4525
|
+
}
|
|
4526
|
+
throw new Error(spaceTrim$1((block) => `
|
|
4527
|
+
Invalid agent URL or file path in IMPORT commitment: "${trimmedContent}"
|
|
4528
|
+
|
|
4529
|
+
\`\`\`book
|
|
4530
|
+
${block(content)}
|
|
4531
|
+
\`\`\`
|
|
4532
|
+
`));
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
/**
|
|
4536
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4537
|
+
*/
|
|
4538
|
+
|
|
4522
4539
|
/**
|
|
4523
4540
|
* KNOWLEDGE commitment definition
|
|
4524
4541
|
*
|
|
@@ -4938,7 +4955,13 @@ class InitialMessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
4938
4955
|
`);
|
|
4939
4956
|
}
|
|
4940
4957
|
applyToAgentModelRequirements(requirements, content) {
|
|
4941
|
-
|
|
4958
|
+
// INITIAL MESSAGE is for UI display purposes and for conversation history construction.
|
|
4959
|
+
const newSample = { question: null, answer: content };
|
|
4960
|
+
const newSamples = [...(requirements.samples || []), newSample];
|
|
4961
|
+
return {
|
|
4962
|
+
...requirements,
|
|
4963
|
+
samples: newSamples,
|
|
4964
|
+
};
|
|
4942
4965
|
}
|
|
4943
4966
|
}
|
|
4944
4967
|
|
|
@@ -5970,27 +5993,16 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
5970
5993
|
`);
|
|
5971
5994
|
}
|
|
5972
5995
|
applyToAgentModelRequirements(requirements, content) {
|
|
5973
|
-
var _a;
|
|
5974
5996
|
// The NOTE commitment makes no changes to the system message or model requirements
|
|
5975
5997
|
// It only stores the note content in metadata for documentation purposes
|
|
5976
|
-
const trimmedContent = content
|
|
5977
|
-
if (
|
|
5998
|
+
const trimmedContent = spaceTrim$1(content);
|
|
5999
|
+
if (trimmedContent === '') {
|
|
5978
6000
|
return requirements;
|
|
5979
6001
|
}
|
|
5980
|
-
//
|
|
5981
|
-
const existingNoteContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.NOTE) || '';
|
|
5982
|
-
// Merge the new content with existing note content
|
|
5983
|
-
// When multiple NOTE commitments exist, they are aggregated together
|
|
5984
|
-
const mergedNoteContent = existingNoteContent ? `${existingNoteContent}\n${trimmedContent}` : trimmedContent;
|
|
5985
|
-
// Store the merged note content in metadata for debugging and inspection
|
|
5986
|
-
const updatedMetadata = {
|
|
5987
|
-
...requirements.metadata,
|
|
5988
|
-
NOTE: mergedNoteContent,
|
|
5989
|
-
};
|
|
5990
|
-
// Return requirements with updated metadata but no changes to system message
|
|
6002
|
+
// Return requirements with updated notes but no changes to system message
|
|
5991
6003
|
return {
|
|
5992
6004
|
...requirements,
|
|
5993
|
-
|
|
6005
|
+
notes: [...(requirements.notes || []), trimmedContent],
|
|
5994
6006
|
};
|
|
5995
6007
|
}
|
|
5996
6008
|
}
|
|
@@ -7009,6 +7021,104 @@ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
7009
7021
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
7010
7022
|
*/
|
|
7011
7023
|
|
|
7024
|
+
/**
|
|
7025
|
+
* USE TIME commitment definition
|
|
7026
|
+
*
|
|
7027
|
+
* The `USE TIME` commitment indicates that the agent should be able to determine the current date and time.
|
|
7028
|
+
*
|
|
7029
|
+
* Example usage in agent source:
|
|
7030
|
+
*
|
|
7031
|
+
* ```book
|
|
7032
|
+
* USE TIME
|
|
7033
|
+
* ```
|
|
7034
|
+
*
|
|
7035
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
7036
|
+
*/
|
|
7037
|
+
class UseTimeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
7038
|
+
constructor() {
|
|
7039
|
+
super('USE TIME', ['CURRENT TIME', 'TIME', 'DATE']);
|
|
7040
|
+
}
|
|
7041
|
+
/**
|
|
7042
|
+
* Short one-line description of USE TIME.
|
|
7043
|
+
*/
|
|
7044
|
+
get description() {
|
|
7045
|
+
return 'Enable the agent to determine the current date and time.';
|
|
7046
|
+
}
|
|
7047
|
+
/**
|
|
7048
|
+
* Icon for this commitment.
|
|
7049
|
+
*/
|
|
7050
|
+
get icon() {
|
|
7051
|
+
return '🕒';
|
|
7052
|
+
}
|
|
7053
|
+
/**
|
|
7054
|
+
* Markdown documentation for USE TIME commitment.
|
|
7055
|
+
*/
|
|
7056
|
+
get documentation() {
|
|
7057
|
+
return spaceTrim$1(`
|
|
7058
|
+
# USE TIME
|
|
7059
|
+
|
|
7060
|
+
Enables the agent to determine the current date and time.
|
|
7061
|
+
|
|
7062
|
+
## Key aspects
|
|
7063
|
+
|
|
7064
|
+
- This tool won't receive any input.
|
|
7065
|
+
- It outputs the current date and time as an ISO 8601 string.
|
|
7066
|
+
- Allows the agent to answer questions about the current time or date.
|
|
7067
|
+
|
|
7068
|
+
## Examples
|
|
7069
|
+
|
|
7070
|
+
\`\`\`book
|
|
7071
|
+
Time-aware Assistant
|
|
7072
|
+
|
|
7073
|
+
PERSONA You are a helpful assistant who knows the current time.
|
|
7074
|
+
USE TIME
|
|
7075
|
+
\`\`\`
|
|
7076
|
+
`);
|
|
7077
|
+
}
|
|
7078
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
7079
|
+
// Get existing tools array or create new one
|
|
7080
|
+
const existingTools = requirements.tools || [];
|
|
7081
|
+
// Add 'get_current_time' to tools if not already present
|
|
7082
|
+
const updatedTools = existingTools.some((tool) => tool.name === 'get_current_time')
|
|
7083
|
+
? existingTools
|
|
7084
|
+
: [
|
|
7085
|
+
...existingTools,
|
|
7086
|
+
{
|
|
7087
|
+
name: 'get_current_time',
|
|
7088
|
+
description: 'Get the current date and time in ISO 8601 format.',
|
|
7089
|
+
parameters: {
|
|
7090
|
+
type: 'object',
|
|
7091
|
+
properties: {},
|
|
7092
|
+
required: [],
|
|
7093
|
+
},
|
|
7094
|
+
},
|
|
7095
|
+
// <- TODO: !!!! define the function in LLM tools
|
|
7096
|
+
];
|
|
7097
|
+
// Return requirements with updated tools and metadata
|
|
7098
|
+
return {
|
|
7099
|
+
...requirements,
|
|
7100
|
+
tools: updatedTools,
|
|
7101
|
+
metadata: {
|
|
7102
|
+
...requirements.metadata,
|
|
7103
|
+
},
|
|
7104
|
+
};
|
|
7105
|
+
}
|
|
7106
|
+
/**
|
|
7107
|
+
* Gets the `get_current_time` tool function implementation.
|
|
7108
|
+
*/
|
|
7109
|
+
getToolFunctions() {
|
|
7110
|
+
return {
|
|
7111
|
+
async get_current_time() {
|
|
7112
|
+
console.log('!!!! [Tool] get_current_time called');
|
|
7113
|
+
return new Date().toISOString();
|
|
7114
|
+
},
|
|
7115
|
+
};
|
|
7116
|
+
}
|
|
7117
|
+
}
|
|
7118
|
+
/**
|
|
7119
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
7120
|
+
*/
|
|
7121
|
+
|
|
7012
7122
|
/**
|
|
7013
7123
|
* Placeholder commitment definition for commitments that are not yet implemented
|
|
7014
7124
|
*
|
|
@@ -7076,7 +7186,6 @@ class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
7076
7186
|
}
|
|
7077
7187
|
}
|
|
7078
7188
|
|
|
7079
|
-
// Import all commitment definition classes
|
|
7080
7189
|
/**
|
|
7081
7190
|
* Registry of all available commitment definitions
|
|
7082
7191
|
* This array contains instances of all commitment definitions
|
|
@@ -7093,10 +7202,10 @@ const COMMITMENT_REGISTRY = [
|
|
|
7093
7202
|
new MemoryCommitmentDefinition('MEMORIES'),
|
|
7094
7203
|
new StyleCommitmentDefinition('STYLE'),
|
|
7095
7204
|
new StyleCommitmentDefinition('STYLES'),
|
|
7096
|
-
new RuleCommitmentDefinition('RULE'),
|
|
7097
7205
|
new RuleCommitmentDefinition('RULES'),
|
|
7098
|
-
new
|
|
7206
|
+
new RuleCommitmentDefinition('RULE'),
|
|
7099
7207
|
new LanguageCommitmentDefinition('LANGUAGES'),
|
|
7208
|
+
new LanguageCommitmentDefinition('LANGUAGE'),
|
|
7100
7209
|
new SampleCommitmentDefinition('SAMPLE'),
|
|
7101
7210
|
new SampleCommitmentDefinition('EXAMPLE'),
|
|
7102
7211
|
new FormatCommitmentDefinition('FORMAT'),
|
|
@@ -7136,6 +7245,7 @@ const COMMITMENT_REGISTRY = [
|
|
|
7136
7245
|
new ClosedCommitmentDefinition(),
|
|
7137
7246
|
new UseBrowserCommitmentDefinition(),
|
|
7138
7247
|
new UseSearchEngineCommitmentDefinition(),
|
|
7248
|
+
new UseTimeCommitmentDefinition(),
|
|
7139
7249
|
new UseMcpCommitmentDefinition(),
|
|
7140
7250
|
new UseCommitmentDefinition(),
|
|
7141
7251
|
// Not yet implemented commitments (using placeholder)
|
|
@@ -7248,11 +7358,37 @@ function parseAgentSourceWithCommitments(agentSource) {
|
|
|
7248
7358
|
let currentCommitment = null;
|
|
7249
7359
|
// Process lines starting from after the agent name line
|
|
7250
7360
|
const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
|
|
7361
|
+
let isInsideCodeBlock = false;
|
|
7251
7362
|
for (let i = startIndex; i < lines.length; i++) {
|
|
7252
7363
|
const line = lines[i];
|
|
7253
7364
|
if (line === undefined) {
|
|
7254
7365
|
continue;
|
|
7255
7366
|
}
|
|
7367
|
+
const trimmedLine = line.trim();
|
|
7368
|
+
// Check if this line starts or ends a code block
|
|
7369
|
+
if (trimmedLine.startsWith('```')) {
|
|
7370
|
+
isInsideCodeBlock = !isInsideCodeBlock;
|
|
7371
|
+
if (currentCommitment) {
|
|
7372
|
+
// If we are inside a commitment, the code block is part of it
|
|
7373
|
+
currentCommitment.contentLines.push(line);
|
|
7374
|
+
}
|
|
7375
|
+
else {
|
|
7376
|
+
// If we are not inside a commitment, the code block is non-commitment
|
|
7377
|
+
nonCommitmentLines.push(line);
|
|
7378
|
+
}
|
|
7379
|
+
continue;
|
|
7380
|
+
}
|
|
7381
|
+
if (isInsideCodeBlock) {
|
|
7382
|
+
if (currentCommitment) {
|
|
7383
|
+
// If we are inside a commitment and a code block, the line is part of the commitment
|
|
7384
|
+
currentCommitment.contentLines.push(line);
|
|
7385
|
+
}
|
|
7386
|
+
else {
|
|
7387
|
+
// If we are inside a code block but not a commitment, the line is non-commitment
|
|
7388
|
+
nonCommitmentLines.push(line);
|
|
7389
|
+
}
|
|
7390
|
+
continue;
|
|
7391
|
+
}
|
|
7256
7392
|
// Check if this line starts a new commitment
|
|
7257
7393
|
let foundNewCommitment = false;
|
|
7258
7394
|
for (const definition of COMMITMENT_REGISTRY) {
|
|
@@ -7426,7 +7562,24 @@ function parseAgentSource(agentSource) {
|
|
|
7426
7562
|
const meta = {};
|
|
7427
7563
|
const links = [];
|
|
7428
7564
|
const capabilities = [];
|
|
7565
|
+
const samples = [];
|
|
7566
|
+
let pendingUserMessage = null;
|
|
7429
7567
|
for (const commitment of parseResult.commitments) {
|
|
7568
|
+
if (commitment.type === 'INITIAL MESSAGE') {
|
|
7569
|
+
samples.push({ question: null, answer: commitment.content });
|
|
7570
|
+
continue;
|
|
7571
|
+
}
|
|
7572
|
+
if (commitment.type === 'USER MESSAGE') {
|
|
7573
|
+
pendingUserMessage = commitment.content;
|
|
7574
|
+
continue;
|
|
7575
|
+
}
|
|
7576
|
+
if (commitment.type === 'AGENT MESSAGE') {
|
|
7577
|
+
if (pendingUserMessage !== null) {
|
|
7578
|
+
samples.push({ question: pendingUserMessage, answer: commitment.content });
|
|
7579
|
+
pendingUserMessage = null;
|
|
7580
|
+
}
|
|
7581
|
+
continue;
|
|
7582
|
+
}
|
|
7430
7583
|
if (commitment.type === 'USE BROWSER') {
|
|
7431
7584
|
capabilities.push({
|
|
7432
7585
|
type: 'browser',
|
|
@@ -7443,6 +7596,37 @@ function parseAgentSource(agentSource) {
|
|
|
7443
7596
|
});
|
|
7444
7597
|
continue;
|
|
7445
7598
|
}
|
|
7599
|
+
if (commitment.type === 'USE TIME') {
|
|
7600
|
+
capabilities.push({
|
|
7601
|
+
type: 'time',
|
|
7602
|
+
label: 'Time',
|
|
7603
|
+
iconName: 'Clock',
|
|
7604
|
+
});
|
|
7605
|
+
continue;
|
|
7606
|
+
}
|
|
7607
|
+
if (commitment.type === 'IMPORT') {
|
|
7608
|
+
const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
|
|
7609
|
+
let label = content;
|
|
7610
|
+
const iconName = 'Download';
|
|
7611
|
+
try {
|
|
7612
|
+
if (content.startsWith('http://') || content.startsWith('https://')) {
|
|
7613
|
+
const url = new URL(content);
|
|
7614
|
+
label = url.hostname.replace(/^www\./, '') + '.../' + url.pathname.split('/').pop();
|
|
7615
|
+
}
|
|
7616
|
+
else if (content.startsWith('./') || content.startsWith('../') || content.startsWith('/')) {
|
|
7617
|
+
label = content.split('/').pop() || content;
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
catch (e) {
|
|
7621
|
+
// Invalid URL or path, keep default label
|
|
7622
|
+
}
|
|
7623
|
+
capabilities.push({
|
|
7624
|
+
type: 'knowledge',
|
|
7625
|
+
label,
|
|
7626
|
+
iconName,
|
|
7627
|
+
});
|
|
7628
|
+
continue;
|
|
7629
|
+
}
|
|
7446
7630
|
if (commitment.type === 'KNOWLEDGE') {
|
|
7447
7631
|
const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
|
|
7448
7632
|
let label = content;
|
|
@@ -7527,6 +7711,7 @@ function parseAgentSource(agentSource) {
|
|
|
7527
7711
|
links,
|
|
7528
7712
|
parameters,
|
|
7529
7713
|
capabilities,
|
|
7714
|
+
samples,
|
|
7530
7715
|
};
|
|
7531
7716
|
}
|
|
7532
7717
|
/**
|
|
@@ -8596,13 +8781,17 @@ function BookEditorMonaco(props) {
|
|
|
8596
8781
|
// Register a new language
|
|
8597
8782
|
monaco.languages.register({ id: BOOK_LANGUAGE_ID });
|
|
8598
8783
|
const commitmentTypes = [...new Set(getAllCommitmentDefinitions().map(({ type }) => type))];
|
|
8599
|
-
const commitmentRegex = new RegExp(
|
|
8784
|
+
const commitmentRegex = new RegExp(`^\\s*(${commitmentTypes
|
|
8785
|
+
.sort((a, b) => b.length - a.length) // [1] Prefer longer commitments to avoid partial matching (e.g. LANGUAGES vs LANGUAGE)
|
|
8786
|
+
.map((type) => (type === 'META' ? 'META\\s+\\w+' : type.replace(/\s+/, '\\s+')))
|
|
8787
|
+
.join('|')})(?=\\s|$)`);
|
|
8600
8788
|
// Note: Using a broad character set for Latin and Cyrillic to support international characters in parameters.
|
|
8601
8789
|
// Monarch tokenizer does not support Unicode property escapes like \p{L}.
|
|
8602
8790
|
const parameterRegex = /@([a-zA-Z0-9_á-žÁ-Žč-řČ-Řš-žŠ-Žа-яА-ЯёЁ]+)/;
|
|
8603
8791
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8604
8792
|
const bookRules = [
|
|
8605
8793
|
[/^---[-]*$/, ''],
|
|
8794
|
+
[/^```.*$/, 'code-block', '@codeblock'],
|
|
8606
8795
|
[parameterRegex, 'parameter'],
|
|
8607
8796
|
[/\{[^}]+\}/, 'parameter'],
|
|
8608
8797
|
[commitmentRegex, 'commitment'],
|
|
@@ -8614,10 +8803,15 @@ function BookEditorMonaco(props) {
|
|
|
8614
8803
|
root: [
|
|
8615
8804
|
[/^\s*$/, 'empty'],
|
|
8616
8805
|
[/^-*$/, 'line'],
|
|
8806
|
+
[/^```.*$/, 'code-block', '@codeblock'],
|
|
8617
8807
|
[/^.*$/, 'title', '@body'],
|
|
8618
8808
|
[commitmentRegex, 'commitment'],
|
|
8619
8809
|
],
|
|
8620
8810
|
body: bookRules,
|
|
8811
|
+
codeblock: [
|
|
8812
|
+
[/^```.*$/, 'code-block', '@pop'],
|
|
8813
|
+
[/^.*$/, 'code-block'],
|
|
8814
|
+
],
|
|
8621
8815
|
},
|
|
8622
8816
|
});
|
|
8623
8817
|
// Register a completion item provider for the language
|
|
@@ -8659,6 +8853,10 @@ function BookEditorMonaco(props) {
|
|
|
8659
8853
|
foreground: PROMPTBOOK_SYNTAX_COLORS.PARAMETER.toHex(),
|
|
8660
8854
|
fontStyle: `italic`,
|
|
8661
8855
|
},
|
|
8856
|
+
{
|
|
8857
|
+
token: 'code-block',
|
|
8858
|
+
foreground: PROMPTBOOK_SYNTAX_COLORS.CODE_BLOCK.toHex(),
|
|
8859
|
+
},
|
|
8662
8860
|
],
|
|
8663
8861
|
colors: {
|
|
8664
8862
|
'editor.scrollbarSlider.background': '#E0E0E0',
|
|
@@ -8715,12 +8913,35 @@ function BookEditorMonaco(props) {
|
|
|
8715
8913
|
.${instanceClass} .monaco-editor .transparent-text {
|
|
8716
8914
|
color: transparent !important;
|
|
8717
8915
|
}
|
|
8916
|
+
|
|
8917
|
+
.${instanceClass} .monaco-editor .code-block-box {
|
|
8918
|
+
background-color: #f5f5f566;
|
|
8919
|
+
border-left: 1px solid ${PROMPTBOOK_SYNTAX_COLORS.CODE_BLOCK.toHex()};
|
|
8920
|
+
border-right: 1px solid ${PROMPTBOOK_SYNTAX_COLORS.CODE_BLOCK.toHex()};
|
|
8921
|
+
padding-left: ${Math.round(8 * zoomLevel)}px;
|
|
8922
|
+
padding-right: ${Math.round(8 * zoomLevel)}px;
|
|
8923
|
+
}
|
|
8924
|
+
|
|
8925
|
+
.${instanceClass} .monaco-editor .code-block-top {
|
|
8926
|
+
border-top: 1px solid ${PROMPTBOOK_SYNTAX_COLORS.CODE_BLOCK.toHex()};
|
|
8927
|
+
border-top-left-radius: ${Math.round(10 * zoomLevel)}px;
|
|
8928
|
+
border-top-right-radius: ${Math.round(10 * zoomLevel)}px;
|
|
8929
|
+
overflow: hidden;
|
|
8930
|
+
}
|
|
8931
|
+
|
|
8932
|
+
.${instanceClass} .monaco-editor .code-block-bottom {
|
|
8933
|
+
border-bottom: 1px solid ${PROMPTBOOK_SYNTAX_COLORS.CODE_BLOCK.toHex()};
|
|
8934
|
+
border-bottom-left-radius: ${Math.round(10 * zoomLevel)}px;
|
|
8935
|
+
border-bottom-right-radius: ${Math.round(10 * zoomLevel)}px;
|
|
8936
|
+
overflow: hidden;
|
|
8937
|
+
}
|
|
8718
8938
|
`;
|
|
8719
8939
|
return () => {
|
|
8720
8940
|
// Note: Style is not removed on purpose to avoid flickering during development with fast refresh
|
|
8721
8941
|
};
|
|
8722
8942
|
}, [scaledLineHeight, scaledContentPaddingLeft, scaledVerticalLineLeft]);
|
|
8723
8943
|
const decorationIdsRef = useRef([]);
|
|
8944
|
+
const codeBlockDecorationIdsRef = useRef([]);
|
|
8724
8945
|
useEffect(() => {
|
|
8725
8946
|
if (!editor || !monaco) {
|
|
8726
8947
|
return;
|
|
@@ -8749,6 +8970,39 @@ function BookEditorMonaco(props) {
|
|
|
8749
8970
|
});
|
|
8750
8971
|
}
|
|
8751
8972
|
decorationIdsRef.current = editor.deltaDecorations(decorationIdsRef.current, newDecorations);
|
|
8973
|
+
// Add decorations for code blocks
|
|
8974
|
+
const lines = text.split('\n');
|
|
8975
|
+
const codeBlockDecorations = [];
|
|
8976
|
+
let inCodeBlock = false;
|
|
8977
|
+
let codeBlockStartLine = 0;
|
|
8978
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8979
|
+
const line = lines[i];
|
|
8980
|
+
if (line === null || line === void 0 ? void 0 : line.trim().startsWith('```')) {
|
|
8981
|
+
if (!inCodeBlock) {
|
|
8982
|
+
// Starting a code block
|
|
8983
|
+
inCodeBlock = true;
|
|
8984
|
+
codeBlockStartLine = i + 1; // 1-based line number
|
|
8985
|
+
}
|
|
8986
|
+
else {
|
|
8987
|
+
// Ending a code block
|
|
8988
|
+
inCodeBlock = false;
|
|
8989
|
+
const endLine = i + 1; // 1-based line number
|
|
8990
|
+
// Add decorations for each line in the code block
|
|
8991
|
+
for (let j = codeBlockStartLine; j <= endLine; j++) {
|
|
8992
|
+
const isFirst = j === codeBlockStartLine;
|
|
8993
|
+
const isLast = j === endLine;
|
|
8994
|
+
codeBlockDecorations.push({
|
|
8995
|
+
range: new monaco.Range(j, 1, j, 1),
|
|
8996
|
+
options: {
|
|
8997
|
+
isWholeLine: true,
|
|
8998
|
+
className: `code-block-box${isFirst ? ' code-block-top' : ''}${isLast ? ' code-block-bottom' : ''}`,
|
|
8999
|
+
},
|
|
9000
|
+
});
|
|
9001
|
+
}
|
|
9002
|
+
}
|
|
9003
|
+
}
|
|
9004
|
+
}
|
|
9005
|
+
codeBlockDecorationIdsRef.current = editor.deltaDecorations(codeBlockDecorationIdsRef.current, codeBlockDecorations);
|
|
8752
9006
|
};
|
|
8753
9007
|
updateDecorations();
|
|
8754
9008
|
const changeListener = editor.onDidChangeModelContent(() => {
|
|
@@ -12716,74 +12970,90 @@ function addUsage(...usageItems) {
|
|
|
12716
12970
|
* in real-time through an observable.
|
|
12717
12971
|
*
|
|
12718
12972
|
* @param llmTools - The LLM tools to be intercepted and tracked
|
|
12719
|
-
* @returns
|
|
12973
|
+
* @returns Full proxy of the tools with added usage tracking capabilities
|
|
12720
12974
|
* @public exported from `@promptbook/core`
|
|
12721
12975
|
*/
|
|
12722
12976
|
function countUsage(llmTools) {
|
|
12723
12977
|
let totalUsage = ZERO_USAGE;
|
|
12724
12978
|
const spending = new Subject();
|
|
12725
|
-
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
//
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
|
|
12734
|
-
//
|
|
12735
|
-
|
|
12736
|
-
|
|
12737
|
-
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12742
|
-
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
//
|
|
12747
|
-
|
|
12979
|
+
// Create a Proxy to intercept all property access and ensure full proxying of all properties
|
|
12980
|
+
const proxyTools = new Proxy(llmTools, {
|
|
12981
|
+
get(target, prop, receiver) {
|
|
12982
|
+
// Handle title property
|
|
12983
|
+
if (prop === 'title') {
|
|
12984
|
+
return `${target.title} (+usage)`;
|
|
12985
|
+
// <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
|
|
12986
|
+
// <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
|
|
12987
|
+
}
|
|
12988
|
+
// Handle description property
|
|
12989
|
+
if (prop === 'description') {
|
|
12990
|
+
return `${target.description} (+usage)`;
|
|
12991
|
+
// <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
|
|
12992
|
+
// <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
|
|
12993
|
+
}
|
|
12994
|
+
// Handle spending method (new method added by this wrapper)
|
|
12995
|
+
if (prop === 'spending') {
|
|
12996
|
+
return () => {
|
|
12997
|
+
return spending.asObservable();
|
|
12998
|
+
};
|
|
12999
|
+
}
|
|
13000
|
+
// Handle getTotalUsage method (new method added by this wrapper)
|
|
13001
|
+
if (prop === 'getTotalUsage') {
|
|
13002
|
+
// <- Note: [🥫] Not using getter `get totalUsage` but `getTotalUsage` to allow this object to be proxied
|
|
13003
|
+
return () => {
|
|
13004
|
+
return totalUsage;
|
|
13005
|
+
};
|
|
13006
|
+
}
|
|
13007
|
+
// Handle callChatModel method with usage counting
|
|
13008
|
+
if (prop === 'callChatModel' && target.callChatModel !== undefined) {
|
|
13009
|
+
return async (prompt) => {
|
|
13010
|
+
// console.info('[🚕] callChatModel through countTotalUsage');
|
|
13011
|
+
const promptResult = await target.callChatModel(prompt);
|
|
13012
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
13013
|
+
spending.next(promptResult.usage);
|
|
13014
|
+
return promptResult;
|
|
13015
|
+
};
|
|
13016
|
+
}
|
|
13017
|
+
// Handle callCompletionModel method with usage counting
|
|
13018
|
+
if (prop === 'callCompletionModel' && target.callCompletionModel !== undefined) {
|
|
13019
|
+
return async (prompt) => {
|
|
13020
|
+
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
13021
|
+
const promptResult = await target.callCompletionModel(prompt);
|
|
13022
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
13023
|
+
spending.next(promptResult.usage);
|
|
13024
|
+
return promptResult;
|
|
13025
|
+
};
|
|
13026
|
+
}
|
|
13027
|
+
// Handle callEmbeddingModel method with usage counting
|
|
13028
|
+
if (prop === 'callEmbeddingModel' && target.callEmbeddingModel !== undefined) {
|
|
13029
|
+
return async (prompt) => {
|
|
13030
|
+
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
13031
|
+
const promptResult = await target.callEmbeddingModel(prompt);
|
|
13032
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
13033
|
+
spending.next(promptResult.usage);
|
|
13034
|
+
return promptResult;
|
|
13035
|
+
};
|
|
13036
|
+
}
|
|
13037
|
+
// Handle callImageGenerationModel method with usage counting
|
|
13038
|
+
if (prop === 'callImageGenerationModel' && target.callImageGenerationModel !== undefined) {
|
|
13039
|
+
return async (prompt) => {
|
|
13040
|
+
// console.info('[🚕] callImageGenerationModel through countTotalUsage');
|
|
13041
|
+
const promptResult = await target.callImageGenerationModel(prompt);
|
|
13042
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
13043
|
+
spending.next(promptResult.usage);
|
|
13044
|
+
return promptResult;
|
|
13045
|
+
};
|
|
13046
|
+
}
|
|
13047
|
+
// <- Note: [🤖]
|
|
13048
|
+
// For all other properties and methods, delegate to the original target
|
|
13049
|
+
const value = Reflect.get(target, prop, receiver);
|
|
13050
|
+
// If it's a function, bind it to the target to preserve context
|
|
13051
|
+
if (typeof value === 'function') {
|
|
13052
|
+
return value.bind(target);
|
|
13053
|
+
}
|
|
13054
|
+
return value;
|
|
12748
13055
|
},
|
|
12749
|
-
};
|
|
12750
|
-
if (llmTools.callChatModel !== undefined) {
|
|
12751
|
-
proxyTools.callChatModel = async (prompt) => {
|
|
12752
|
-
// console.info('[🚕] callChatModel through countTotalUsage');
|
|
12753
|
-
const promptResult = await llmTools.callChatModel(prompt);
|
|
12754
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
12755
|
-
spending.next(promptResult.usage);
|
|
12756
|
-
return promptResult;
|
|
12757
|
-
};
|
|
12758
|
-
}
|
|
12759
|
-
if (llmTools.callCompletionModel !== undefined) {
|
|
12760
|
-
proxyTools.callCompletionModel = async (prompt) => {
|
|
12761
|
-
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
12762
|
-
const promptResult = await llmTools.callCompletionModel(prompt);
|
|
12763
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
12764
|
-
spending.next(promptResult.usage);
|
|
12765
|
-
return promptResult;
|
|
12766
|
-
};
|
|
12767
|
-
}
|
|
12768
|
-
if (llmTools.callEmbeddingModel !== undefined) {
|
|
12769
|
-
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
12770
|
-
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
12771
|
-
const promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
12772
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
12773
|
-
spending.next(promptResult.usage);
|
|
12774
|
-
return promptResult;
|
|
12775
|
-
};
|
|
12776
|
-
}
|
|
12777
|
-
if (llmTools.callImageGenerationModel !== undefined) {
|
|
12778
|
-
proxyTools.callImageGenerationModel = async (prompt) => {
|
|
12779
|
-
// console.info('[🚕] callImageGenerationModel through countTotalUsage');
|
|
12780
|
-
const promptResult = await llmTools.callImageGenerationModel(prompt);
|
|
12781
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
12782
|
-
spending.next(promptResult.usage);
|
|
12783
|
-
return promptResult;
|
|
12784
|
-
};
|
|
12785
|
-
}
|
|
12786
|
-
// <- Note: [🤖]
|
|
13056
|
+
});
|
|
12787
13057
|
return proxyTools;
|
|
12788
13058
|
}
|
|
12789
13059
|
/**
|
|
@@ -15563,6 +15833,97 @@ function createBasicAgentModelRequirements(agentName) {
|
|
|
15563
15833
|
* TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
|
|
15564
15834
|
*/
|
|
15565
15835
|
|
|
15836
|
+
/**
|
|
15837
|
+
* Plugin for importing agent books *(`.book` files)*
|
|
15838
|
+
*
|
|
15839
|
+
* @private [🥝] Maybe export the import plugins through some package
|
|
15840
|
+
*/
|
|
15841
|
+
const AgentFileImportPlugin = {
|
|
15842
|
+
name: 'agent-file-import-plugin',
|
|
15843
|
+
canImport(mimeType) {
|
|
15844
|
+
// [🧠] Should we have a specific MIME type for agent books?
|
|
15845
|
+
// For now, let's assume it's identified by .book extension or certain MIME types if provided
|
|
15846
|
+
return mimeType === 'text/x-promptbook' || mimeType === 'application/x-promptbook';
|
|
15847
|
+
},
|
|
15848
|
+
import(content) {
|
|
15849
|
+
const parseResult = parseAgentSourceWithCommitments(content);
|
|
15850
|
+
// Bring only the agent corpus (non-commitment lines and relevant commitments)
|
|
15851
|
+
// Stripping the agent name (which is usually the first line)
|
|
15852
|
+
const corpus = parseResult.nonCommitmentLines
|
|
15853
|
+
.filter((line, index) => index > 0 || !parseResult.agentName)
|
|
15854
|
+
.join('\n')
|
|
15855
|
+
.trim();
|
|
15856
|
+
// Also include relevant commitments that make up the "corpus" of the agent
|
|
15857
|
+
// For example PERSONA, RULE, KNOWLEDGE
|
|
15858
|
+
const relevantCommitments = parseResult.commitments
|
|
15859
|
+
.filter((c) => ['PERSONA', 'RULE', 'KNOWLEDGE'].includes(c.type))
|
|
15860
|
+
.map((c) => `${c.type} ${c.content}`)
|
|
15861
|
+
.join('\n\n');
|
|
15862
|
+
return spaceTrim$1((block) => `
|
|
15863
|
+
${block(relevantCommitments)}
|
|
15864
|
+
|
|
15865
|
+
${block(corpus)}
|
|
15866
|
+
`).trim();
|
|
15867
|
+
},
|
|
15868
|
+
};
|
|
15869
|
+
|
|
15870
|
+
/**
|
|
15871
|
+
* Plugin for importing JSON files
|
|
15872
|
+
*
|
|
15873
|
+
* @private [🥝] Maybe export the import plugins through some package
|
|
15874
|
+
*/
|
|
15875
|
+
const JsonFileImportPlugin = {
|
|
15876
|
+
name: 'json-file-import-plugin',
|
|
15877
|
+
canImport(mimeType) {
|
|
15878
|
+
return mimeType === 'application/json' || mimeType.endsWith('+json');
|
|
15879
|
+
},
|
|
15880
|
+
import(content) {
|
|
15881
|
+
try {
|
|
15882
|
+
const json = JSON.parse(content);
|
|
15883
|
+
const formattedJson = JSON.stringify(json, null, 4);
|
|
15884
|
+
return `\`\`\`json\n${formattedJson}\n\`\`\``;
|
|
15885
|
+
}
|
|
15886
|
+
catch (error) {
|
|
15887
|
+
// If JSON is invalid, still import it but maybe not as pretty JSON
|
|
15888
|
+
return `\`\`\`json\n${content}\n\`\`\``;
|
|
15889
|
+
}
|
|
15890
|
+
},
|
|
15891
|
+
};
|
|
15892
|
+
|
|
15893
|
+
/**
|
|
15894
|
+
* Plugin for importing generic text files
|
|
15895
|
+
*
|
|
15896
|
+
* @private [🥝] Maybe export the import plugins through some package
|
|
15897
|
+
*/
|
|
15898
|
+
const TextFileImportPlugin = {
|
|
15899
|
+
name: 'text-file-import-plugin',
|
|
15900
|
+
canImport(mimeType) {
|
|
15901
|
+
return (mimeType === 'text/plain' ||
|
|
15902
|
+
mimeType === 'text/markdown' ||
|
|
15903
|
+
mimeType === 'text/x-typescript' ||
|
|
15904
|
+
mimeType === 'text/javascript' ||
|
|
15905
|
+
mimeType === 'text/css' ||
|
|
15906
|
+
mimeType === 'text/html' ||
|
|
15907
|
+
mimeType.startsWith('text/'));
|
|
15908
|
+
},
|
|
15909
|
+
import(content, mimeType) {
|
|
15910
|
+
const extension = mimeTypeToExtension(mimeType);
|
|
15911
|
+
const codeBlockType = extension || 'txt';
|
|
15912
|
+
return `\`\`\`${codeBlockType}\n${content}\n\`\`\``;
|
|
15913
|
+
},
|
|
15914
|
+
};
|
|
15915
|
+
|
|
15916
|
+
/**
|
|
15917
|
+
* All available file import plugins
|
|
15918
|
+
*
|
|
15919
|
+
* @private [🥝] Maybe export the import plugins through some package
|
|
15920
|
+
*/
|
|
15921
|
+
const $fileImportPlugins = [
|
|
15922
|
+
AgentFileImportPlugin,
|
|
15923
|
+
JsonFileImportPlugin,
|
|
15924
|
+
TextFileImportPlugin,
|
|
15925
|
+
];
|
|
15926
|
+
|
|
15566
15927
|
/**
|
|
15567
15928
|
* Removes comment lines (lines starting with #) from a system message
|
|
15568
15929
|
* This is used to clean up the final system message before sending it to the AI model
|
|
@@ -15594,6 +15955,7 @@ function removeCommentsFromSystemMessage(systemMessage) {
|
|
|
15594
15955
|
* @public exported from `@promptbook/core`
|
|
15595
15956
|
*/
|
|
15596
15957
|
async function createAgentModelRequirementsWithCommitments(agentSource, modelName) {
|
|
15958
|
+
var _a;
|
|
15597
15959
|
// Parse the agent source to extract commitments
|
|
15598
15960
|
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
15599
15961
|
// Apply DELETE filtering: remove prior commitments tagged by parameters targeted by DELETE/CANCEL/DISCARD/REMOVE
|
|
@@ -15660,6 +16022,64 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
15660
16022
|
}
|
|
15661
16023
|
}
|
|
15662
16024
|
}
|
|
16025
|
+
// Handle IMPORT commitments for generic files
|
|
16026
|
+
// Note: This logic could be moved to ImportCommitmentDefinition, but it needs to be asynchronous
|
|
16027
|
+
if (requirements.importedFileUrls && requirements.importedFileUrls.length > 0) {
|
|
16028
|
+
for (const fileUrl of requirements.importedFileUrls) {
|
|
16029
|
+
try {
|
|
16030
|
+
// 1. Mocked security check
|
|
16031
|
+
await mockedSecurityCheck(fileUrl);
|
|
16032
|
+
// 2. Fetch file content
|
|
16033
|
+
let content;
|
|
16034
|
+
let mimeType = null;
|
|
16035
|
+
if (isValidUrl(fileUrl)) {
|
|
16036
|
+
const response = await promptbookFetch(fileUrl);
|
|
16037
|
+
if (!response.ok) {
|
|
16038
|
+
throw new Error(`Failed to fetch ${fileUrl}: ${response.statusText}`);
|
|
16039
|
+
}
|
|
16040
|
+
content = await response.text();
|
|
16041
|
+
mimeType = response.headers.get('Content-Type');
|
|
16042
|
+
/*
|
|
16043
|
+
TODO: !!!! Commented out this case because we need to work in Browser-compatible mode in many packages, use passed `fs` instead
|
|
16044
|
+
} else if (isValidFilePath(fileUrl)) {
|
|
16045
|
+
// [x🟢x] This code is expected to run in Node environment if local files are used
|
|
16046
|
+
const fs = await import('fs/promises');
|
|
16047
|
+
content = await fs.readFile(fileUrl, 'utf-8');
|
|
16048
|
+
const extension = getFileExtension(fileUrl);
|
|
16049
|
+
mimeType = extensionToMimeType(extension as string);
|
|
16050
|
+
*/
|
|
16051
|
+
}
|
|
16052
|
+
else {
|
|
16053
|
+
throw new Error(`Invalid file URL or path: ${fileUrl}`);
|
|
16054
|
+
}
|
|
16055
|
+
if (!mimeType) {
|
|
16056
|
+
mimeType = 'text/plain';
|
|
16057
|
+
}
|
|
16058
|
+
// Remove charset from mime type
|
|
16059
|
+
mimeType = mimeType.split(';')[0].trim();
|
|
16060
|
+
// 3. Prevent importing binary files (mocked check)
|
|
16061
|
+
if (isBinaryMimeType(mimeType)) {
|
|
16062
|
+
throw new Error(`Importing binary files is not allowed: ${mimeType}`);
|
|
16063
|
+
}
|
|
16064
|
+
// 4. Find appropriate plugin
|
|
16065
|
+
const plugin = $fileImportPlugins.find((p) => p.canImport(mimeType));
|
|
16066
|
+
if (!plugin) {
|
|
16067
|
+
throw new Error(`No import plugin found for MIME type: ${mimeType}`);
|
|
16068
|
+
}
|
|
16069
|
+
// 5. Process content
|
|
16070
|
+
const importedContent = await plugin.import(content, mimeType);
|
|
16071
|
+
// 6. Append to system message
|
|
16072
|
+
requirements = {
|
|
16073
|
+
...requirements,
|
|
16074
|
+
systemMessage: requirements.systemMessage + '\n\n' + importedContent,
|
|
16075
|
+
};
|
|
16076
|
+
}
|
|
16077
|
+
catch (error) {
|
|
16078
|
+
console.warn(`Failed to import file ${fileUrl}:`, error);
|
|
16079
|
+
// Continue with other imports even if one fails
|
|
16080
|
+
}
|
|
16081
|
+
}
|
|
16082
|
+
}
|
|
15663
16083
|
// Handle MCP servers (extract from original agent source)
|
|
15664
16084
|
const mcpServers = extractMcpServers(agentSource);
|
|
15665
16085
|
if (mcpServers.length > 0) {
|
|
@@ -15669,9 +16089,11 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
15669
16089
|
};
|
|
15670
16090
|
}
|
|
15671
16091
|
// Add non-commitment lines to system message if they exist
|
|
16092
|
+
// Note: Filtering out horizontal lines (---) as requested
|
|
15672
16093
|
const nonCommitmentContent = parseResult.nonCommitmentLines
|
|
15673
16094
|
.filter((line, index) => index > 0 || !parseResult.agentName) // Skip first line if it's the agent name
|
|
15674
16095
|
.filter((line) => line.trim()) // Remove empty lines
|
|
16096
|
+
.filter((line) => !/^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/.test(line)) // Remove horizontal lines
|
|
15675
16097
|
.join('\n')
|
|
15676
16098
|
.trim();
|
|
15677
16099
|
if (nonCommitmentContent) {
|
|
@@ -15680,6 +16102,26 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
15680
16102
|
systemMessage: requirements.systemMessage + '\n\n' + nonCommitmentContent,
|
|
15681
16103
|
};
|
|
15682
16104
|
}
|
|
16105
|
+
// Add example interactions to the system message
|
|
16106
|
+
const examples = [];
|
|
16107
|
+
// 1. Initial message as an example agent response
|
|
16108
|
+
const initialMessage = (_a = parseResult.commitments.find((c) => c.type === 'INITIAL MESSAGE')) === null || _a === void 0 ? void 0 : _a.content;
|
|
16109
|
+
if (initialMessage) {
|
|
16110
|
+
examples.push(`Agent: ${initialMessage}`);
|
|
16111
|
+
}
|
|
16112
|
+
// 2. User and Agent message pairs
|
|
16113
|
+
if (requirements.samples && requirements.samples.length > 0) {
|
|
16114
|
+
for (const sample of requirements.samples) {
|
|
16115
|
+
examples.push(`User: ${sample.question}\nAgent: ${sample.answer}`);
|
|
16116
|
+
}
|
|
16117
|
+
}
|
|
16118
|
+
if (examples.length > 0) {
|
|
16119
|
+
const exampleInteractionsContent = `Example interaction:\n\n${examples.join('\n\n')}`;
|
|
16120
|
+
requirements = {
|
|
16121
|
+
...requirements,
|
|
16122
|
+
systemMessage: requirements.systemMessage + '\n\n' + exampleInteractionsContent,
|
|
16123
|
+
};
|
|
16124
|
+
}
|
|
15683
16125
|
// Remove comment lines (lines starting with #) from the final system message
|
|
15684
16126
|
// while preserving the original content with comments in metadata
|
|
15685
16127
|
const cleanedSystemMessage = removeCommentsFromSystemMessage(requirements.systemMessage);
|
|
@@ -15688,6 +16130,36 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
15688
16130
|
systemMessage: cleanedSystemMessage,
|
|
15689
16131
|
};
|
|
15690
16132
|
}
|
|
16133
|
+
/**
|
|
16134
|
+
* Mocked security check for imported files
|
|
16135
|
+
*
|
|
16136
|
+
* @param urlOrPath - The URL or local path of the file to check
|
|
16137
|
+
* @returns A promise that resolves if the file is safe
|
|
16138
|
+
*/
|
|
16139
|
+
async function mockedSecurityCheck(urlOrPath) {
|
|
16140
|
+
// TODO: Implement proper security checks
|
|
16141
|
+
await new Promise((resolve) => setTimeout(resolve, 10)); // Mock async delay
|
|
16142
|
+
if (urlOrPath.includes('malicious')) {
|
|
16143
|
+
throw new Error(`Security check failed for: ${urlOrPath}`);
|
|
16144
|
+
}
|
|
16145
|
+
}
|
|
16146
|
+
/**
|
|
16147
|
+
* Checks if the given MIME type belongs to a binary file
|
|
16148
|
+
*
|
|
16149
|
+
* @param mimeType - The MIME type to check
|
|
16150
|
+
* @returns True if it's a binary MIME type
|
|
16151
|
+
*/
|
|
16152
|
+
function isBinaryMimeType(mimeType) {
|
|
16153
|
+
const binaryPrefixes = [
|
|
16154
|
+
'image/',
|
|
16155
|
+
'video/',
|
|
16156
|
+
'audio/',
|
|
16157
|
+
'application/octet-stream',
|
|
16158
|
+
'application/pdf',
|
|
16159
|
+
'application/zip',
|
|
16160
|
+
];
|
|
16161
|
+
return binaryPrefixes.some((prefix) => mimeType.startsWith(prefix));
|
|
16162
|
+
}
|
|
15691
16163
|
|
|
15692
16164
|
/**
|
|
15693
16165
|
* Creates model requirements for an agent based on its source
|
|
@@ -17514,7 +17986,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17514
17986
|
* Calls OpenAI API to use a chat model with streaming.
|
|
17515
17987
|
*/
|
|
17516
17988
|
async callChatModelStream(prompt, onProgress) {
|
|
17517
|
-
var _a, _b, _c;
|
|
17989
|
+
var _a, _b, _c, _d;
|
|
17518
17990
|
if (this.options.isVerbose) {
|
|
17519
17991
|
console.info('💬 OpenAI callChatModel call', { prompt });
|
|
17520
17992
|
}
|
|
@@ -17569,6 +18041,131 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17569
18041
|
}
|
|
17570
18042
|
// Always add the current user message
|
|
17571
18043
|
threadMessages.push({ role: 'user', content: rawPromptContent });
|
|
18044
|
+
// Check if tools are being used - if so, use non-streaming mode
|
|
18045
|
+
const hasTools = modelRequirements.tools !== undefined && modelRequirements.tools.length > 0;
|
|
18046
|
+
const start = $getCurrentDate();
|
|
18047
|
+
let complete;
|
|
18048
|
+
// [🐱🚀] When tools are present, we need to use the non-streaming Runs API
|
|
18049
|
+
// because streaming doesn't support tool execution flow properly
|
|
18050
|
+
if (hasTools) {
|
|
18051
|
+
const rawRequest = {
|
|
18052
|
+
assistant_id: this.assistantId,
|
|
18053
|
+
thread: {
|
|
18054
|
+
messages: threadMessages,
|
|
18055
|
+
},
|
|
18056
|
+
tools: mapToolsToOpenAi(modelRequirements.tools),
|
|
18057
|
+
};
|
|
18058
|
+
if (this.options.isVerbose) {
|
|
18059
|
+
console.info(colors.bgWhite('rawRequest (non-streaming with tools)'), JSON.stringify(rawRequest, null, 4));
|
|
18060
|
+
}
|
|
18061
|
+
// Create thread and run
|
|
18062
|
+
const threadAndRun = await client.beta.threads.createAndRun(rawRequest);
|
|
18063
|
+
let run = threadAndRun;
|
|
18064
|
+
// Poll until run completes or requires action
|
|
18065
|
+
while (run.status === 'queued' || run.status === 'in_progress' || run.status === 'requires_action') {
|
|
18066
|
+
if (run.status === 'requires_action' && ((_a = run.required_action) === null || _a === void 0 ? void 0 : _a.type) === 'submit_tool_outputs') {
|
|
18067
|
+
// Execute tools
|
|
18068
|
+
const toolCalls = run.required_action.submit_tool_outputs.tool_calls;
|
|
18069
|
+
const toolOutputs = [];
|
|
18070
|
+
for (const toolCall of toolCalls) {
|
|
18071
|
+
if (toolCall.type === 'function') {
|
|
18072
|
+
const functionName = toolCall.function.name;
|
|
18073
|
+
const functionArgs = JSON.parse(toolCall.function.arguments);
|
|
18074
|
+
if (this.options.isVerbose) {
|
|
18075
|
+
console.info(`🔧 Executing tool: ${functionName}`, functionArgs);
|
|
18076
|
+
}
|
|
18077
|
+
// Get execution tools for script execution
|
|
18078
|
+
const executionTools = this.options
|
|
18079
|
+
.executionTools;
|
|
18080
|
+
if (!executionTools || !executionTools.script) {
|
|
18081
|
+
throw new PipelineExecutionError(`Model requested tool '${functionName}' but no executionTools.script were provided in OpenAiAssistantExecutionTools options`);
|
|
18082
|
+
}
|
|
18083
|
+
// TODO: [DRY] Use some common tool caller (similar to OpenAiCompatibleExecutionTools)
|
|
18084
|
+
const scriptTools = Array.isArray(executionTools.script)
|
|
18085
|
+
? executionTools.script
|
|
18086
|
+
: [executionTools.script];
|
|
18087
|
+
let functionResponse;
|
|
18088
|
+
try {
|
|
18089
|
+
const scriptTool = scriptTools[0]; // <- TODO: [🧠] Which script tool to use?
|
|
18090
|
+
functionResponse = await scriptTool.execute({
|
|
18091
|
+
scriptLanguage: 'javascript',
|
|
18092
|
+
script: `
|
|
18093
|
+
const args = ${JSON.stringify(functionArgs)};
|
|
18094
|
+
return await ${functionName}(args);
|
|
18095
|
+
`,
|
|
18096
|
+
parameters: {}, // <- TODO: [🧠] What parameters to pass?
|
|
18097
|
+
});
|
|
18098
|
+
if (this.options.isVerbose) {
|
|
18099
|
+
console.info(`✅ Tool ${functionName} executed:`, functionResponse);
|
|
18100
|
+
}
|
|
18101
|
+
}
|
|
18102
|
+
catch (error) {
|
|
18103
|
+
assertsError(error);
|
|
18104
|
+
functionResponse = spaceTrim$2((block) => `
|
|
18105
|
+
|
|
18106
|
+
The invoked tool \`${functionName}\` failed with error:
|
|
18107
|
+
|
|
18108
|
+
\`\`\`json
|
|
18109
|
+
${block(JSON.stringify(serializeError(error), null, 4))}
|
|
18110
|
+
\`\`\`
|
|
18111
|
+
|
|
18112
|
+
`);
|
|
18113
|
+
console.error(colors.bgRed(`❌ Error executing tool ${functionName}:`));
|
|
18114
|
+
console.error(error);
|
|
18115
|
+
}
|
|
18116
|
+
toolOutputs.push({
|
|
18117
|
+
tool_call_id: toolCall.id,
|
|
18118
|
+
output: functionResponse,
|
|
18119
|
+
});
|
|
18120
|
+
}
|
|
18121
|
+
}
|
|
18122
|
+
// Submit tool outputs
|
|
18123
|
+
run = await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
|
|
18124
|
+
tool_outputs: toolOutputs,
|
|
18125
|
+
});
|
|
18126
|
+
}
|
|
18127
|
+
else {
|
|
18128
|
+
// Wait a bit before polling again
|
|
18129
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
18130
|
+
run = await client.beta.threads.runs.retrieve(run.thread_id, run.id);
|
|
18131
|
+
}
|
|
18132
|
+
}
|
|
18133
|
+
if (run.status !== 'completed') {
|
|
18134
|
+
throw new PipelineExecutionError(`Assistant run failed with status: ${run.status}`);
|
|
18135
|
+
}
|
|
18136
|
+
// Get messages from the thread
|
|
18137
|
+
const messages = await client.beta.threads.messages.list(run.thread_id);
|
|
18138
|
+
const assistantMessages = messages.data.filter((msg) => msg.role === 'assistant');
|
|
18139
|
+
if (assistantMessages.length === 0) {
|
|
18140
|
+
throw new PipelineExecutionError('No assistant messages found after run completion');
|
|
18141
|
+
}
|
|
18142
|
+
const lastMessage = assistantMessages[0];
|
|
18143
|
+
const textContent = lastMessage.content.find((c) => c.type === 'text');
|
|
18144
|
+
if (!textContent || textContent.type !== 'text') {
|
|
18145
|
+
throw new PipelineExecutionError('No text content in assistant response');
|
|
18146
|
+
}
|
|
18147
|
+
complete = $getCurrentDate();
|
|
18148
|
+
const resultContent = textContent.text.value;
|
|
18149
|
+
const usage = UNCERTAIN_USAGE;
|
|
18150
|
+
// Progress callback with final result
|
|
18151
|
+
const finalChunk = {
|
|
18152
|
+
content: resultContent,
|
|
18153
|
+
modelName: 'assistant',
|
|
18154
|
+
timing: { start, complete },
|
|
18155
|
+
usage,
|
|
18156
|
+
rawPromptContent,
|
|
18157
|
+
rawRequest,
|
|
18158
|
+
rawResponse: { run, messages: messages.data },
|
|
18159
|
+
};
|
|
18160
|
+
onProgress(finalChunk);
|
|
18161
|
+
return exportJson({
|
|
18162
|
+
name: 'promptResult',
|
|
18163
|
+
message: `Result of \`OpenAiAssistantExecutionTools.callChatModelStream\` (with tools)`,
|
|
18164
|
+
order: [],
|
|
18165
|
+
value: finalChunk,
|
|
18166
|
+
});
|
|
18167
|
+
}
|
|
18168
|
+
// Streaming mode (without tools)
|
|
17572
18169
|
const rawRequest = {
|
|
17573
18170
|
// TODO: [👨👨👧👧] ...modelSettings,
|
|
17574
18171
|
// TODO: [👨👨👧👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
|
|
@@ -17579,10 +18176,8 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17579
18176
|
tools: modelRequirements.tools === undefined ? undefined : mapToolsToOpenAi(modelRequirements.tools),
|
|
17580
18177
|
// <- TODO: Add user identification here> user: this.options.user,
|
|
17581
18178
|
};
|
|
17582
|
-
const start = $getCurrentDate();
|
|
17583
|
-
let complete;
|
|
17584
18179
|
if (this.options.isVerbose) {
|
|
17585
|
-
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
18180
|
+
console.info(colors.bgWhite('rawRequest (streaming)'), JSON.stringify(rawRequest, null, 4));
|
|
17586
18181
|
}
|
|
17587
18182
|
const stream = await client.beta.threads.createAndRunStream(rawRequest);
|
|
17588
18183
|
stream.on('connect', () => {
|
|
@@ -17618,6 +18213,15 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17618
18213
|
console.info('messageDone', message);
|
|
17619
18214
|
}
|
|
17620
18215
|
});
|
|
18216
|
+
// TODO: [🐱🚀] Handle tool calls in assistants
|
|
18217
|
+
// Note: OpenAI Assistant streaming with tool calls requires special handling.
|
|
18218
|
+
// The stream will pause when a tool call is needed, and we need to:
|
|
18219
|
+
// 1. Wait for the run to reach 'requires_action' status
|
|
18220
|
+
// 2. Execute the tool calls
|
|
18221
|
+
// 3. Submit tool outputs via a separate API call (not on the stream)
|
|
18222
|
+
// 4. Continue the run
|
|
18223
|
+
// This requires switching to non-streaming mode or using the Runs API directly.
|
|
18224
|
+
// For now, tools with assistants should use the non-streaming chat completions API instead.
|
|
17621
18225
|
const rawResponse = await stream.finalMessages();
|
|
17622
18226
|
if (this.options.isVerbose) {
|
|
17623
18227
|
console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
|
|
@@ -17628,10 +18232,10 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17628
18232
|
if (rawResponse[0].content.length !== 1) {
|
|
17629
18233
|
throw new PipelineExecutionError(`There is NOT 1 BUT ${rawResponse[0].content.length} finalMessages content from OpenAI`);
|
|
17630
18234
|
}
|
|
17631
|
-
if (((
|
|
17632
|
-
throw new PipelineExecutionError(`There is NOT 'text' BUT ${(
|
|
18235
|
+
if (((_b = rawResponse[0].content[0]) === null || _b === void 0 ? void 0 : _b.type) !== 'text') {
|
|
18236
|
+
throw new PipelineExecutionError(`There is NOT 'text' BUT ${(_c = rawResponse[0].content[0]) === null || _c === void 0 ? void 0 : _c.type} finalMessages content type from OpenAI`);
|
|
17633
18237
|
}
|
|
17634
|
-
const resultContent = (
|
|
18238
|
+
const resultContent = (_d = rawResponse[0].content[0]) === null || _d === void 0 ? void 0 : _d.text.value;
|
|
17635
18239
|
// <- TODO: [🧠] There are also annotations, maybe use them
|
|
17636
18240
|
// eslint-disable-next-line prefer-const
|
|
17637
18241
|
complete = $getCurrentDate();
|
|
@@ -17699,7 +18303,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17699
18303
|
throw new NotAllowed(`Creating new assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
|
|
17700
18304
|
}
|
|
17701
18305
|
// await this.playground();
|
|
17702
|
-
const { name, instructions, knowledgeSources } = options;
|
|
18306
|
+
const { name, instructions, knowledgeSources, tools } = options;
|
|
17703
18307
|
const client = await this.getClient();
|
|
17704
18308
|
let vectorStoreId;
|
|
17705
18309
|
// If knowledge sources are provided, create a vector store with them
|
|
@@ -17770,7 +18374,11 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17770
18374
|
description: 'Assistant created via Promptbook',
|
|
17771
18375
|
model: 'gpt-4o',
|
|
17772
18376
|
instructions,
|
|
17773
|
-
tools: [
|
|
18377
|
+
tools: [
|
|
18378
|
+
/* TODO: [🧠] Maybe add { type: 'code_interpreter' }, */
|
|
18379
|
+
{ type: 'file_search' },
|
|
18380
|
+
...(tools === undefined ? [] : mapToolsToOpenAi(tools)),
|
|
18381
|
+
],
|
|
17774
18382
|
};
|
|
17775
18383
|
// Attach vector store if created
|
|
17776
18384
|
if (vectorStoreId) {
|
|
@@ -17795,7 +18403,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17795
18403
|
if (!this.isCreatingNewAssistantsAllowed) {
|
|
17796
18404
|
throw new NotAllowed(`Updating assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
|
|
17797
18405
|
}
|
|
17798
|
-
const { assistantId, name, instructions, knowledgeSources } = options;
|
|
18406
|
+
const { assistantId, name, instructions, knowledgeSources, tools } = options;
|
|
17799
18407
|
const client = await this.getClient();
|
|
17800
18408
|
let vectorStoreId;
|
|
17801
18409
|
// If knowledge sources are provided, create a vector store with them
|
|
@@ -17864,7 +18472,11 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17864
18472
|
const assistantUpdate = {
|
|
17865
18473
|
name,
|
|
17866
18474
|
instructions,
|
|
17867
|
-
tools: [
|
|
18475
|
+
tools: [
|
|
18476
|
+
/* TODO: [🧠] Maybe add { type: 'code_interpreter' }, */
|
|
18477
|
+
{ type: 'file_search' },
|
|
18478
|
+
...(tools === undefined ? [] : mapToolsToOpenAi(tools)),
|
|
18479
|
+
],
|
|
17868
18480
|
};
|
|
17869
18481
|
if (vectorStoreId) {
|
|
17870
18482
|
assistantUpdate.tool_resources = {
|
|
@@ -17905,6 +18517,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
17905
18517
|
*/
|
|
17906
18518
|
const DISCRIMINANT = 'OPEN_AI_ASSISTANT_V1';
|
|
17907
18519
|
/**
|
|
18520
|
+
* TODO: [🙎] In `OpenAiAssistantExecutionTools` Allow to create abstract assistants with `isCreatingNewAssistantsAllowed`
|
|
17908
18521
|
* TODO: [🧠][🧙♂️] Maybe there can be some wizard for those who want to use just OpenAI
|
|
17909
18522
|
* TODO: Maybe make custom OpenAiError
|
|
17910
18523
|
* TODO: [🧠][🈁] Maybe use `isDeterministic` from options
|
|
@@ -17963,8 +18576,10 @@ class AgentLlmExecutionTools {
|
|
|
17963
18576
|
}
|
|
17964
18577
|
/**
|
|
17965
18578
|
* Get cached or create agent model requirements
|
|
18579
|
+
*
|
|
18580
|
+
* Note: [🐤] This is names `getModelRequirements` *(not `getAgentModelRequirements`)* because in future these two will be united
|
|
17966
18581
|
*/
|
|
17967
|
-
async
|
|
18582
|
+
async getModelRequirements() {
|
|
17968
18583
|
if (this._cachedModelRequirements === null) {
|
|
17969
18584
|
// Get available models from underlying LLM tools for best model selection
|
|
17970
18585
|
const availableModels = await this.options.llmTools.listModels();
|
|
@@ -18034,9 +18649,25 @@ class AgentLlmExecutionTools {
|
|
|
18034
18649
|
if (prompt.modelRequirements.modelVariant !== 'CHAT') {
|
|
18035
18650
|
throw new Error('AgentLlmExecutionTools only supports chat prompts');
|
|
18036
18651
|
}
|
|
18037
|
-
const modelRequirements = await this.
|
|
18652
|
+
const modelRequirements = await this.getModelRequirements();
|
|
18038
18653
|
const chatPrompt = prompt;
|
|
18039
18654
|
let underlyingLlmResult;
|
|
18655
|
+
// Create modified chat prompt with agent system message
|
|
18656
|
+
const promptWithAgentModelRequirements = {
|
|
18657
|
+
...chatPrompt,
|
|
18658
|
+
modelRequirements: {
|
|
18659
|
+
...chatPrompt.modelRequirements,
|
|
18660
|
+
...modelRequirements,
|
|
18661
|
+
// Spread tools to convert readonly array to mutable
|
|
18662
|
+
tools: modelRequirements.tools ? [...modelRequirements.tools] : chatPrompt.modelRequirements.tools,
|
|
18663
|
+
// Prepend agent system message to existing system message
|
|
18664
|
+
systemMessage: modelRequirements.systemMessage +
|
|
18665
|
+
(chatPrompt.modelRequirements.systemMessage
|
|
18666
|
+
? `\n\n${chatPrompt.modelRequirements.systemMessage}`
|
|
18667
|
+
: ''),
|
|
18668
|
+
},
|
|
18669
|
+
};
|
|
18670
|
+
console.log('!!!! promptWithAgentModelRequirements:', promptWithAgentModelRequirements);
|
|
18040
18671
|
if (OpenAiAssistantExecutionTools.isOpenAiAssistantExecutionTools(this.options.llmTools)) {
|
|
18041
18672
|
const requirementsHash = SHA256(JSON.stringify(modelRequirements)).toString();
|
|
18042
18673
|
const cached = AgentLlmExecutionTools.assistantCache.get(this.title);
|
|
@@ -18057,6 +18688,7 @@ class AgentLlmExecutionTools {
|
|
|
18057
18688
|
name: this.title,
|
|
18058
18689
|
instructions: modelRequirements.systemMessage,
|
|
18059
18690
|
knowledgeSources: modelRequirements.knowledgeSources,
|
|
18691
|
+
tools: modelRequirements.tools ? [...modelRequirements.tools] : undefined,
|
|
18060
18692
|
});
|
|
18061
18693
|
AgentLlmExecutionTools.assistantCache.set(this.title, {
|
|
18062
18694
|
assistantId: assistant.assistantId,
|
|
@@ -18073,6 +18705,7 @@ class AgentLlmExecutionTools {
|
|
|
18073
18705
|
name: this.title,
|
|
18074
18706
|
instructions: modelRequirements.systemMessage,
|
|
18075
18707
|
knowledgeSources: modelRequirements.knowledgeSources,
|
|
18708
|
+
tools: modelRequirements.tools ? [...modelRequirements.tools] : undefined,
|
|
18076
18709
|
/*
|
|
18077
18710
|
!!!
|
|
18078
18711
|
metadata: {
|
|
@@ -18085,32 +18718,28 @@ class AgentLlmExecutionTools {
|
|
|
18085
18718
|
requirementsHash,
|
|
18086
18719
|
});
|
|
18087
18720
|
}
|
|
18088
|
-
|
|
18721
|
+
// Create modified chat prompt with agent system message specific to OpenAI Assistant
|
|
18722
|
+
const promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools = {
|
|
18723
|
+
...promptWithAgentModelRequirements,
|
|
18724
|
+
modelRequirements: {
|
|
18725
|
+
...promptWithAgentModelRequirements.modelRequirements,
|
|
18726
|
+
modelName: undefined,
|
|
18727
|
+
systemMessage: undefined,
|
|
18728
|
+
temperature: undefined, // <- Note: Let the Assistant use its default temperature
|
|
18729
|
+
},
|
|
18730
|
+
};
|
|
18731
|
+
console.log('!!!! promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools:', promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools);
|
|
18732
|
+
underlyingLlmResult = await assistant.callChatModelStream(promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools, onProgress);
|
|
18089
18733
|
}
|
|
18090
18734
|
else {
|
|
18091
18735
|
if (this.options.isVerbose) {
|
|
18092
18736
|
console.log(`2️⃣ Creating Assistant ${this.title} on generic LLM execution tools...`);
|
|
18093
18737
|
}
|
|
18094
|
-
// Create modified chat prompt with agent system message
|
|
18095
|
-
const modifiedChatPrompt = {
|
|
18096
|
-
...chatPrompt,
|
|
18097
|
-
modelRequirements: {
|
|
18098
|
-
...chatPrompt.modelRequirements,
|
|
18099
|
-
...modelRequirements,
|
|
18100
|
-
// Spread tools to convert readonly array to mutable
|
|
18101
|
-
tools: modelRequirements.tools ? [...modelRequirements.tools] : chatPrompt.modelRequirements.tools,
|
|
18102
|
-
// Prepend agent system message to existing system message
|
|
18103
|
-
systemMessage: modelRequirements.systemMessage +
|
|
18104
|
-
(chatPrompt.modelRequirements.systemMessage
|
|
18105
|
-
? `\n\n${chatPrompt.modelRequirements.systemMessage}`
|
|
18106
|
-
: ''),
|
|
18107
|
-
},
|
|
18108
|
-
};
|
|
18109
18738
|
if (this.options.llmTools.callChatModelStream) {
|
|
18110
|
-
underlyingLlmResult = await this.options.llmTools.callChatModelStream(
|
|
18739
|
+
underlyingLlmResult = await this.options.llmTools.callChatModelStream(promptWithAgentModelRequirements, onProgress);
|
|
18111
18740
|
}
|
|
18112
18741
|
else if (this.options.llmTools.callChatModel) {
|
|
18113
|
-
underlyingLlmResult = await this.options.llmTools.callChatModel(
|
|
18742
|
+
underlyingLlmResult = await this.options.llmTools.callChatModel(promptWithAgentModelRequirements);
|
|
18114
18743
|
onProgress(underlyingLlmResult);
|
|
18115
18744
|
}
|
|
18116
18745
|
else {
|
|
@@ -18139,7 +18768,8 @@ AgentLlmExecutionTools.assistantCache = new Map();
|
|
|
18139
18768
|
* TODO: [🧠] Adding parameter substitution support (here or should be responsibility of the underlying LLM Tools)
|
|
18140
18769
|
*/
|
|
18141
18770
|
|
|
18142
|
-
var _Agent_instances,
|
|
18771
|
+
var _Agent_instances, _Agent_selfLearnSamples;
|
|
18772
|
+
// !!!!! import { RemoteAgent } from './RemoteAgent'; // <- [💞] <- !!!!!
|
|
18143
18773
|
/**
|
|
18144
18774
|
* Represents one AI Agent
|
|
18145
18775
|
*
|
|
@@ -18199,6 +18829,10 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
18199
18829
|
* This is parsed from commitments like USE BROWSER, USE SEARCH ENGINE, KNOWLEDGE, etc.
|
|
18200
18830
|
*/
|
|
18201
18831
|
this.capabilities = [];
|
|
18832
|
+
/**
|
|
18833
|
+
* List of sample conversations (question/answer pairs)
|
|
18834
|
+
*/
|
|
18835
|
+
this.samples = [];
|
|
18202
18836
|
/**
|
|
18203
18837
|
* Metadata like image or color
|
|
18204
18838
|
*/
|
|
@@ -18208,12 +18842,13 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
18208
18842
|
this.agentSource = agentSource;
|
|
18209
18843
|
this.agentSource.subscribe((source) => {
|
|
18210
18844
|
this.updateAgentSource(source);
|
|
18211
|
-
const { agentName, personaDescription, initialMessage, links, meta, capabilities } = parseAgentSource(source);
|
|
18845
|
+
const { agentName, personaDescription, initialMessage, links, meta, capabilities, samples } = parseAgentSource(source);
|
|
18212
18846
|
this._agentName = agentName;
|
|
18213
18847
|
this.personaDescription = personaDescription;
|
|
18214
18848
|
this.initialMessage = initialMessage;
|
|
18215
18849
|
this.links = links;
|
|
18216
18850
|
this.capabilities = capabilities;
|
|
18851
|
+
this.samples = samples;
|
|
18217
18852
|
this.meta = { ...this.meta, ...meta };
|
|
18218
18853
|
});
|
|
18219
18854
|
}
|
|
@@ -18225,10 +18860,10 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
18225
18860
|
async callChatModelStream(prompt, onProgress) {
|
|
18226
18861
|
var _a;
|
|
18227
18862
|
// [1] Check if the user is asking the same thing as in the samples
|
|
18228
|
-
const modelRequirements = await this.
|
|
18863
|
+
const modelRequirements = await this.getModelRequirements();
|
|
18229
18864
|
if (modelRequirements.samples) {
|
|
18230
18865
|
const normalizedPrompt = normalizeMessageText(prompt.content);
|
|
18231
|
-
const sample = modelRequirements.samples.find((sample) => normalizeMessageText(sample.question) === normalizedPrompt);
|
|
18866
|
+
const sample = modelRequirements.samples.find((sample) => sample.question !== null && normalizeMessageText(sample.question) === normalizedPrompt);
|
|
18232
18867
|
if (sample) {
|
|
18233
18868
|
const now = new Date().toISOString();
|
|
18234
18869
|
const result = {
|
|
@@ -18274,17 +18909,22 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
18274
18909
|
if ((_a = modelRequirements.metadata) === null || _a === void 0 ? void 0 : _a.isClosed) {
|
|
18275
18910
|
return result;
|
|
18276
18911
|
}
|
|
18277
|
-
|
|
18278
|
-
//
|
|
18912
|
+
// TODO: !!!!! Is this timed properly?
|
|
18913
|
+
// Note: [1] Do the append of the samples
|
|
18914
|
+
__classPrivateFieldGet(this, _Agent_instances, "m", _Agent_selfLearnSamples).call(this, prompt, result);
|
|
18915
|
+
/*
|
|
18916
|
+
!!!!!
|
|
18917
|
+
// Note: [2] Asynchronously call the teacher agent and invoke the silver link. When the teacher fails, keep just the samples
|
|
18918
|
+
this.#selfLearnTeacher(prompt, result).catch((error) => {
|
|
18919
|
+
if (this.options.isVerbose) {
|
|
18920
|
+
console.error('Failed to self-learn from teacher agent', error);
|
|
18921
|
+
}
|
|
18922
|
+
});
|
|
18923
|
+
*/
|
|
18279
18924
|
return result;
|
|
18280
18925
|
}
|
|
18281
18926
|
}
|
|
18282
|
-
_Agent_instances = new WeakSet(),
|
|
18283
|
-
/**
|
|
18284
|
-
* Self-learning: Appends the conversation and extracted knowledge to the agent source
|
|
18285
|
-
*/
|
|
18286
|
-
async function _Agent_selfLearn(prompt, result) {
|
|
18287
|
-
// Learning: Append the conversation sample to the agent source
|
|
18927
|
+
_Agent_instances = new WeakSet(), _Agent_selfLearnSamples = function _Agent_selfLearnSamples(prompt, result) {
|
|
18288
18928
|
const learningExample = spaceTrim$2((block) => `
|
|
18289
18929
|
|
|
18290
18930
|
---
|
|
@@ -18296,52 +18936,9 @@ async function _Agent_selfLearn(prompt, result) {
|
|
|
18296
18936
|
${block(result.content)}
|
|
18297
18937
|
|
|
18298
18938
|
`);
|
|
18299
|
-
// Extract knowledge
|
|
18300
|
-
let knowledgeBlock = '';
|
|
18301
|
-
try {
|
|
18302
|
-
const extractionPrompt = {
|
|
18303
|
-
title: 'Knowledge Extraction',
|
|
18304
|
-
modelRequirements: {
|
|
18305
|
-
modelVariant: 'CHAT',
|
|
18306
|
-
},
|
|
18307
|
-
content: spaceTrim$2((block) => `
|
|
18308
|
-
You are an AI agent that is learning from a conversation.
|
|
18309
|
-
|
|
18310
|
-
Here is the conversation so far:
|
|
18311
|
-
|
|
18312
|
-
User: ${block(prompt.content)}
|
|
18313
|
-
Agent: ${block(result.content)}
|
|
18314
|
-
|
|
18315
|
-
Extract any new knowledge, facts, or important information that should be remembered for future interactions.
|
|
18316
|
-
Format the output as a list of KNOWLEDGE blocks.
|
|
18317
|
-
If there is no new knowledge, return nothing.
|
|
18318
|
-
|
|
18319
|
-
Example output:
|
|
18320
|
-
KNOWLEDGE The user's name is Alice.
|
|
18321
|
-
KNOWLEDGE The project deadline is next Friday.
|
|
18322
|
-
`),
|
|
18323
|
-
pipelineUrl: 'https://github.com/webgptorg/promptbook/blob/main/prompts/knowledge-extraction.ptbk.md',
|
|
18324
|
-
parameters: {},
|
|
18325
|
-
};
|
|
18326
|
-
if (this.options.llmTools.callChatModel) {
|
|
18327
|
-
const extractionResult = await this.options.llmTools.callChatModel(extractionPrompt);
|
|
18328
|
-
const extractedContent = extractionResult.content;
|
|
18329
|
-
if (extractedContent.includes('KNOWLEDGE')) {
|
|
18330
|
-
knowledgeBlock = '\n\n' + spaceTrim$2(extractedContent);
|
|
18331
|
-
}
|
|
18332
|
-
}
|
|
18333
|
-
else {
|
|
18334
|
-
// TODO: [🧠] Fallback to callChatModelStream if callChatModel is not available
|
|
18335
|
-
}
|
|
18336
|
-
}
|
|
18337
|
-
catch (error) {
|
|
18338
|
-
if (this.options.isVerbose) {
|
|
18339
|
-
console.warn('Failed to extract knowledge', error);
|
|
18340
|
-
}
|
|
18341
|
-
}
|
|
18342
18939
|
// Append to the current source
|
|
18343
18940
|
const currentSource = this.agentSource.value;
|
|
18344
|
-
const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample
|
|
18941
|
+
const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample));
|
|
18345
18942
|
// Update the source (which will trigger the subscription and update the underlying tools)
|
|
18346
18943
|
this.agentSource.next(newSource);
|
|
18347
18944
|
};
|