@promptbook/core 0.104.0-1 → 0.104.0-11

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.
Files changed (57) hide show
  1. package/esm/index.es.js +549 -163
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/servers.d.ts +8 -0
  4. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +16 -2
  6. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
  7. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
  8. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
  9. package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
  10. package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
  11. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  12. package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
  13. package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
  14. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
  15. package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
  16. package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
  17. package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
  18. package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
  19. package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
  20. package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
  21. package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
  22. package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
  23. package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
  24. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
  25. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
  26. package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
  27. package/esm/typings/src/commitments/index.d.ts +2 -1
  28. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
  29. package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
  30. package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
  31. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
  32. package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
  33. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
  34. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
  35. package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
  36. package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
  37. package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
  38. package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
  39. package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
  40. package/esm/typings/src/types/Message.d.ts +49 -0
  41. package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
  42. package/esm/typings/src/types/typeAliases.d.ts +23 -1
  43. package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
  44. package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
  45. package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
  46. package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
  47. package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
  48. package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
  49. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  50. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  51. package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
  52. package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
  53. package/esm/typings/src/version.d.ts +1 -1
  54. package/package.json +1 -1
  55. package/umd/index.umd.js +555 -168
  56. package/umd/index.umd.js.map +1 -1
  57. package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
package/esm/index.es.js CHANGED
@@ -27,7 +27,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
27
27
  * @generated
28
28
  * @see https://github.com/webgptorg/promptbook
29
29
  */
30
- const PROMPTBOOK_ENGINE_VERSION = '0.104.0-1';
30
+ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-11';
31
31
  /**
32
32
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
33
33
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -37,6 +37,8 @@ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-1';
37
37
  * Core Promptbook server configuration.
38
38
  *
39
39
  * This server is also used for auto-federation in the Agents Server.
40
+ *
41
+ * @public exported from `@promptbook/core`
40
42
  */
41
43
  const CORE_SERVER = {
42
44
  title: 'Promptbook Core',
@@ -3744,6 +3746,15 @@ function countUsage(llmTools) {
3744
3746
  return promptResult;
3745
3747
  };
3746
3748
  }
3749
+ if (llmTools.callImageGenerationModel !== undefined) {
3750
+ proxyTools.callImageGenerationModel = async (prompt) => {
3751
+ // console.info('[🚕] callImageGenerationModel through countTotalUsage');
3752
+ const promptResult = await llmTools.callImageGenerationModel(prompt);
3753
+ totalUsage = addUsage(totalUsage, promptResult.usage);
3754
+ spending.next(promptResult.usage);
3755
+ return promptResult;
3756
+ };
3757
+ }
3747
3758
  // <- Note: [🤖]
3748
3759
  return proxyTools;
3749
3760
  }
