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