@promptbook/cli 0.103.0-46 → 0.103.0-48

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 (109) hide show
  1. package/apps/agents-server/TODO.txt +2 -2
  2. package/apps/agents-server/config.ts.todo +5 -279
  3. package/apps/agents-server/next.config.ts +3 -0
  4. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +1 -1
  5. package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +2 -2
  6. package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +13 -5
  7. package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/TODO.txt +1 -0
  8. package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +53 -0
  9. package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +45 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +54 -0
  11. package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +84 -18
  12. package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +9 -5
  13. package/apps/agents-server/src/app/agents/[agentName]/book+chat/{SelfLearningBook.tsx → AgentBookAndChatComponent.tsx} +5 -48
  14. package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +7 -4
  15. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatWrapper.tsx +38 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +23 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +8 -6
  18. package/apps/agents-server/src/app/agents/page.tsx +11 -0
  19. package/apps/agents-server/src/app/api/chat/route.ts +1 -1
  20. package/apps/agents-server/src/app/api/chat-streaming/route.ts +5 -1
  21. package/apps/agents-server/src/app/api/upload/route.ts +71 -0
  22. package/apps/agents-server/src/{supabase/getSupabase.ts → database/$provideSupabase.ts} +11 -7
  23. package/apps/agents-server/src/{supabase/getSupabaseForBrowser.ts → database/$provideSupabaseForBrowser.ts} +9 -5
  24. package/apps/agents-server/src/{supabase/getSupabaseForServer.ts → database/$provideSupabaseForServer.ts} +4 -4
  25. package/apps/agents-server/src/{supabase/getSupabaseForWorker.ts → database/$provideSupabaseForWorker.ts} +5 -4
  26. package/apps/agents-server/src/database/schema.sql +131 -0
  27. package/apps/agents-server/src/database/schema.ts +217 -0
  28. package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +3 -2
  29. package/apps/agents-server/src/tools/$provideCdnForServer.ts +28 -0
  30. package/apps/agents-server/src/tools/$provideOpenAiAssistantExecutionToolsForServer.ts +1 -1
  31. package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +119 -0
  32. package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +32 -0
  33. package/apps/agents-server/src/utils/cdn/interfaces/IStorage.ts +14 -0
  34. package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +28 -0
  35. package/apps/agents-server/src/utils/cdn/utils/nameToSubfolderPath.ts +9 -0
  36. package/apps/agents-server/src/utils/cdn/utils/nextRequestToNodeRequest.ts +27 -0
  37. package/apps/agents-server/src/utils/validators/validateMimeType.ts +24 -0
  38. package/apps/agents-server/tsconfig.json +1 -1
  39. package/esm/index.es.js +319 -181
  40. package/esm/index.es.js.map +1 -1
  41. package/esm/typings/servers.d.ts +1 -7
  42. package/esm/typings/src/_packages/components.index.d.ts +4 -0
  43. package/esm/typings/src/_packages/core.index.d.ts +22 -14
  44. package/esm/typings/src/_packages/types.index.d.ts +14 -6
  45. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +7 -3
  46. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +6 -1
  47. package/esm/typings/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +3 -2
  48. package/esm/typings/src/book-2.0/agent-source/computeAgentHash.d.ts +8 -0
  49. package/esm/typings/src/book-2.0/agent-source/computeAgentHash.test.d.ts +1 -0
  50. package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +1 -1
  51. package/esm/typings/src/book-2.0/agent-source/createDefaultAgentName.d.ts +8 -0
  52. package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.d.ts +9 -0
  53. package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.test.d.ts +1 -0
  54. package/esm/typings/src/book-2.0/agent-source/parseAgentSourceWithCommitments.d.ts +1 -1
  55. package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.d.ts +14 -0
  56. package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.test.d.ts +1 -0
  57. package/esm/typings/src/book-components/Chat/AgentChat/AgentChatProps.d.ts +13 -0
  58. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +1 -60
  59. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +57 -32
  60. package/esm/typings/src/{book-2.0/commitments → commitments}/ACTION/ACTION.d.ts +1 -1
  61. package/esm/typings/src/{book-2.0/commitments → commitments}/DELETE/DELETE.d.ts +1 -1
  62. package/esm/typings/src/{book-2.0/commitments → commitments}/FORMAT/FORMAT.d.ts +1 -1
  63. package/esm/typings/src/{book-2.0/commitments → commitments}/GOAL/GOAL.d.ts +1 -1
  64. package/esm/typings/src/{book-2.0/commitments → commitments}/KNOWLEDGE/KNOWLEDGE.d.ts +1 -5
  65. package/esm/typings/src/{book-2.0/commitments → commitments}/MEMORY/MEMORY.d.ts +1 -1
  66. package/esm/typings/src/{book-2.0/commitments → commitments}/MESSAGE/MESSAGE.d.ts +1 -1
  67. package/esm/typings/src/{book-2.0/commitments → commitments}/META/META.d.ts +1 -1
  68. package/esm/typings/src/{book-2.0/commitments → commitments}/META_IMAGE/META_IMAGE.d.ts +1 -1
  69. package/esm/typings/src/{book-2.0/commitments → commitments}/META_LINK/META_LINK.d.ts +1 -1
  70. package/esm/typings/src/{book-2.0/commitments → commitments}/MODEL/MODEL.d.ts +1 -1
  71. package/esm/typings/src/{book-2.0/commitments → commitments}/NOTE/NOTE.d.ts +1 -1
  72. package/esm/typings/src/{book-2.0/commitments → commitments}/PERSONA/PERSONA.d.ts +1 -1
  73. package/esm/typings/src/{book-2.0/commitments → commitments}/RULE/RULE.d.ts +1 -1
  74. package/esm/typings/src/{book-2.0/commitments → commitments}/SAMPLE/SAMPLE.d.ts +1 -1
  75. package/esm/typings/src/{book-2.0/commitments → commitments}/SCENARIO/SCENARIO.d.ts +1 -1
  76. package/esm/typings/src/{book-2.0/commitments → commitments}/STYLE/STYLE.d.ts +1 -1
  77. package/esm/typings/src/{book-2.0/commitments → commitments}/_base/BaseCommitmentDefinition.d.ts +1 -1
  78. package/esm/typings/src/{book-2.0/commitments → commitments}/_base/CommitmentDefinition.d.ts +1 -1
  79. package/esm/typings/src/{book-2.0/commitments → commitments}/_base/NotYetImplementedCommitmentDefinition.d.ts +1 -1
  80. package/esm/typings/src/{book-2.0/commitments → commitments}/_base/createEmptyAgentModelRequirements.d.ts +1 -1
  81. package/esm/typings/src/execution/LlmExecutionTools.d.ts +1 -1
  82. package/esm/typings/src/llm-providers/_common/utils/assertUniqueModels.d.ts +12 -0
  83. package/esm/typings/src/llm-providers/agent/Agent.d.ts +10 -9
  84. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +5 -1
  85. package/esm/typings/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +1 -1
  86. package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +32 -0
  87. package/esm/typings/src/llm-providers/agent/RemoteAgentOptions.d.ts +11 -0
  88. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +29 -4
  89. package/esm/typings/src/llm-providers/openai/openai-models.test.d.ts +4 -0
  90. package/esm/typings/src/remote-server/startAgentServer.d.ts +1 -1
  91. package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
  92. package/esm/typings/src/storage/_common/PromptbookStorage.d.ts +1 -0
  93. package/esm/typings/src/transpilers/openai-sdk/register.d.ts +1 -1
  94. package/esm/typings/src/types/typeAliases.d.ts +12 -0
  95. package/esm/typings/src/utils/color/internal-utils/checkChannelValue.d.ts +0 -3
  96. package/esm/typings/src/utils/normalization/normalize-to-kebab-case.d.ts +2 -0
  97. package/esm/typings/src/utils/normalization/normalizeTo_PascalCase.d.ts +3 -0
  98. package/esm/typings/src/utils/normalization/normalizeTo_camelCase.d.ts +2 -0
  99. package/esm/typings/src/utils/normalization/titleToName.d.ts +2 -0
  100. package/esm/typings/src/utils/random/$generateBookBoilerplate.d.ts +2 -2
  101. package/esm/typings/src/utils/random/$randomFullnameWithColor.d.ts +1 -1
  102. package/esm/typings/src/version.d.ts +1 -1
  103. package/package.json +1 -1
  104. package/umd/index.umd.js +320 -182
  105. package/umd/index.umd.js.map +1 -1
  106. package/apps/agents-server/src/supabase/TODO.txt +0 -1
  107. /package/esm/typings/src/{book-2.0/commitments → commitments}/_base/BookCommitment.d.ts +0 -0
  108. /package/esm/typings/src/{book-2.0/commitments → commitments}/_base/ParsedCommitment.d.ts +0 -0
  109. /package/esm/typings/src/{book-2.0/commitments → commitments}/index.d.ts +0 -0