@@ -3752,7 +3763,7 @@ function countUsage(llmTools) {
3752
3763
  * TODO: [🧠] Is there some meaningfull way how to test this util
3753
3764
  * TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
3754
3765
  * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
3755
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
3766
+ * TODO: [👷‍♂️] Write a comprehensive manual explaining the construction and usage of LLM tools in the Promptbook ecosystem
3756
3767
  */
3757
3768
 
3758
3769
  /**
@@ -3853,6 +3864,12 @@ class MultipleLlmExecutionTools {
3853
3864
  callEmbeddingModel(prompt) {
3854
3865
  return this.callCommonModel(prompt);
3855
3866
  }
3867
+ /**
3868
+ * Calls the best available embedding model
3869
+ */
3870
+ callImageGenerationModel(prompt) {
3871
+ return this.callCommonModel(prompt);
3872
+ }
3856
3873
  // <- Note: [🤖]
3857
3874
  /**
3858
3875
  * Calls the best available model
@@ -3879,6 +3896,11 @@ class MultipleLlmExecutionTools {
3879
3896
  continue llm;
3880
3897
  }
3881
3898
  return await llmExecutionTools.callEmbeddingModel(prompt);
3899
+ case 'IMAGE_GENERATION':
3900
+ if (llmExecutionTools.callImageGenerationModel === undefined) {
3901
+ continue llm;
3902
+ }
3903
+ return await llmExecutionTools.callImageGenerationModel(prompt);
3882
3904
  // <- case [🤖]:
3883
3905
  default:
3884
3906
  throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
@@ -6304,8 +6326,9 @@ async function executeAttempts(options) {
6304
6326
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
6305
6327
  break variant;
6306
6328
  case 'EMBEDDING':
6329
+ case 'IMAGE_GENERATION':
6307
6330
  throw new PipelineExecutionError(spaceTrim$1((block) => `
6308
- Embedding model can not be used in pipeline
6331
+ ${modelRequirements.modelVariant} model can not be used in pipeline
6309
6332
 
6310
6333
  This should be catched during parsing
6311
6334
 
@@ -7964,6 +7987,114 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
7964
7987
  * Note: [💞] Ignore a discrepancy between file name and entity name
7965
7988
  */
7966
7989
 
7990
+ /**
7991
+ * DICTIONARY commitment definition
7992
+ *
7993
+ * The DICTIONARY commitment defines specific terms and their meanings that the agent should use correctly
7994
+ * in its reasoning and responses. This ensures consistent terminology usage.
7995
+ *
7996
+ * Key features:
7997
+ * - Multiple DICTIONARY commitments are automatically merged into one
7998
+ * - Content is placed in a dedicated section of the system message
7999
+ * - Terms and definitions are stored in metadata.DICTIONARY for debugging
8000
+ * - Agent should use the defined terms correctly in responses
8001
+ *
8002
+ * Example usage in agent source:
8003
+ *
8004
+ * ```book
8005
+ * Legal Assistant
8006
+ *
8007
+ * PERSONA You are a knowledgeable legal assistant
8008
+ * DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
8009
+ * DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
8010
+ * DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
8011
+ * ```
8012
+ *
8013
+ * @private [🪔] Maybe export the commitments through some package
8014
+ */
8015
+ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
8016
+ constructor() {
8017
+ super('DICTIONARY');
8018
+ }
8019
+ /**
8020
+ * Short one-line description of DICTIONARY.
8021
+ */
8022
+ get description() {
8023
+ return 'Define terms and their meanings for consistent terminology usage.';
8024
+ }
8025
+ /**
8026
+ * Icon for this commitment.
8027
+ */
8028
+ get icon() {
8029
+ return '📚';
8030
+ }
8031
+ /**
8032
+ * Markdown documentation for DICTIONARY commitment.
8033
+ */
8034
+ get documentation() {
8035
+ return spaceTrim$1(`
8036
+ # DICTIONARY
8037
+
8038
+ Defines specific terms and their meanings that the agent should use correctly in reasoning and responses.
8039
+
8040
+ ## Key aspects
8041
+
8042
+ - Multiple \`DICTIONARY\` commitments are merged together.
8043
+ - Terms are defined in the format: "Term is definition"
8044
+ - The agent should use these terms consistently in responses.
8045
+ - Definitions help ensure accurate and consistent terminology.
8046
+
8047
+ ## Examples
8048
+
8049
+ \`\`\`book
8050
+ Legal Assistant
8051
+
8052
+ PERSONA You are a knowledgeable legal assistant specializing in criminal law
8053
+ DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
8054
+ DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
8055
+ DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
8056
+ \`\`\`
8057
+
8058
+ \`\`\`book
8059
+ Medical Assistant
8060
+
8061
+ PERSONA You are a helpful medical assistant
8062
+ DICTIONARY Hypertension is persistently high blood pressure
8063
+ DICTIONARY Diabetes is a chronic condition that affects how the body processes blood sugar
8064
+ DICTIONARY Vaccine is a biological preparation that provides active immunity to a particular disease
8065
+ \`\`\`
8066
+ `);
8067
+ }
8068
+ applyToAgentModelRequirements(requirements, content) {
8069
+ var _a;
8070
+ const trimmedContent = content.trim();
8071
+ if (!trimmedContent) {
8072
+ return requirements;
8073
+ }
8074
+ // Get existing dictionary entries from metadata
8075
+ const existingDictionary = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
8076
+ // Merge the new dictionary entry with existing entries
8077
+ const mergedDictionary = existingDictionary
8078
+ ? `${existingDictionary}\n${trimmedContent}`
8079
+ : trimmedContent;
8080
+ // Store the merged dictionary in metadata for debugging and inspection
8081
+ const updatedMetadata = {
8082
+ ...requirements.metadata,
8083
+ DICTIONARY: mergedDictionary,
8084
+ };
8085
+ // Create the dictionary section for the system message
8086
+ // Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
8087
+ const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
8088
+ return {
8089
+ ...this.appendToSystemMessage(requirements, dictionarySection),
8090
+ metadata: updatedMetadata,
8091
+ };
8092
+ }
8093
+ }
8094
+ /**
8095
+ * Note: [💞] Ignore a discrepancy between file name and entity name
8096
+ */
8097
+
7967
8098
  /**
7968
8099
  * FORMAT commitment definition
7969
8100
  *
@@ -10784,6 +10915,7 @@ const COMMITMENT_REGISTRY = [
10784
10915
  new DeleteCommitmentDefinition('CANCEL'),
10785
10916
  new DeleteCommitmentDefinition('DISCARD'),
10786
10917
  new DeleteCommitmentDefinition('REMOVE'),
10918
+ new DictionaryCommitmentDefinition(),
10787
10919
  new OpenCommitmentDefinition(),
10788
10920
  new ClosedCommitmentDefinition(),
10789
10921
  new UseBrowserCommitmentDefinition(),
@@ -10935,17 +11067,64 @@ function parseAgentSourceWithCommitments(agentSource) {
10935
11067
  };
10936
11068
  }
10937
11069
  const lines = agentSource.split('\n');
10938
- const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
11070
+ let agentName = null;
11071
+ let agentNameLineIndex = -1;
11072
+ // Find the agent name: first non-empty line that is not a commitment and not a horizontal line
11073
+ for (let i = 0; i < lines.length; i++) {
11074
+ const line = lines[i];
11075
+ if (line === undefined) {
11076
+ continue;
11077
+ }
11078
+ const trimmed = line.trim();
11079
+ if (!trimmed) {
11080
+ continue;
11081
+ }
11082
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
11083
+ if (isHorizontal) {
11084
+ continue;
11085
+ }
11086
+ let isCommitment = false;
11087
+ for (const definition of COMMITMENT_REGISTRY) {
11088
+ const typeRegex = definition.createTypeRegex();
11089
+ const match = typeRegex.exec(trimmed);
11090
+ if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
11091
+ isCommitment = true;
11092
+ break;
11093
+ }
11094
+ }
11095
+ if (!isCommitment) {
11096
+ agentName = trimmed;
11097
+ agentNameLineIndex = i;
11098
+ break;
11099
+ }
11100
+ }
10939
11101
  const commitments = [];
10940
11102
  const nonCommitmentLines = [];
10941
- // Always add the first line (agent name) to non-commitment lines
10942
- if (lines[0] !== undefined) {
10943
- nonCommitmentLines.push(lines[0]);
11103
+ // Add lines before agentName that are horizontal lines (they are non-commitment)
11104
+ for (let i = 0; i < agentNameLineIndex; i++) {
11105
+ const line = lines[i];
11106
+ if (line === undefined) {
11107
+ continue;
11108
+ }
11109
+ const trimmed = line.trim();
11110
+ if (!trimmed) {
11111
+ continue;
11112
+ }
11113
+ const isHorizontal = HORIZONTAL_LINE_PATTERN.test(line);
11114
+ if (isHorizontal) {
11115
+ nonCommitmentLines.push(line);
11116
+ }
11117
+ // Note: Commitments before agentName are not added to nonCommitmentLines
11118
+ }
11119
+ // Add the agent name line to non-commitment lines
11120
+ if (agentNameLineIndex >= 0) {
11121
+ nonCommitmentLines.push(lines[agentNameLineIndex]);
10944
11122
  }
10945
11123
  // Parse commitments with multiline support
10946
11124
  let currentCommitment = null;
10947
- // Process lines starting from the second line (skip agent name)
10948
- for (let i = 1; i < lines.length; i++) {
11125
+ // Process lines starting from after the agent name line
11126
+ const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
11127
+ for (let i = startIndex; i < lines.length; i++) {
10949
11128
  const line = lines[i];
10950
11129
  if (line === undefined) {
10951
11130
  continue;
@@ -11165,7 +11344,12 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
11165
11344
  };
11166
11345
  }
11167
11346
  // Apply each commitment in order using reduce-like pattern
11168
- for (const commitment of filteredCommitments) {
11347
+ for (let i = 0; i < filteredCommitments.length; i++) {
11348
+ const commitment = filteredCommitments[i];
11349
+ // CLOSED commitment should work only if its the last commitment in the book
11350
+ if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
11351
+ continue;
11352
+ }
11169
11353
  const definition = getCommitmentDefinition(commitment.type);
11170
11354
  if (definition) {
11171
11355
  try {
@@ -11260,44 +11444,6 @@ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
11260
11444
  * TODO: [🌺] Use some intermediate util splitWords
11261
11445
  */
11262
11446
 
11263
- /**
11264
- * Generates a gravatar URL based on agent name for fallback avatar
11265
- *
11266
- * @param agentName The agent name to generate avatar for
11267
- * @returns Gravatar URL
11268
- *
11269
- * @private - [🤹] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
11270
- */
11271
- function generateGravatarUrl(agentName) {
11272
- // Use a default name if none provided
11273
- const safeName = agentName || 'Anonymous Agent';
11274
- // Create a simple hash from the name for consistent avatar
11275
- let hash = 0;
11276
- for (let i = 0; i < safeName.length; i++) {
11277
- const char = safeName.charCodeAt(i);
11278
- hash = (hash << 5) - hash + char;
11279
- hash = hash & hash; // Convert to 32bit integer
11280
- }
11281
- const avatarId = Math.abs(hash).toString();
11282
- return `https://www.gravatar.com/avatar/${avatarId}?default=robohash&size=200&rating=x`;
11283
- }
11284
-
11285
- /**
11286
- * Generates an image for the agent to use as profile image
11287
- *
11288
- * @param agentName The agent name to generate avatar for
11289
- * @returns The placeholder profile image URL for the agent
11290
- *
11291
- * @public exported from `@promptbook/core`
11292
- */
11293
- function generatePlaceholderAgentProfileImageUrl(agentName) {
11294
- // Note: [🤹] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
11295
- return generateGravatarUrl(agentName);
11296
- }
11297
- /**
11298
- * TODO: [🤹] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
11299
- */
11300
-
11301
11447
  /**
11302
11448
  * Creates a Mermaid graph based on the promptbook
11303
11449
  *
@@ -11468,13 +11614,14 @@ function prompt(strings, ...values) {
11468
11614
  *
11469
11615
  * @public exported from `@promptbook/utils`
11470
11616
  */