package/esm/index.es.js CHANGED
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
47
47
  * @generated
48
48
  * @see https://github.com/webgptorg/promptbook
49
49
  */
50
- const PROMPTBOOK_ENGINE_VERSION = '0.103.0-46';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-48';
51
51
  /**
52
52
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
53
53
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -60,15 +60,20 @@ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-46';
60
60
  */
61
61
  const REMOTE_SERVER_URLS = [
62
62
  {
63
- title: 'Promptbook',
64
- description: `Servers of Promptbook.studio`,
63
+ title: 'Promptbook.Studio',
64
+ description: `Server of Promptbook.studio`,
65
65
  owner: 'AI Web, LLC <legal@ptbk.io> (https://www.ptbk.io/)',
66
- isAnonymousModeAllowed: true,
67
66
  urls: [
68
67
  'https://promptbook.s5.ptbk.io/',
69
68
  // Note: Servers 1-4 are not running
70
69
  ],
71
70
  },
71
+ {
72
+ title: 'Testing Agents',
73
+ description: `Testing Agents server on Vercel`,
74
+ owner: 'AI Web, LLC <legal@ptbk.io> (https://www.ptbk.io/)',
75
+ urls: ['https://s6.ptbk.io/'],
76
+ },
72
77
  /*
73
78
  Note: Working on older version of Promptbook and not supported anymore
74
79
  {
@@ -326,9 +331,6 @@ function checkChannelValue(channelName, value) {
326
331
  throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
327
332
  }
328
333
  }
329
- /**
330
- * TODO: [🧠][🚓] Is/which combination it better to use asserts/check, validate or is utility function?
331
- */
332
334
 
333
335
  /**
334
336
  * Color object represents an RGB color with alpha channel
@@ -2936,6 +2938,8 @@ function removeDiacritics(input) {
2936
2938
  /**
2937
2939
  * Converts a given text to kebab-case format.
2938
2940
  *
2941
+ * Note: [🔂] This function is idempotent.
2942
+ *
2939
2943
  * @param text The text to be converted.
2940
2944
  * @returns The kebab-case formatted string.
2941
2945
  * @example 'hello-world'
@@ -3005,6 +3009,8 @@ function removeEmojis(text) {
3005
3009
  /**
3006
3010
  * Converts a title string into a normalized name.
3007
3011
  *
3012
+ * Note: [🔂] This function is idempotent.
3013
+ *
3008
3014
  * @param value The title string to be converted to a name.
3009
3015
  * @returns A normalized name derived from the input title.
3010
3016
  * @example 'Hello World!' -> 'hello-world'
@@ -10015,6 +10021,8 @@ const expectCommandParser = {
10015
10021
  /**
10016
10022
  * Normalizes a given text to camelCase format.
10017
10023
  *
10024
+ * Note: [🔂] This function is idempotent.
10025
+ *
10018
10026
  * @param text The text to be normalized.
10019
10027
  * @param _isFirstLetterCapital Whether the first letter should be capitalized.
10020
10028
  * @returns The camelCase formatted string.
@@ -13023,6 +13031,9 @@ function nameToUriParts(name) {
13023
13031
  }
13024
13032
 
13025
13033
  /**
13034
+ * Normalizes a given text to PascalCase format.
13035
+ *
13036
+ * Note: [🔂] This function is idempotent.
13026
13037
  *
13027
13038
  * @param text @public exported from `@promptbook/utils`
13028
13039
  * @returns
@@ -15080,16 +15091,18 @@ function $initializeRunCommand(program) {
15080
15091
  *
15081
15092
  * @see https://github.com/webgptorg/promptbook#remote-server
15082
15093
  * @public exported from `@promptbook/remote-server`
15083
- * <- TODO: !!!! Maybe change to `@promptbook/agent-server`
15094
+ * <- TODO: !!!! Change to `@promptbook/agent-server`
15084
15095
  */
15085
15096
  async function startAgentServer(options) {
15086
15097
  const { port = 4440 } = options;
15087
15098
  // TODO: !!!! [🌕]
15099
+ const agentsServerRoot = join(__dirname, '../apps/agents-server');
15088
15100
  console.trace(`!!! Starting agents server on port ${port}...`);
15089
15101
  console.log(`!!! cwd`, process.cwd());
15090
15102
  console.log(`!!! __dirname`, __dirname);
15103
+ console.log(`!!! agentsServerRoot`, agentsServerRoot);
15091
15104
  await $execCommand({
15092
- cwd: './apps/agents-server',
15105
+ cwd: agentsServerRoot,
15093
15106
  command: `next dev --port ${port} `,
15094
15107
  isVerbose: true,
15095
15108
  });
@@ -16390,8 +16403,7 @@ function startRemoteServer(options) {
16390
16403
  };
16391
16404
  }
16392
16405
  /**
16393
- * TODO !!!! Add agent
16394
- * TODO: !!!! Allow to chat with agents directly via remote server
16406
+
16395
16407
  * TODO: [🕋] Use here `aboutPromptbookInformation`
16396
16408
  * TODO: [🌡] Add CORS and security - probably via `helmet`
16397
16409
  * TODO: Split this file into multiple functions - handler for each request
@@ -17512,17 +17524,17 @@ const OPENAI_MODELS = exportJson({
17512
17524
  },
17513
17525
  /**/
17514
17526
  /*/
17515
- {
17516
- modelTitle: 'tts-1-hd-1106',
17517
- modelName: 'tts-1-hd-1106',
17518
- },
17519
- /**/
17527
+ {
17528
+ modelTitle: 'tts-1-hd-1106',
17529
+ modelName: 'tts-1-hd-1106',
17530
+ },
17531
+ /**/
17520
17532
  /*/
17521
- {
17522
- modelTitle: 'tts-1-hd',
17523
- modelName: 'tts-1-hd',
17524
- },
17525
- /**/
17533
+ {
17534
+ modelTitle: 'tts-1-hd',
17535
+ modelName: 'tts-1-hd',
17536
+ },
17537
+ /**/
17526
17538
  /**/
17527
17539
  {
17528
17540
  modelVariant: 'CHAT',
@@ -18842,26 +18854,6 @@ const GOOGLE_MODELS = exportJson({
18842
18854
  output: pricing(`$0.45 / 1M tokens`),
18843
18855
  },
18844
18856
  },
18845
- {
18846
- modelVariant: 'CHAT',
18847
- modelTitle: 'Gemini 2.0 Flash',
18848
- modelName: 'gemini-2.0-flash',
18849
- modelDescription: 'Fast, efficient model with 128K context window optimized for rapid response times. Balances performance and cost with 2x lower latency than Pro models while maintaining strong capabilities in text generation, code completion, and logical reasoning. Excellent for interactive applications, chatbots, and services requiring quick responses with good quality.',
18850
- pricing: {
18851
- prompt: pricing(`$0.35 / 1M tokens`),
18852
- output: pricing(`$1.05 / 1M tokens`),
18853
- },
18854
- },
18855
- {
18856
- modelVariant: 'CHAT',
18857
- modelTitle: 'Gemini 2.0 Flash Lite',
18858
- modelName: 'gemini-2.0-flash-lite',
18859
- modelDescription: 'Streamlined version of Gemini 2.0 Flash with 64K context window, designed for extremely low-latency applications. Features 40% smaller model size and 3x faster inference while retaining core capabilities for text and simple reasoning tasks. Perfect for mobile applications, edge deployments, and high-volume services with strict latency requirements.',
18860
- pricing: {
18861
- prompt: pricing(`$0.20 / 1M tokens`),
18862
- output: pricing(`$0.60 / 1M tokens`),
18863
- },
18864
- },
18865
18857
  {
18866
18858
  modelVariant: 'CHAT',
18867
18859
  modelTitle: 'Gemini 2.0 Flash Thinking',
@@ -20398,7 +20390,7 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
20398
20390
  *
20399
20391
  * This is useful for calling OpenAI API with a single assistant, for more wide usage use `OpenAiExecutionTools`.
20400
20392
  *
20401
- * Note: [🦖] There are several different things in Promptbook:
20393
+ * !!! Note: [🦖] There are several different things in Promptbook:
20402
20394
  * - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
20403
20395
  * - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
20404
20396
  * - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
@@ -20504,17 +20496,21 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20504
20496
  console.info('connect', stream.currentEvent);
20505
20497
  }
20506
20498
  });
20499
+ /*
20507
20500
  stream.on('messageDelta', (messageDelta) => {
20508
- var _a;
20509
- if (this.options.isVerbose &&
20501
+ if (
20502
+ this.options.isVerbose &&
20510
20503
  messageDelta &&
20511
20504
  messageDelta.content &&
20512
20505
  messageDelta.content[0] &&
20513
- messageDelta.content[0].type === 'text') {
20514
- console.info('messageDelta', (_a = messageDelta.content[0].text) === null || _a === void 0 ? void 0 : _a.value);
20506
+ messageDelta.content[0].type === 'text'
20507
+ ) {
20508
+ console.info('messageDelta', messageDelta.content[0].text?.value);
20515
20509
  }
20510
+
20516
20511
  // <- TODO: [🐚] Make streaming and running tasks working
20517
20512
  });
20513
+ */
20518
20514
  stream.on('messageCreated', (message) => {
20519
20515
  if (this.options.isVerbose) {
20520
20516
  console.info('messageCreated', message);
@@ -20569,15 +20565,19 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20569
20565
  },
20570
20566
  });
20571
20567
  }
20572
- async playground() {
20568
+ /*
20569
+ public async playground() {
20573
20570
  const client = await this.getClient();
20571
+
20574
20572
  // List all assistants
20575
20573
  const assistants = await client.beta.assistants.list();
20576
20574
  console.log('!!! Assistants:', assistants);
20575
+
20577
20576
  // Get details of a specific assistant
20578
20577
  const assistantId = 'asst_MO8fhZf4dGloCfXSHeLcIik0';
20579
20578
  const assistant = await client.beta.assistants.retrieve(assistantId);
20580
20579
  console.log('!!! Assistant Details:', assistant);
20580
+
20581
20581
  // Update an assistant
20582
20582
  const updatedAssistant = await client.beta.assistants.update(assistantId, {
20583
20583
  name: assistant.name + '(M)',
@@ -20587,71 +20587,103 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20587
20587
  },
20588
20588
  });
20589
20589
  console.log('!!! Updated Assistant:', updatedAssistant);
20590
+
20590
20591
  await forEver();
20591
20592
  }
20593
+ */
20594
+ /**
20595
+ * Get an existing assistant tool wrapper
20596
+ */
20597
+ getAssistant(assistantId) {
20598
+ return new OpenAiAssistantExecutionTools({
20599
+ ...this.options,
20600
+ assistantId,
20601
+ });
20602
+ }
20592
20603
  async createNewAssistant(options) {
20593
20604
  if (!this.isCreatingNewAssistantsAllowed) {
20594
20605
  throw new NotAllowed(`Creating new assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
20595
20606
  }
20596
20607
  // await this.playground();
20597
- const { name, instructions } = options;
20608
+ const { name, instructions, knowledgeSources } = options;
20598
20609
  const client = await this.getClient();
20599
- /*/
20600
- //TODO: !!!
20601
- async function downloadFile(url: string, folder = './tmp'): Promise<string> {
20602
- const filename = path.basename(url.split('?')[0]);
20603
- const filepath = path.join(folder, filename);
20604
-
20605
- if (!fs.existsSync(folder)) fs.mkdirSync(folder);
20606
-
20607
- const res = await fetch(url);
20608
- if (!res.ok) throw new Error(`Download error: ${url}`);
20609
- const buffer = await res.arrayBuffer();
20610
- fs.writeFileSync(filepath, Buffer.from(buffer));
20611
- console.log(`📥 File downloaded: ${filename}`);
20612
-
20613
- return filepath;
20614
- }
20615
-
20616
- async function uploadFileToOpenAI(filepath: string) {
20617
- const file = await client.files.create({
20618
- file: fs.createReadStream(filepath),
20619
- purpose: 'assistants',
20610
+ let vectorStoreId;
20611
+ // If knowledge sources are provided, create a vector store with them
20612
+ if (knowledgeSources && knowledgeSources.length > 0) {
20613
+ if (this.options.isVerbose) {
20614
+ console.info(`📚 Creating vector store with ${knowledgeSources.length} knowledge sources...`);
20615
+ }
20616
+ // Create a vector store
20617
+ const vectorStore = await client.beta.vectorStores.create({
20618
+ name: `${name} Knowledge Base`,
20620
20619
  });
20621
- console.log(`⬆️ File uploaded to OpenAI: ${file.filename} (${file.id})`);
20622
- return file;
20623
- }
20624
-
20625
- // 🌐 URL addresses of files to upload
20626
- const fileUrls = [
20627
- 'https://raw.githubusercontent.com/vercel/next.js/canary/packages/next/README.md',
20628
- 'https://raw.githubusercontent.com/openai/openai-cookbook/main/examples/How_to_call_the_Assistants_API_with_Node.js.ipynb',
20629
- ];
20630
-
20631
- // 1️⃣ Download files from URL
20632
- const localFiles = [];
20633
- for (const url of fileUrls) {
20634
- const filepath = await downloadFile(url);
20635
- localFiles.push(filepath);
20636
- }
20637
-
20638
- // 2️⃣ Upload files to OpenAI
20639
- const uploadedFiles = [];
20640
- for (const filepath of localFiles) {
20641
- const file = await uploadFileToOpenAI(filepath);
20642
- uploadedFiles.push(file.id);
20620
+ vectorStoreId = vectorStore.id;
20621
+ if (this.options.isVerbose) {
20622
+ console.info(`✅ Vector store created: ${vectorStoreId}`);
20623
+ }
20624
+ // Upload files from knowledge sources to the vector store
20625
+ const fileStreams = [];
20626
+ for (const source of knowledgeSources) {
20627
+ try {
20628
+ // Check if it's a URL
20629
+ if (source.startsWith('http://') || source.startsWith('https://')) {
20630
+ // Download the file
20631
+ const response = await fetch(source);
20632
+ if (!response.ok) {
20633
+ console.error(`Failed to download ${source}: ${response.statusText}`);
20634
+ continue;
20635
+ }
20636
+ const buffer = await response.arrayBuffer();
20637
+ const filename = source.split('/').pop() || 'downloaded-file';
20638
+ const blob = new Blob([buffer]);
20639
+ const file = new File([blob], filename);
20640
+ fileStreams.push(file);
20641
+ }
20642
+ else {
20643
+ // Assume it's a local file path
20644
+ // Note: This will work in Node.js environment
20645
+ // For browser environments, this would need different handling
20646
+ const fs = await import('fs');
20647
+ const fileStream = fs.createReadStream(source);
20648
+ fileStreams.push(fileStream);
20649
+ }
20650
+ }
20651
+ catch (error) {
20652
+ console.error(`Error processing knowledge source ${source}:`, error);
20653
+ }
20654
+ }
20655
+ // Batch upload files to the vector store
20656
+ if (fileStreams.length > 0) {
20657
+ try {
20658
+ await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
20659
+ files: fileStreams,
20660
+ });
20661
+ if (this.options.isVerbose) {
20662
+ console.info(`✅ Uploaded ${fileStreams.length} files to vector store`);
20663
+ }
20664
+ }
20665
+ catch (error) {
20666
+ console.error('Error uploading files to vector store:', error);
20667
+ }
20668
+ }
20643
20669
  }
20644
- /**/
20645
- // alert('!!!! Creating new OpenAI assistant');
20646
- // 3️⃣ Create assistant with uploaded files
20647
- const assistant = await client.beta.assistants.create({
20670
+ // Create assistant with vector store attached
20671
+ const assistantConfig = {
20648
20672
  name,
20649
20673
  description: 'Assistant created via Promptbook',
20650
20674
  model: 'gpt-4o',
20651
20675
  instructions,
20652
20676
  tools: [/* TODO: [🧠] Maybe add { type: 'code_interpreter' }, */ { type: 'file_search' }],
20653
- // !!!! file_ids: uploadedFiles,
20654
- });
20677
+ };
20678
+ // Attach vector store if created
20679
+ if (vectorStoreId) {
20680
+ assistantConfig.tool_resources = {
20681
+ file_search: {
20682
+ vector_store_ids: [vectorStoreId],
20683
+ },
20684
+ };
20685
+ }
20686
+ const assistant = await client.beta.assistants.create(assistantConfig);
20655
20687
  console.log(`✅ Assistant created: ${assistant.id}`);
20656
20688
  // TODO: !!!! Try listing existing assistants
20657
20689
  // TODO: !!!! Try marking existing assistants by DISCRIMINANT
@@ -20662,6 +20694,95 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20662
20694
  assistantId: assistant.id,
20663
20695
  });
20664
20696
  }
20697
+ async updateAssistant(options) {
20698
+ if (!this.isCreatingNewAssistantsAllowed) {
20699
+ throw new NotAllowed(`Updating assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
20700
+ }
20701
+ const { assistantId, name, instructions, knowledgeSources } = options;
20702
+ const client = await this.getClient();
20703
+ let vectorStoreId;
20704
+ // If knowledge sources are provided, create a vector store with them
20705
+ // TODO: [🧠] Reuse vector store creation logic from createNewAssistant
20706
+ if (knowledgeSources && knowledgeSources.length > 0) {
20707
+ if (this.options.isVerbose) {
20708
+ console.info(`📚 Creating vector store for update with ${knowledgeSources.length} knowledge sources...`);
20709
+ }
20710
+ // Create a vector store
20711
+ const vectorStore = await client.beta.vectorStores.create({
20712
+ name: `${name} Knowledge Base`,
20713
+ });
20714
+ vectorStoreId = vectorStore.id;
20715
+ if (this.options.isVerbose) {
20716
+ console.info(`✅ Vector store created: ${vectorStoreId}`);
20717
+ }
20718
+ // Upload files from knowledge sources to the vector store
20719
+ const fileStreams = [];
20720
+ for (const source of knowledgeSources) {
20721
+ try {
20722
+ // Check if it's a URL
20723
+ if (source.startsWith('http://') || source.startsWith('https://')) {
20724
+ // Download the file
20725
+ const response = await fetch(source);
20726
+ if (!response.ok) {
20727
+ console.error(`Failed to download ${source}: ${response.statusText}`);
20728
+ continue;
20729
+ }
20730
+ const buffer = await response.arrayBuffer();
20731
+ const filename = source.split('/').pop() || 'downloaded-file';
20732
+ const blob = new Blob([buffer]);
20733
+ const file = new File([blob], filename);
20734
+ fileStreams.push(file);
20735
+ }
20736
+ else {
20737
+ // Assume it's a local file path
20738
+ // Note: This will work in Node.js environment
20739
+ // For browser environments, this would need different handling
20740
+ const fs = await import('fs');
20741
+ const fileStream = fs.createReadStream(source);
20742
+ fileStreams.push(fileStream);
20743
+ }
20744
+ }
20745
+ catch (error) {
20746
+ console.error(`Error processing knowledge source ${source}:`, error);
20747
+ }
20748
+ }
20749
+ // Batch upload files to the vector store
20750
+ if (fileStreams.length > 0) {
20751
+ try {
20752
+ await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
20753
+ files: fileStreams,
20754
+ });
20755
+ if (this.options.isVerbose) {
20756
+ console.info(`✅ Uploaded ${fileStreams.length} files to vector store`);
20757
+ }
20758
+ }
20759
+ catch (error) {
20760
+ console.error('Error uploading files to vector store:', error);
20761
+ }
20762
+ }
20763
+ }
20764
+ const assistantUpdate = {
20765
+ name,
20766
+ instructions,
20767
+ tools: [/* TODO: [🧠] Maybe add { type: 'code_interpreter' }, */ { type: 'file_search' }],
20768
+ };
20769
+ if (vectorStoreId) {
20770
+ assistantUpdate.tool_resources = {
20771
+ file_search: {
20772
+ vector_store_ids: [vectorStoreId],
20773
+ },
20774
+ };
20775
+ }
20776
+ const assistant = await client.beta.assistants.update(assistantId, assistantUpdate);
20777
+ if (this.options.isVerbose) {
20778
+ console.log(`✅ Assistant updated: ${assistant.id}`);
20779
+ }
20780
+ return new OpenAiAssistantExecutionTools({
20781
+ ...this.options,
20782
+ isCreatingNewAssistantsAllowed: false,
20783
+ assistantId: assistant.id,
20784
+ });
20785
+ }
20665
20786
  /**
20666
20787
  * Discriminant for type guards
20667
20788
  */