11471
- const $isRunningInBrowser = new Function(`
11617
+ function $isRunningInBrowser() {
11472
11618
  try {
11473
- return this === window;
11474
- } catch (e) {
11619
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
11620
+ }
11621
+ catch (e) {
11475
11622
  return false;
11476
11623
  }
11477
- `);
11624
+ }
11478
11625
  /**
11479
11626
  * TODO: [🎺]
11480
11627
  */
@@ -11486,13 +11633,15 @@ const $isRunningInBrowser = new Function(`
11486
11633
  *
11487
11634
  * @public exported from `@promptbook/utils`
11488
11635
  */
11489
- const $isRunningInJest = new Function(`
11636
+ function $isRunningInJest() {
11637
+ var _a;
11490
11638
  try {
11491
- return process.env.JEST_WORKER_ID !== undefined;
11492
- } catch (e) {
11639
+ return typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.JEST_WORKER_ID) !== undefined;
11640
+ }
11641
+ catch (e) {
11493
11642
  return false;
11494
11643
  }
11495
- `);
11644
+ }
11496
11645
  /**
11497
11646
  * TODO: [🎺]
11498
11647
  */
@@ -11504,13 +11653,14 @@ const $isRunningInJest = new Function(`
11504
11653
  *
11505
11654
  * @public exported from `@promptbook/utils`
11506
11655
  */
11507
- const $isRunningInNode = new Function(`
11656
+ function $isRunningInNode() {
11508
11657
  try {
11509
- return this === global;
11510
- } catch (e) {
11658
+ return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
11659
+ }
11660
+ catch (e) {
11511
11661
  return false;
11512
11662
  }
11513
- `);
11663
+ }
11514
11664
  /**
11515
11665
  * TODO: [🎺]
11516
11666
  */