@@ -22225,40 +22346,6 @@ const _FormattedBookInMarkdownTranspilerRegistration = $bookTranspilersRegister.
22225
22346
  * Note: [💞] Ignore a discrepancy between file name and entity name
22226
22347
  */
22227
22348
 
22228
- /**
22229
- * Creates an empty/basic agent model requirements object
22230
- * This serves as the starting point for the reduce-like pattern
22231
- * where each commitment applies its changes to build the final requirements
22232
- *
22233
- * @public exported from `@promptbook/core`
22234
- */
22235
- function createEmptyAgentModelRequirements() {
22236
- return {
22237
- systemMessage: '',
22238
- // modelName: 'gpt-5',
22239
- modelName: 'gemini-2.5-flash-lite',
22240
- temperature: 0.7,
22241
- topP: 0.9,
22242
- topK: 50,
22243
- };
22244
- }
22245
- /**
22246
- * Creates a basic agent model requirements with just the agent name
22247
- * This is used when we have an agent name but no commitments
22248
- *
22249
- * @public exported from `@promptbook/core`
22250
- */
22251
- function createBasicAgentModelRequirements(agentName) {
22252
- const empty = createEmptyAgentModelRequirements();
22253
- return {
22254
- ...empty,
22255
- systemMessage: `You are ${agentName || 'AI Agent'}`,
22256
- };
22257
- }
22258
- /**
22259
- * TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
22260
- */
22261
-
22262
22349
  /**
22263
22350
  * Generates a regex pattern to match a specific commitment
22264
22351
  *
@@ -22792,23 +22879,19 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
22792
22879
  `);
22793
22880
  }
22794
22881
  applyToAgentModelRequirements(requirements, content) {
22795
- var _a;
22796
22882
  const trimmedContent = content.trim();
22797
22883
  if (!trimmedContent) {
22798
22884
  return requirements;
22799
22885
  }
22800
22886
  // Check if content is a URL (external knowledge source)
22801
- if (this.isUrl(trimmedContent)) {
22887
+ if (isValidUrl(trimmedContent)) {
22802
22888
  // Store the URL for later async processing
22803
22889
  const updatedRequirements = {
22804
22890
  ...requirements,
22805
- metadata: {
22806
- ...requirements.metadata,
22807
- knowledgeSources: [
22808
- ...(((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.knowledgeSources) || []),
22809
- trimmedContent,
22810
- ],
22811
- },
22891
+ knowledgeSources: [
22892
+ ...(requirements.knowledgeSources || []),
22893
+ trimmedContent,
22894
+ ],
22812
22895
  };
22813
22896
  // Add placeholder information about knowledge sources to system message
22814
22897
  const knowledgeInfo = `Knowledge Source URL: ${trimmedContent} (will be processed for retrieval during chat)`;
@@ -22820,18 +22903,6 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
22820
22903
  return this.appendToSystemMessage(requirements, knowledgeSection, '\n\n');
22821
22904
  }
22822
22905
  }
22823
- /**
22824
- * Check if content is a URL
22825
- */
22826
- isUrl(content) {
22827
- try {
22828
- new URL(content);
22829
- return true;
22830
- }
22831
- catch (_a) {
22832
- return false;
22833
- }
22834
- }
22835
22906
  }