@@ -11522,17 +11672,17 @@ const $isRunningInNode = new Function(`
11522
11672
  *
11523
11673
  * @public exported from `@promptbook/utils`
11524
11674
  */
11525
- const $isRunningInWebWorker = new Function(`
11675
+ function $isRunningInWebWorker() {
11526
11676
  try {
11527
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
11528
- return true;
11529
- } else {
11530
- return false;
11531
- }
11532
- } catch (e) {
11677
+ // Note: Check for importScripts which is specific to workers
11678
+ // and not available in the main browser thread
11679
+ return (typeof self !== 'undefined' &&
11680
+ typeof self.importScripts === 'function');
11681
+ }
11682
+ catch (e) {
11533
11683
  return false;
11534
11684
  }
11535
- `);
11685
+ }
11536
11686
  /**
11537
11687
  * TODO: [🎺]
11538
11688
  */
@@ -11745,7 +11895,57 @@ function parseAgentSource(agentSource) {
11745
11895
  }
11746
11896
  const meta = {};
11747
11897
  const links = [];
11898
+ const capabilities = [];
11748
11899
  for (const commitment of parseResult.commitments) {
11900
+ if (commitment.type === 'USE BROWSER') {
11901
+ capabilities.push({
11902
+ type: 'browser',
11903
+ label: 'Browser',
11904
+ iconName: 'Globe',
11905
+ });
11906
+ continue;
11907
+ }
11908
+ if (commitment.type === 'USE SEARCH ENGINE') {
11909
+ capabilities.push({
11910
+ type: 'search-engine',
11911
+ label: 'Search Internet',
11912
+ iconName: 'Search',
11913
+ });
11914
+ continue;
11915
+ }
11916
+ if (commitment.type === 'KNOWLEDGE') {
11917
+ const content = spaceTrim$2(commitment.content).split('\n')[0] || '';
11918
+ let label = content;
11919
+ let iconName = 'Book';
11920
+ if (content.startsWith('http://') || content.startsWith('https://')) {
11921
+ try {
11922
+ const url = new URL(content);
11923
+ if (url.pathname.endsWith('.pdf')) {
11924
+ label = url.pathname.split('/').pop() || 'Document.pdf';
11925
+ iconName = 'FileText';
11926
+ }
11927
+ else {
11928
+ label = url.hostname.replace(/^www\./, '');
11929
+ }
11930
+ }
11931
+ catch (e) {
11932
+ // Invalid URL, treat as text
11933
+ }
11934
+ }
11935
+ else {
11936
+ // Text content - take first few words
11937
+ const words = content.split(/\s+/);
11938
+ if (words.length > 4) {
11939
+ label = words.slice(0, 4).join(' ') + '...';
11940
+ }
11941
+ }
11942
+ capabilities.push({
11943
+ type: 'knowledge',
11944
+ label,
11945
+ iconName,
11946
+ });
11947
+ continue;
11948
+ }
11749
11949
  if (commitment.type === 'META LINK') {
11750
11950
  const linkValue = spaceTrim$2(commitment.content);
11751
11951
  links.push(linkValue);
@@ -11775,10 +11975,6 @@ function parseAgentSource(agentSource) {
11775
11975
  const metaType = normalizeTo_camelCase(metaTypeRaw);
11776
11976
  meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
11777
11977
  }
11778
- // Generate gravatar fallback if no meta image specified
11779
- if (!meta.image) {
11780
- meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
11781
- }
11782
11978
  // Generate fullname fallback if no meta fullname specified
11783
11979
  if (!meta.fullname) {
11784
11980
  meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
@@ -11790,11 +11986,13 @@ function parseAgentSource(agentSource) {
11790
11986
  return {
11791
11987
  agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
11792
11988
  agentHash,
11989
+ permanentId: meta.id,
11793
11990
  personaDescription,
11794
11991
  initialMessage,
11795
11992
  meta,
11796
11993
  links,
11797
11994
  parameters,
11995
+ capabilities,
11798
11996
  };
11799
11997
  }
11800
11998
  /**
@@ -11981,6 +12179,59 @@ const DEFAULT_BOOK = padBook(validateBook(spaceTrim$2(`
11981
12179
  // <- [🐱‍🚀] Buttons into genesis book
11982
12180
  // <- TODO: [🐱‍🚀] generateBookBoilerplate and deprecate `DEFAULT_BOOK`
11983
12181
 
12182
+ /**
12183
+ * Generates an image for the agent to use as profile image
12184
+ *
12185
+ * @param agentId - The permanent ID of the agent
12186
+ * @returns The placeholder profile image URL for the agent
12187
+ *
12188
+ * @public exported from `@promptbook/core`
12189
+ */
12190
+ function generatePlaceholderAgentProfileImageUrl(agentIdOrName, agentsServerUrl = CORE_SERVER.urls[0]) {
12191
+ if (typeof agentsServerUrl === 'string') {
12192
+ agentsServerUrl = new URL(agentsServerUrl);
12193
+ }
12194
+ return `${agentsServerUrl.href}agents/${agentIdOrName}/images/default-avatar.png`;
12195
+ }
12196
+ /**
12197
+ * TODO: [🤹] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
12198
+ */
12199
+
12200
+ /**
12201
+ * Base58 characters
12202
+ */
12203
+ const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
12204
+ /**
12205
+ * Generates random base58 string
12206
+ *
12207
+ * Note: `$` is used to indicate that this function is not a pure function - it is not deterministic
12208
+ * Note: This function is cryptographically secure (it uses crypto.randomBytes internally)
12209
+ *
12210
+ * @param length - length of the string
12211
+ * @returns secure random base58 string
12212
+ *
12213
+ * @private internal helper function
12214
+ */
12215
+ function $randomBase58(length) {
12216
+ let result = '';
12217
+ while (result.length < length) {
12218
+ // Generate enough bytes to cover the remaining length, plus some extra buffer to reduce calls
12219
+ // But simply generating `length - result.length` is fine for small lengths
12220
+ const bytes = randomBytes(length - result.length);
12221
+ for (let i = 0; i < bytes.length; i++) {
12222
+ const byte = bytes[i];
12223
+ // 58 * 4 = 232
12224
+ // We discard values >= 232 to avoid modulo bias
12225
+ if (byte < 232) {
12226
+ result += BASE58_ALPHABET[byte % 58];
12227
+ if (result.length === length)
12228
+ break;
12229
+ }
12230
+ }
12231
+ }
12232
+ return result;
12233
+ }
12234
+
11984
12235
  // import { getTableName } from '../../../../../apps/agents-server/src/database/getTableName';
11985
12236
  // <- TODO: [🐱‍🚀] Prevent imports from `/apps` -> `/src`
11986
12237
  /**
@@ -12014,19 +12265,20 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12014
12265
  const { isVerbose = DEFAULT_IS_VERBOSE } = this.options || {};
12015
12266
  const selectResult = await this.supabaseClient
12016
12267
  .from(this.getTableName('Agent'))
12017
- .select('agentName,agentProfile');
12268
+ .select('agentName,agentProfile,permanentId')
12269
+ .is('deletedAt', null);
12018
12270
  if (selectResult.error) {
12019
12271
  throw new DatabaseError(spaceTrim((block) => `
12020
-
12272
+
12021
12273
  Error fetching agents from Supabase:
12022
-
12274
+
12023
12275
  ${block(selectResult.error.message)}
12024
12276
  `));
12025
12277
  }
12026
12278
  if (isVerbose) {
12027
12279
  console.info(`Found ${selectResult.data.length} agents in directory`);
12028
12280
  }
12029
- return selectResult.data.map(({ agentName, agentProfile }) => {
12281
+ return selectResult.data.map(({ agentName, agentProfile, permanentId }) => {
12030
12282
  if (isVerbose && agentProfile.agentName !== agentName) {
12031
12283
  console.warn(spaceTrim(`
12032
12284
  Agent name mismatch for agent "${agentName}". Using name from database.
@@ -12038,26 +12290,42 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12038
12290
  return {
12039
12291
  ...agentProfile,
12040
12292
  agentName,
12293
+ permanentId: permanentId || agentProfile.permanentId,
12041
12294
  };
12042
12295
  });
12043
12296
  }
12044
12297
  /**
12045
- * [🐱‍🚀]@@@
12298
+ * Retrieves the permanent ID of an agent by its name or permanent ID.
12046
12299
  */
12047
- async getAgentSource(agentName) {
12300
+ async getAgentPermanentId(agentNameOrPermanentId) {
12301
+ const selectResult = await this.supabaseClient
12302
+ .from(this.getTableName('Agent'))
12303
+ .select('permanentId')
12304
+ .or(`agentName.eq.${agentNameOrPermanentId},permanentId.eq.${agentNameOrPermanentId}`)
12305
+ .single();
12306
+ if (selectResult.error || !selectResult.data) {
12307
+ throw new NotFoundError(`Agent with name not id "${agentNameOrPermanentId}" not found`);
12308
+ }
12309
+ return selectResult.data.permanentId;
12310
+ }
12311
+ /**
12312
+ * Retrieves the source code of an agent by its name or permanent ID.
12313
+ */
12314
+ async getAgentSource(agentNameOrPermanentId) {
12048
12315
  const selectResult = await this.supabaseClient
12049
12316
  .from(this.getTableName('Agent'))
12050
12317
  .select('agentSource')
12051
- .eq('agentName', agentName);
12318
+ .or(`agentName.eq.${agentNameOrPermanentId},permanentId.eq.${agentNameOrPermanentId}`)
12319
+ .is('deletedAt', null);
12052
12320
  if (selectResult.data && selectResult.data.length === 0) {
12053
- throw new NotFoundError(`Agent "${agentName}" not found`);
12321
+ throw new NotFoundError(`Agent "${agentNameOrPermanentId}" not found`);
12054
12322
  }
12055
12323
  else if (selectResult.data && selectResult.data.length > 1) {
12056
- throw new UnexpectedError(`More agents with agentName="${agentName}" found`);
12324
+ throw new UnexpectedError(`More agents with name or id "${agentNameOrPermanentId}" found`);
12057
12325
  }
12058
12326
  else if (selectResult.error) {
12059
12327
  throw new DatabaseError(spaceTrim((block) => `
12060
- Error fetching agent "${agentName}" from Supabase:
12328
+ Error fetching agent "${agentNameOrPermanentId}" from Supabase:
12061
12329
 
12062
12330
  ${block(selectResult.error.message)}
12063
12331
  `));
@@ -12070,12 +12338,26 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12070
12338
  * Note: You can set 'PARENT' in the agent source to inherit from another agent in the collection.
12071
12339
  */
12072
12340
  async createAgent(agentSource) {
12073
- const agentProfile = parseAgentSource(agentSource);
12341
+ let agentProfile = parseAgentSource(agentSource);
12074
12342
  // <- TODO: [🕛]
12343
+ // 1. Extract permanentId from the source if present
12344
+ let { permanentId } = agentProfile;
12345
+ // 2. Remove META ID from the source
12346
+ const lines = agentSource.split('\n');
12347
+ const strippedLines = lines.filter((line) => !line.trim().startsWith('META ID '));
12348
+ if (lines.length !== strippedLines.length) {
12349
+ agentSource = strippedLines.join('\n');
12350
+ // 3. Re-parse the agent source to get the correct hash and other info
12351
+ agentProfile = parseAgentSource(agentSource);
12352
+ }
12075
12353
  const { agentName, agentHash } = agentProfile;
12354
+ if (!permanentId) {
12355
+ permanentId = $randomBase58(14);
12356
+ }
12076
12357
  const insertAgentResult = await this.supabaseClient.from(this.getTableName('Agent')).insert({
12077
12358
  agentName,
12078
12359
  agentHash,
12360
+ permanentId,
12079
12361
  agentProfile,
12080
12362
  createdAt: new Date().toISOString(),
12081
12363
  updatedAt: null,
@@ -12093,27 +12375,29 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12093
12375
  await this.supabaseClient.from(this.getTableName('AgentHistory')).insert({
12094
12376
  createdAt: new Date().toISOString(),
12095
12377
  agentName,
12378
+ permanentId,
12096
12379
  agentHash,
12097
12380
  previousAgentHash: null,
12098
12381
  agentSource,
12099
12382
  promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
12100
12383
  });
12101
12384
  // <- TODO: [🧠] What to do with `insertAgentHistoryResult.error`, ignore? wait?
12102
- return agentProfile;
12385
+ return { ...agentProfile, permanentId };
12103
12386
  }
12104
12387
  /**
12105
12388
  * Updates an existing agent in the collection
12106
12389
  */
12107
- async updateAgentSource(agentName, agentSource) {
12390
+ async updateAgentSource(permanentId, agentSource) {
12391
+ console.log('!!! updateAgentSource', { permanentId });
12108
12392
  const selectPreviousAgentResult = await this.supabaseClient
12109
12393
  .from(this.getTableName('Agent'))
12110
- .select('agentHash,agentName')
12111
- .eq('agentName', agentName)
12394
+ .select('agentHash,agentName,permanentId')
12395
+ .eq('permanentId', permanentId)
12112
12396
  .single();
12113
12397
  if (selectPreviousAgentResult.error) {
12114
12398
  throw new DatabaseError(spaceTrim((block) => `
12115
12399
 
12116
- Error fetching agent "${agentName}" from Supabase:
12400
+ Error fetching agent "${permanentId}" from Supabase:
12117
12401
 
12118
12402
  ${block(selectPreviousAgentResult.error.message)}
12119
12403
  `));
@@ -12121,26 +12405,48 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12121
12405
  }
12122
12406
  selectPreviousAgentResult.data.agentName;
12123
12407
  const previousAgentHash = selectPreviousAgentResult.data.agentHash;
12124
- const agentProfile = parseAgentSource(agentSource);
12408
+ const previousPermanentId = selectPreviousAgentResult.data.permanentId;
12409
+ let agentProfile = parseAgentSource(agentSource);
12125
12410
  // <- TODO: [🕛]
12126
- const { agentHash } = agentProfile;
12411
+ // 1. Extract permanentId from the source if present
12412
+ let { permanentId: newPermanentId } = agentProfile;
12413
+ // 2. Remove META ID from the source
12414
+ const lines = agentSource.split('\n');
12415
+ const strippedLines = lines.filter((line) => !line.trim().startsWith('META ID '));
12416
+ if (lines.length !== strippedLines.length) {
12417
+ agentSource = strippedLines.join('\n');
12418
+ // 3. Re-parse the agent source to get the correct hash and other info
12419
+ agentProfile = parseAgentSource(agentSource);
12420
+ }
12421
+ const { agentHash, agentName } = agentProfile;
12422
+ if (!newPermanentId && previousPermanentId) {
12423
+ newPermanentId = previousPermanentId;
12424
+ }
12425
+ if (!newPermanentId) {
12426
+ newPermanentId = $randomBase58(14);
12427
+ }
12428
+ if (newPermanentId !== permanentId) {
12429
+ // [🧠] Should be allowed to change permanentId?
12430
+ throw new UnexpectedError(`Permanent ID mismatch: "${permanentId}" (argument) !== "${newPermanentId}" (in source)`);
12431
+ }
12127
12432
  const updateAgentResult = await this.supabaseClient
12128
12433
  .from(this.getTableName('Agent'))
12129
12434
  .update({
12130
12435
  // TODO: [🐱‍🚀] Compare not update> agentName: agentProfile.agentName || '[🐱‍🚀]' /* <- TODO: [🐱‍🚀] Remove */,
12436
+ permanentId,
12131
12437
  agentProfile,
12132
12438
  updatedAt: new Date().toISOString(),
12133
12439
  agentHash: agentProfile.agentHash,
12134
12440
  agentSource,
12135
12441
  promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
12136
12442
  })
12137
- .eq('agentName', agentName);
12443
+ .eq('permanentId', permanentId);
12138
12444
  // console.log('[🐱‍🚀] updateAgent', updateResult);
12139
12445
  // console.log('[🐱‍🚀] old', oldAgentSource);
12140
12446
  // console.log('[🐱‍🚀] new', newAgentSource);
12141
12447
  if (updateAgentResult.error) {
12142
12448
  throw new DatabaseError(spaceTrim((block) => `
12143
- Error updating agent "${agentName}" in Supabase:
12449
+ Error updating agent "${permanentId}" in Supabase:
12144
12450
 
12145
12451
  ${block(updateAgentResult.error.message)}
12146
12452
  `));
@@ -12148,6 +12454,7 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12148
12454
  await this.supabaseClient.from(this.getTableName('AgentHistory')).insert({
12149
12455
  createdAt: new Date().toISOString(),
12150
12456
  agentName,
12457
+ permanentId,
12151
12458
  agentHash,
12152
12459
  previousAgentHash,
12153
12460
  agentSource,
@@ -12155,101 +12462,119 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12155
12462
  });
12156
12463
  // <- TODO: [🧠] What to do with `insertAgentHistoryResult.error`, ignore? wait?
12157
12464
  }
12158
- // TODO: [🐱‍🚀] public async getAgentSourceSubject(agentName: string_agent_name): Promise<BehaviorSubject<string_book>>
12465
+ // TODO: [🐱‍🚀] public async getAgentSourceSubject(permanentId: string_agent_permanent_id): Promise<BehaviorSubject<string_book>>
12159
12466
  // Use Supabase realtime logic
12160
12467
  /**
12161
- * Deletes an agent from the collection
12468
+ * List agents that are soft deleted (deletedAt IS NOT NULL)
12162
12469
  */
12163
- async deleteAgent(agentName) {
12164
- const deleteResult = await this.supabaseClient
12470
+ async listDeletedAgents() {
12471
+ const { isVerbose = DEFAULT_IS_VERBOSE } = this.options || {};
12472
+ const selectResult = await this.supabaseClient
12165
12473
  .from(this.getTableName('Agent'))
12166
- .delete()
12167
- .eq('agentName', agentName);
12168
- if (deleteResult.error) {
12474
+ .select('agentName,agentProfile,permanentId')
12475
+ .not('deletedAt', 'is', null);
12476
+ if (selectResult.error) {
12169
12477
  throw new DatabaseError(spaceTrim((block) => `
12170
- Error deleting agent "${agentName}" from Supabase:
12171
-
12172
- ${block(deleteResult.error.message)}
12173
- `));
12478
+ Error fetching deleted agents from Supabase:
12479
+
12480
+ ${block(selectResult.error.message)}
12481
+ `));
12174
12482
  }
12483
+ if (isVerbose) {
12484
+ console.info(`Found ${selectResult.data.length} deleted agents in directory`);
12485
+ }
12486
+ return selectResult.data.map(({ agentName, agentProfile, permanentId }) => {
12487
+ if (isVerbose && agentProfile.agentName !== agentName) {
12488
+ console.warn(spaceTrim(`
12489
+ Agent name mismatch for agent "${agentName}". Using name from database.
12490
+
12491
+ agentName: "${agentName}"
12492
+ agentProfile.agentName: "${agentProfile.agentName}"
12493
+ `));
12494
+ }
12495
+ return {
12496
+ ...agentProfile,
12497
+ agentName,
12498
+ permanentId: permanentId || agentProfile.permanentId,
12499
+ };
12500
+ });
12175
12501
  }
12176
12502
  /**
12177
12503
  * List history of an agent
12178
12504
  */
12179
- async listAgentHistory(agentName) {
12505
+ async listAgentHistory(permanentId) {
12180
12506
  const result = await this.supabaseClient
12181
12507
  .from(this.getTableName('AgentHistory'))
12182
12508
  .select('id, createdAt, agentHash, promptbookEngineVersion')
12183
- .eq('agentName', agentName)
12509
+ .eq('permanentId', permanentId)
12184
12510
  .order('createdAt', { ascending: false });
12185
12511
  if (result.error) {
12186
12512
  throw new DatabaseError(spaceTrim((block) => `
12187
- Error listing history for agent "${agentName}" from Supabase:
12188
-
12513
+ Error listing history for agent "${permanentId}" from Supabase:
12514
+
12189
12515
  ${block(result.error.message)}
12190
12516
  `));
12191
12517
  }
12192
12518
  return result.data;
12193
12519
  }
12194
12520
  /**
12195
- * List agents that are in history but not in the active agents list
12521
+ * Restore a soft-deleted agent by setting deletedAt to NULL
12196
12522
  */
12197
- async listDeletedAgents() {
12198
- const historyNamesResult = await this.supabaseClient.from(this.getTableName('AgentHistory')).select('agentName');
12199
- const currentNamesResult = await this.supabaseClient.from(this.getTableName('Agent')).select('agentName');
12200
- if (historyNamesResult.error) {
12201
- throw new DatabaseError(spaceTrim((block) => `
12202
- Error fetching agent history names from Supabase:
12203
-
12204
- ${block(historyNamesResult.error.message)}
12205
- `));
12206
- }
12207
- if (currentNamesResult.error) {
12523
+ async restoreAgent(permanentId) {
12524
+ const updateResult = await this.supabaseClient
12525
+ .from(this.getTableName('Agent'))
12526
+ .update({ deletedAt: null })
12527
+ .eq('permanentId', permanentId)
12528
+ .not('deletedAt', 'is', null);
12529
+ if (updateResult.error) {
12208
12530
  throw new DatabaseError(spaceTrim((block) => `
12209
- Error fetching current agent names from Supabase:
12210
-
12211
- ${block(currentNamesResult.error.message)}
12531
+ Error restoring agent "${permanentId}" from Supabase:
12532
+
12533
+ ${block(updateResult.error.message)}
12212
12534
  `));
12213
12535
  }
12214
- const currentNames = new Set(currentNamesResult.data.map((d) => d.agentName));
12215
- const deletedNames = new Set();
12216
- for (const { agentName } of historyNamesResult.data) {
12217
- if (!currentNames.has(agentName)) {
12218
- deletedNames.add(agentName);
12219
- }
12220
- }
12221
- return Array.from(deletedNames);
12222
12536
  }
12223
12537
  /**
12224
- * Restore an agent from history
12538
+ * Restore an agent from a specific history entry
12539
+ *
12540
+ * This will update the current agent with the source from the history entry
12225
12541
  */
12226
- async restoreAgent(historyId) {
12542
+ async restoreAgentFromHistory(historyId) {
12543
+ // First, get the history entry
12227
12544
  const historyResult = await this.supabaseClient
12228
12545
  .from(this.getTableName('AgentHistory'))
12229
- .select('*')
12546
+ .select('permanentId, agentSource')
12230
12547
  .eq('id', historyId)
12231
12548
  .single();
12232
12549
  if (historyResult.error) {
12233
12550
  throw new DatabaseError(spaceTrim((block) => `
12234
- Error fetching agent history item "${historyId}" from Supabase:
12235
-
12551
+ Error fetching history entry with id "${historyId}" from Supabase:
12552
+
12236
12553
  ${block(historyResult.error.message)}
12237
12554
  `));
12238
12555
  }
12239
- const { agentName, agentSource } = historyResult.data;
12240
- // Check if agent exists
12241
- const agentResult = await this.supabaseClient
12242
- .from(this.getTableName('Agent'))
12243
- .select('id')
12244
- .eq('agentName', agentName)
12245
- .single();
12246
- if (agentResult.data) {
12247
- // Update
12248
- await this.updateAgentSource(agentName, agentSource);
12556
+ if (!historyResult.data) {
12557
+ throw new NotFoundError(`History entry with id "${historyId}" not found`);
12249
12558
  }
12250
- else {
12251
- // Insert (Restore from deleted)
12252
- await this.createAgent(agentSource);
12559
+ const { permanentId, agentSource } = historyResult.data;
12560
+ // Update the agent with the source from the history entry
12561
+ await this.updateAgentSource(permanentId, agentSource);
12562
+ }
12563
+ /**
12564
+ * Soft delete an agent by setting deletedAt to current timestamp
12565
+ */
12566
+ async deleteAgent(permanentId) {
12567
+ const updateResult = await this.supabaseClient
12568
+ .from(this.getTableName('Agent'))
12569
+ .update({ deletedAt: new Date().toISOString() })
12570
+ .eq('permanentId', permanentId)
12571
+ .is('deletedAt', null);
12572
+ if (updateResult.error) {
12573
+ throw new DatabaseError(spaceTrim((block) => `
12574
+ Error deleting agent "${permanentId}" from Supabase:
12575
+
12576
+ ${block(updateResult.error.message)}
12577
+ `));
12253
12578
  }
12254
12579
  }
12255
12580
  /**
@@ -12261,6 +12586,7 @@ class AgentCollectionInSupabase /* TODO: [🐱‍🚀] implements Agent */ {
12261
12586
  getTableName(tableName) {
12262
12587
  const { tablePrefix = '' } = this.options || {};
12263
12588
  return `${tablePrefix}${tableName}`;
12589
+ // <- TODO: [🏧] DRY
12264
12590
  }
12265
12591
  }
12266
12592
  /**
@@ -13939,11 +14265,7 @@ const modelCommandParser = {
13939
14265
  // TODO: [🚜] DRY
13940
14266
  if ($taskJson.modelRequirements[command.key] !== undefined) {
13941
14267
  if ($taskJson.modelRequirements[command.key] === command.value) {
13942
- console.warn(`Multiple commands \`MODEL ${{
13943
- modelName: 'NAME',
13944
- modelVariant: 'VARIANT',
13945
- maxTokens: '???',
13946
- }[command.key]} ${command.value}\` in the task "${$taskJson.title || $taskJson.name}"`);
14268
+ console.warn(`Multiple commands \`MODEL ${command.key} ${command.value}\` in the task "${$taskJson.title || $taskJson.name}"`);
13947
14269
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
13948
14270
  }
13949
14271
  else {
@@ -16467,7 +16789,7 @@ function $registeredLlmToolsMessage() {
16467
16789
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
16468
16790
  ${morePieces.join('; ')}
16469
16791
  `);
16470
- if ($isRunningInNode) {
16792
+ if ($isRunningInNode()) {
16471
16793
  if (isInstalled && isFullyConfigured) {
16472
16794
  providerMessage = colors.green(providerMessage);
16473
16795
  }
@@ -16672,6 +16994,9 @@ function cacheLlmTools(llmTools, options = {}) {
16672
16994
  case 'EMBEDDING':
16673
16995
  promptResult = await llmTools.callEmbeddingModel(prompt);
16674
16996
  break variant;
16997
+ case 'IMAGE_GENERATION':
16998
+ promptResult = await llmTools.callImageGenerationModel(prompt);
16999
+ break variant;
16675
17000
  // <- case [🤖]:
16676
17001
  default:
16677
17002
  throw new PipelineExecutionError(`Unknown model variant "${prompt.modelRequirements.modelVariant}"`);
@@ -16708,12 +17033,13 @@ function cacheLlmTools(llmTools, options = {}) {
16708
17033
  }
16709
17034
  }
16710
17035
  catch (error) {
17036
+ assertsError(error);
16711
17037
  // If validation throws an unexpected error, don't cache
16712
17038
  shouldCache = false;
16713
17039
  if (isVerbose) {
16714
17040
  console.info('Not caching result due to validation error for key:', key, {
16715
17041
  content: promptResult.content,
16716
- validationError: error instanceof Error ? error.message : String(error),
17042
+ validationError: serializeError(error),
16717
17043
  });
16718
17044
  }
16719
17045
  }
@@ -16759,6 +17085,11 @@ function cacheLlmTools(llmTools, options = {}) {
16759
17085
  return /* not await */ callCommonModel(prompt);
16760
17086
  };
16761
17087
  }
17088
+ if (llmTools.callImageGenerationModel !== undefined) {
17089
+ proxyTools.callImageGenerationModel = async (prompt) => {
17090
+ return /* not await */ callCommonModel(prompt);
17091
+ };
17092
+ }
16762
17093
  // <- Note: [🤖]
16763
17094
  return proxyTools;
16764
17095
  }
@@ -16797,6 +17128,11 @@ function limitTotalUsage(llmTools, options = {}) {
16797
17128
  throw new LimitReachedError('Cannot call `callEmbeddingModel` because you are not allowed to spend any cost');
16798
17129
  };
16799
17130
  }
17131
+ if (proxyTools.callImageGenerationModel !== undefined) {
17132
+ proxyTools.callImageGenerationModel = async (prompt) => {
17133
+ throw new LimitReachedError('Cannot call `callImageGenerationModel` because you are not allowed to spend any cost');
17134
+ };
17135
+ }
16800
17136
  // <- Note: [🤖]
16801
17137
  return proxyTools;
16802
17138
  }
@@ -17868,7 +18204,7 @@ class OpenAiCompatibleExecutionTools {
17868
18204
  let threadMessages = [];
17869
18205
  if ('thread' in prompt && Array.isArray(prompt.thread)) {
17870
18206
  threadMessages = prompt.thread.map((msg) => ({
17871
- role: msg.role === 'assistant' ? 'assistant' : 'user',
18207
+ role: msg.sender === 'assistant' ? 'assistant' : 'user',
17872
18208
  content: msg.content,
17873
18209
  }));
17874
18210
  }
@@ -18281,13 +18617,14 @@ class OpenAiCompatibleExecutionTools {
18281
18617
  const modelName = currentModelRequirements.modelName || this.getDefaultImageGenerationModel().modelName;
18282
18618
  const modelSettings = {
18283
18619
  model: modelName,
18284
- // size: currentModelRequirements.size,
18285
- // quality: currentModelRequirements.quality,
18286
- // style: currentModelRequirements.style,
18620
+ size: currentModelRequirements.size,
18621
+ quality: currentModelRequirements.quality,
18622
+ style: currentModelRequirements.style,
18287
18623
  };
18288
18624
  const rawPromptContent = templateParameters(content, { ...parameters, modelName });
18289
18625
  const rawRequest = {
18290
18626
  ...modelSettings,
18627
+ size: modelSettings.size || '1024x1024',
18291
18628
  prompt: rawPromptContent,
18292
18629
  user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
18293
18630
  response_format: 'url', // TODO: [🧠] Maybe allow b64_json
@@ -19306,6 +19643,11 @@ class Agent extends AgentLlmExecutionTools {
19306
19643
  * Links found in the agent source
19307
19644
  */
19308
19645
  this.links = [];
19646
+ /**
19647
+ * Capabilities of the agent
19648
+ * This is parsed from commitments like USE BROWSER, USE SEARCH ENGINE, KNOWLEDGE, etc.
19649
+ */
19650
+ this.capabilities = [];
19309
19651
  /**
19310
19652
  * Metadata like image or color
19311
19653
  */
@@ -19315,11 +19657,12 @@ class Agent extends AgentLlmExecutionTools {
19315
19657
  this.agentSource = agentSource;
19316
19658
  this.agentSource.subscribe((source) => {
19317
19659
  this.updateAgentSource(source);
19318
- const { agentName, personaDescription, initialMessage, links, meta } = parseAgentSource(source);
19660
+ const { agentName, personaDescription, initialMessage, links, meta, capabilities } = parseAgentSource(source);
19319
19661
  this._agentName = agentName;
19320
19662
  this.personaDescription = personaDescription;
19321
19663
  this.initialMessage = initialMessage;
19322
19664
  this.links = links;
19665
+ this.capabilities = capabilities;
19323
19666
  this.meta = { ...this.meta, ...meta };
19324
19667
  });
19325
19668
  }
@@ -19393,9 +19736,52 @@ class Agent extends AgentLlmExecutionTools {
19393
19736
  ${block(result.content)}
19394
19737
 
19395
19738
  `);
19739
+ // Extract knowledge
19740
+ let knowledgeBlock = '';
19741
+ try {
19742
+ const extractionPrompt = {
19743
+ title: 'Knowledge Extraction',
19744
+ modelRequirements: {
19745
+ modelVariant: 'CHAT',
19746
+ },
19747
+ content: spaceTrim$2((block) => `
19748
+ You are an AI agent that is learning from a conversation.
19749
+
19750
+ Here is the conversation so far:
19751
+
19752
+ User: ${block(prompt.content)}
19753
+ Agent: ${block(result.content)}
19754
+
19755
+ Extract any new knowledge, facts, or important information that should be remembered for future interactions.
19756
+ Format the output as a list of KNOWLEDGE blocks.
19757
+ If there is no new knowledge, return nothing.
19758
+
19759
+ Example output:
19760
+ KNOWLEDGE The user's name is Alice.
19761
+ KNOWLEDGE The project deadline is next Friday.
19762
+ `),
19763
+ pipelineUrl: 'https://github.com/webgptorg/promptbook/blob/main/prompts/knowledge-extraction.ptbk.md',
19764
+ parameters: {},
19765
+ };
19766
+ if (this.options.llmTools.callChatModel) {
19767
+ const extractionResult = await this.options.llmTools.callChatModel(extractionPrompt);
19768
+ const extractedContent = extractionResult.content;
19769
+ if (extractedContent.includes('KNOWLEDGE')) {
19770
+ knowledgeBlock = '\n\n' + spaceTrim$2(extractedContent);
19771
+ }
19772
+ }
19773
+ else {
19774
+ // TODO: [🧠] Fallback to callChatModelStream if callChatModel is not available
19775
+ }
19776
+ }
19777
+ catch (error) {
19778
+ if (this.options.isVerbose) {
19779
+ console.warn('Failed to extract knowledge', error);
19780
+ }
19781
+ }
19396
19782
  // Append to the current source
19397
19783
  const currentSource = this.agentSource.value;
19398
- const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample));
19784
+ const newSource = padBook(validateBook(spaceTrim$2(currentSource) + '\n\n' + learningExample + knowledgeBlock));
19399
19785
  // Update the source (which will trigger the subscription and update the underlying tools)
19400
19786
  this.agentSource.next(newSource);
19401
19787
  return result;
@@ -20847,7 +21233,7 @@ const PERSONALITIES = [
20847
21233
  'Serious and focused AI consultant.',
20848
21234
  ];
20849
21235
  /**
20850
- * @@@@
21236
+ * Generates a random agent persona description.
20851
21237
  *
20852
21238
  * @private internal helper function
20853
21239
  */
@@ -21164,5 +21550,5 @@ function $generateBookBoilerplate(options) {
21164
21550
  * TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
21165
21551
  */
21166
21552
 
21167
- export { $bookTranspilersRegister, $generateBookBoilerplate, $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, API_REQUEST_TIMEOUT, AUTO_FEDERATED_AGENT_SERVER_URLS, AbstractFormatError, Agent, AgentCollectionInSupabase, AgentLlmExecutionTools, AuthenticationError, BIG_DATASET_TRESHOLD, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CLI_APP_ID, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CompletionFormfactorDefinition, CsvFormatError, CsvFormatParser, DEFAULT_AGENTS_DIRNAME, DEFAULT_BOOK, DEFAULT_BOOKS_DIRNAME, DEFAULT_BOOK_OUTPUT_PARAMETER_NAME, DEFAULT_BOOK_TITLE, DEFAULT_CSV_SETTINGS, DEFAULT_DOWNLOAD_CACHE_DIRNAME, DEFAULT_EXECUTION_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_MAX_REQUESTS_PER_MINUTE, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_PROMPT_TASK_TITLE, DEFAULT_REMOTE_SERVER_URL, DEFAULT_SCRAPE_CACHE_DIRNAME, DEFAULT_TASK_SIMULATED_DURATION_MS, DEFAULT_TASK_TITLE, DatabaseError, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FAILED_VALUE_PLACEHOLDER, FORMFACTOR_DEFINITIONS, FormattedBookInMarkdownTranspiler, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, ImageGeneratorFormfactorDefinition, KnowledgeScrapeError, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_ORDERS, MODEL_TRUST_LEVELS, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotAllowed, NotFoundError, NotYetImplementedCommitmentDefinition, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, OpenAiSdkTranspiler, PADDING_LINES, PENDING_VALUE_PLACEHOLDER, PLAYGROUND_APP_ID, PROMPTBOOK_CHAT_COLOR, PROMPTBOOK_COLOR, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, PROMPTBOOK_LOGO_URL, PROMPTBOOK_SYNTAX_COLORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, PromptbookFetchError, REMOTE_SERVER_URLS, RESERVED_PARAMETER_NAMES, RemoteAgent, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatParser, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UNCERTAIN_ZERO_VALUE, USER_CHAT_COLOR, UnexpectedError, WrappedError, ZERO_USAGE, ZERO_VALUE, _AgentMetadata, _AgentRegistration, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _BoilerplateScraperMetadataRegistration, _DeepseekMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _MarkitdownScraperMetadataRegistration, _OllamaMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiCompatibleMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, aboutPromptbookInformation, addUsage, book, cacheLlmTools, compilePipeline, computeAgentHash, computeCosineSimilarity, countUsage, createAgentLlmExecutionTools, createAgentModelRequirements, createAgentModelRequirementsWithCommitments, createBasicAgentModelRequirements, createDefaultAgentName, createEmptyAgentModelRequirements, createLlmToolsFromConfiguration, createPipelineCollectionFromJson, createPipelineCollectionFromPromise, createPipelineCollectionFromUrl, createPipelineExecutor, createPipelineSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, filterModels, generatePlaceholderAgentProfileImageUrl, getAllCommitmentDefinitions, getAllCommitmentTypes, getCommitmentDefinition, getGroupedCommitmentDefinitions, getPipelineInterface, getSingleLlmExecutionTools, identificationToPromptbookToken, isCommitmentSupported, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, isValidBook, isValidPipelineString, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, migratePipeline, normalizeAgentName, padBook, parseAgentSource, parseParameters, parsePipeline, pipelineCollectionToJson, pipelineJsonToString, prepareKnowledgePieces, preparePersona, preparePipeline, prettifyPipelineString, promptbookFetch, promptbookTokenToIdentification, unpreparePipeline, usageToHuman, usageToWorktime, validateBook, validatePipeline, validatePipelineString };
21553
+ export { $bookTranspilersRegister, $generateBookBoilerplate, $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, API_REQUEST_TIMEOUT, AUTO_FEDERATED_AGENT_SERVER_URLS, AbstractFormatError, Agent, AgentCollectionInSupabase, AgentLlmExecutionTools, AuthenticationError, BIG_DATASET_TRESHOLD, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CLI_APP_ID, CORE_SERVER, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CompletionFormfactorDefinition, CsvFormatError, CsvFormatParser, DEFAULT_AGENTS_DIRNAME, DEFAULT_BOOK, DEFAULT_BOOKS_DIRNAME, DEFAULT_BOOK_OUTPUT_PARAMETER_NAME, DEFAULT_BOOK_TITLE, DEFAULT_CSV_SETTINGS, DEFAULT_DOWNLOAD_CACHE_DIRNAME, DEFAULT_EXECUTION_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_MAX_REQUESTS_PER_MINUTE, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_PROMPT_TASK_TITLE, DEFAULT_REMOTE_SERVER_URL, DEFAULT_SCRAPE_CACHE_DIRNAME, DEFAULT_TASK_SIMULATED_DURATION_MS, DEFAULT_TASK_TITLE, DatabaseError, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FAILED_VALUE_PLACEHOLDER, FORMFACTOR_DEFINITIONS, FormattedBookInMarkdownTranspiler, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, ImageGeneratorFormfactorDefinition, KnowledgeScrapeError, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_ORDERS, MODEL_TRUST_LEVELS, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotAllowed, NotFoundError, NotYetImplementedCommitmentDefinition, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, OpenAiSdkTranspiler, PADDING_LINES, PENDING_VALUE_PLACEHOLDER, PLAYGROUND_APP_ID, PROMPTBOOK_CHAT_COLOR, PROMPTBOOK_COLOR, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, PROMPTBOOK_LOGO_URL, PROMPTBOOK_SYNTAX_COLORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, PromptbookFetchError, REMOTE_SERVER_URLS, RESERVED_PARAMETER_NAMES, RemoteAgent, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatParser, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UNCERTAIN_ZERO_VALUE, USER_CHAT_COLOR, UnexpectedError, WrappedError, ZERO_USAGE, ZERO_VALUE, _AgentMetadata, _AgentRegistration, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _BoilerplateScraperMetadataRegistration, _DeepseekMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _MarkitdownScraperMetadataRegistration, _OllamaMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiCompatibleMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, aboutPromptbookInformation, addUsage, book, cacheLlmTools, compilePipeline, computeAgentHash, computeCosineSimilarity, countUsage, createAgentLlmExecutionTools, createAgentModelRequirements, createAgentModelRequirementsWithCommitments, createBasicAgentModelRequirements, createDefaultAgentName, createEmptyAgentModelRequirements, createLlmToolsFromConfiguration, createPipelineCollectionFromJson, createPipelineCollectionFromPromise, createPipelineCollectionFromUrl, createPipelineExecutor, createPipelineSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, filterModels, generatePlaceholderAgentProfileImageUrl, getAllCommitmentDefinitions, getAllCommitmentTypes, getCommitmentDefinition, getGroupedCommitmentDefinitions, getPipelineInterface, getSingleLlmExecutionTools, identificationToPromptbookToken, isCommitmentSupported, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, isValidBook, isValidPipelineString, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, migratePipeline, normalizeAgentName, padBook, parseAgentSource, parseParameters, parsePipeline, pipelineCollectionToJson, pipelineJsonToString, prepareKnowledgePieces, preparePersona, preparePipeline, prettifyPipelineString, promptbookFetch, promptbookTokenToIdentification, unpreparePipeline, usageToHuman, usageToWorktime, validateBook, validatePipeline, validatePipelineString };
21168
21554
  //# sourceMappingURL=index.es.js.map