22836
22907
  /**
22837
22908
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -23642,6 +23713,7 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
23642
23713
  // Keep everything after the PERSONA section
23643
23714
  cleanedMessage = lines.slice(personaEndIndex).join('\n').trim();
23644
23715
  }
23716
+ // TODO: [🕛] There should be `agentFullname` not `agentName`
23645
23717
  // Create new system message with persona at the beginning
23646
23718
  // Format: "You are {agentName}\n{personaContent}"
23647
23719
  // The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
@@ -24129,6 +24201,40 @@ function getCommitmentDefinition(type) {
24129
24201
  * Note: [💞] Ignore a discrepancy between file name and entity name
24130
24202
  */
24131
24203
 
24204
+ /**
24205
+ * Creates an empty/basic agent model requirements object
24206
+ * This serves as the starting point for the reduce-like pattern
24207
+ * where each commitment applies its changes to build the final requirements
24208
+ *
24209
+ * @public exported from `@promptbook/core`
24210
+ */
24211
+ function createEmptyAgentModelRequirements() {
24212
+ return {
24213
+ systemMessage: '',
24214
+ // modelName: 'gpt-5',
24215
+ modelName: 'gemini-2.5-flash-lite',
24216
+ temperature: 0.7,
24217
+ topP: 0.9,
24218
+ topK: 50,
24219
+ };
24220
+ }
24221
+ /**
24222
+ * Creates a basic agent model requirements with just the agent name
24223
+ * This is used when we have an agent name but no commitments
24224
+ *
24225
+ * @public exported from `@promptbook/core`
24226
+ */
24227
+ function createBasicAgentModelRequirements(agentName) {
24228
+ const empty = createEmptyAgentModelRequirements();
24229
+ return {
24230
+ ...empty,
24231
+ systemMessage: `You are ${agentName || 'AI Agent'}`,
24232
+ };
24233
+ }
24234
+ /**
24235
+ * TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
24236
+ */
24237
+
24132
24238
  /**
24133
24239
  * Parses agent source using the new commitment system with multiline support
24134
24240
  * This function replaces the hardcoded commitment parsing in the original parseAgentSource
@@ -24219,29 +24325,6 @@ function parseAgentSourceWithCommitments(agentSource) {
24219
24325
  };
24220
24326
  }
24221
24327
 
24222
- /**
24223
- * Removes comment lines (lines starting with #) from a system message
24224
- * This is used to clean up the final system message before sending it to the AI model
24225
- * while preserving the original content with comments in metadata
24226
- *
24227
- * @param systemMessage The system message that may contain comment lines
24228
- * @returns The system message with comment lines removed
24229
- *
24230
- * @private - TODO: [🧠] Maybe should be public?
24231
- */
24232
- function removeCommentsFromSystemMessage(systemMessage) {
24233
- if (!systemMessage) {
24234
- return systemMessage;
24235
- }
24236
- const lines = systemMessage.split('\n');
24237
- const filteredLines = lines.filter((line) => {
24238
- const trimmedLine = line.trim();
24239
- // Remove lines that start with # (comments)
24240
- return !trimmedLine.startsWith('#');
24241
- });
24242
- return filteredLines.join('\n').trim();
24243
- }
24244
-
24245
24328
  /**
24246
24329
  * Parses parameters from text using both supported notations:
24247
24330
  * 1. @Parameter - single word parameter starting with @
@@ -24300,6 +24383,29 @@ function parseParameters(text) {
24300
24383
  return uniqueParameters;
24301
24384
  }
24302
24385
 
24386
+ /**
24387
+ * Removes comment lines (lines starting with #) from a system message
24388
+ * This is used to clean up the final system message before sending it to the AI model
24389
+ * while preserving the original content with comments in metadata
24390
+ *
24391
+ * @param systemMessage The system message that may contain comment lines
24392
+ * @returns The system message with comment lines removed
24393
+ *
24394
+ * @private - TODO: [🧠] Maybe should be public?
24395
+ */
24396
+ function removeCommentsFromSystemMessage(systemMessage) {
24397
+ if (!systemMessage) {
24398
+ return systemMessage;
24399
+ }
24400
+ const lines = systemMessage.split('\n');
24401
+ const filteredLines = lines.filter((line) => {
24402
+ const trimmedLine = line.trim();
24403
+ // Remove lines that start with # (comments)
24404
+ return !trimmedLine.startsWith('#');
24405
+ });
24406
+ return filteredLines.join('\n').trim();
24407
+ }
24408
+
24303
24409
  /**
24304
24410
  * Creates agent model requirements using the new commitment system
24305
24411
  * This function uses a reduce-like pattern where each commitment applies its changes
@@ -24436,6 +24542,36 @@ function generatePlaceholderAgentProfileImageUrl(agentName) {
24436
24542
  * TODO: [🤹] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
24437
24543
  */
24438
24544
 
24545
+ /**
24546
+ * Computes SHA-256 hash of the agent source
24547
+ *
24548
+ * @public exported from `@promptbook/core`
24549
+ */
24550
+ function computeAgentHash(agentSource) {
24551
+ return SHA256(hexEncoder.parse(agentSource /* <- TODO: !!!!! spaceTrim */)).toString( /* hex */);
24552
+ }
24553
+
24554
+ /**
24555
+ * Normalizes agent name from arbitrary string to valid agent name
24556
+ *
24557
+ * Note: [🔂] This function is idempotent.
24558
+ *
24559
+ * @public exported from `@promptbook/core`
24560
+ */
24561
+ function normalizeAgentName(rawAgentName) {
24562
+ return titleToName(spaceTrim(rawAgentName));
24563
+ }
24564
+
24565
+ /**
24566
+ * Creates temporary default agent name based on agent source hash
24567
+ *
24568
+ * @public exported from `@promptbook/core`
24569
+ */
24570
+ function createDefaultAgentName(agentSource) {
24571
+ const agentHash = computeAgentHash(agentSource);
24572
+ return normalizeAgentName(`Agent ${agentHash.substring(0, 6)}`);
24573
+ }
24574
+
24439
24575
  /**
24440
24576
  * Parses basic information from agent source
24441
24577
  *
@@ -24478,8 +24614,10 @@ function parseAgentSource(agentSource) {
24478
24614
  // Parse parameters using unified approach - both @Parameter and {parameter} notations
24479
24615
  // are treated as the same syntax feature with unified representation
24480
24616
  const parameters = parseParameters(agentSource);
24617
+ const agentHash = computeAgentHash(agentSource);
24481
24618
  return {
24482
- agentName: parseResult.agentName,
24619
+ agentName: normalizeAgentName(parseResult.agentName || createDefaultAgentName(agentSource)),
24620
+ agentHash,
24483
24621
  personaDescription,
24484
24622
  meta,
24485
24623
  parameters,
@@ -24699,7 +24837,7 @@ const OpenAiSdkTranspiler = {
24699
24837
  });
24700
24838
 
24701
24839
  const answer = response.choices[0].message.content;
24702
- console.log('\\n🧠 ${agentName}:', answer, '\\n');
24840
+ console.log('\\n🧠 ${agentName /* <- TODO: [🕛] There should be `agentFullname` not `agentName` */}:', answer, '\\n');
24703
24841
 
24704
24842
  chatHistory.push({ role: 'assistant', content: answer });
24705
24843
  promptUser();
@@ -24718,7 +24856,7 @@ const OpenAiSdkTranspiler = {
24718
24856
 
24719
24857
  (async () => {
24720
24858
  await setupKnowledge();
24721
- console.log("🤖 Chat with ${agentName} (type 'exit' to quit)\\n");
24859
+ console.log("🤖 Chat with ${agentName /* <- TODO: [🕛] There should be `agentFullname` not `agentName` */} (type 'exit' to quit)\\n");
24722
24860
  promptUser();
24723
24861
  })();
24724
24862
  `);
@@ -24765,7 +24903,7 @@ const OpenAiSdkTranspiler = {
24765
24903
  });
24766
24904
 
24767
24905
  const answer = response.choices[0].message.content;
24768
- console.log('\\n🧠 ${agentName}:', answer, '\\n');
24906
+ console.log('\\n🧠 ${agentName /* <- TODO: [🕛] There should be `agentFullname` not `agentName` */}:', answer, '\\n');
24769
24907
 
24770
24908
  chatHistory.push({ role: 'assistant', content: answer });
24771
24909
  promptUser();
@@ -24782,7 +24920,7 @@ const OpenAiSdkTranspiler = {
24782
24920
  });
24783
24921
  }
24784
24922
 
24785
- console.log("🤖 Chat with ${agentName} (type 'exit' to quit)\\n");
24923
+ console.log("🤖 Chat with ${agentName /* <- TODO: [🕛] There should be `agentFullname` not `agentName` */} (type 'exit' to quit)\\n");
24786
24924
  promptUser();
24787
24925
 
24788
24926
  `);
@@ -24798,7 +24936,7 @@ const OpenAiSdkTranspiler = {
24798
24936
  * @public exported from `@promptbook/wizard`
24799
24937
  * @public exported from `@promptbook/cli`
24800
24938
  *
24801
- * TODO: !!!! Which package should export this?
24939
+ * TODO: [🧠] Which package should export this?
24802
24940
  */
24803
24941
  const _OpenAiSdkTranspilerRegistration = $bookTranspilersRegister.register(OpenAiSdkTranspiler);
24804
24942
  /**