@promptbook/cli 0.103.0-45 → 0.103.0-46

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.
@@ -0,0 +1,86 @@
1
+ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
2
+ import { padBook, validateBook } from '@promptbook-local/core';
3
+ import { serializeError } from '@promptbook-local/utils';
4
+ import spaceTrim from 'spacetrim';
5
+ import { assertsError } from '../../../../../../../../src/errors/assertsError';
6
+ import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
7
+
8
+ export async function GET(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
9
+ keepUnused(request /* <- Note: We dont need `request` parameter */);
10
+ let { agentName } = await params;
11
+ agentName = decodeURIComponent(agentName);
12
+
13
+ try {
14
+ const collection = await $provideAgentCollectionForServer();
15
+ const agentSource = await collection.getAgentSource(agentName);
16
+
17
+ return new Response(agentSource.getValue(), {
18
+ status: 200,
19
+ headers: { 'Content-Type': 'text/plain' /* <- TODO: [🎳] Mime type of book */ },
20
+ });
21
+ } catch (error) {
22
+ assertsError(error);
23
+
24
+ console.error(error);
25
+
26
+ return new Response(
27
+ JSON.stringify(
28
+ serializeError(error),
29
+ // <- TODO: !!! Rename `serializeError` to `errorToJson`
30
+ null,
31
+ 4,
32
+ // <- TODO: !!! Allow to configure pretty print for agent server
33
+ ),
34
+ {
35
+ status: 400, // <- TODO: !!! Make `errorToHttpStatusCode`
36
+ headers: { 'Content-Type': 'application/json' },
37
+ },
38
+ );
39
+ }
40
+ }
41
+
42
+ export async function PUT(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
43
+ let { agentName } = await params;
44
+ agentName = decodeURIComponent(agentName);
45
+
46
+ try {
47
+ const collection = await $provideAgentCollectionForServer();
48
+ let agentSourceUnchecked = await request.text();
49
+ agentSourceUnchecked = spaceTrim(agentSourceUnchecked);
50
+ let agentSource = validateBook(agentSourceUnchecked);
51
+ agentSource = padBook(agentSource);
52
+
53
+ await collection.updateAgentSource(agentName, agentSource);
54
+ // <- TODO: !!! Properly type as string_book
55
+
56
+ return new Response(
57
+ JSON.stringify({
58
+ isSuccessful: true,
59
+ message: `Agent "${agentName}" updated successfully`,
60
+ agentSource, // <- TODO: !!! Remove from response
61
+ }),
62
+ {
63
+ status: 200,
64
+ headers: { 'Content-Type': 'application/json' },
65
+ },
66
+ );
67
+ } catch (error) {
68
+ assertsError(error);
69
+
70
+ console.error(error);
71
+
72
+ return new Response(
73
+ JSON.stringify(
74
+ serializeError(error),
75
+ // <- TODO: !!! Rename `serializeError` to `errorToJson`
76
+ null,
77
+ 4,
78
+ // <- TODO: !!! Allow to configure pretty print for agent server
79
+ ),
80
+ {
81
+ status: 400, // <- TODO: !!! Make `errorToHttpStatusCode`
82
+ headers: { 'Content-Type': 'application/json' },
83
+ },
84
+ );
85
+ }
86
+ }
@@ -0,0 +1,37 @@
1
+ ### Get the book
2
+
3
+ GET http://localhost:4440/agents/Gabriel%20Gray/api/book
4
+
5
+
6
+
7
+ # _______________________________________
8
+ ### Update the book 1
9
+
10
+
11
+ PUT http://localhost:4440/agents/Gabriel%20Gray/api/book
12
+ Content-Type: text/plain
13
+ # <- TODO: [🎳] Mime type of book
14
+
15
+
16
+ Gabriel Gray
17
+
18
+ META COLOR #c9c9c9ff
19
+ PERSONA Friendly and helpful AI agent.
20
+ RULE Be kind and respectful.
21
+
22
+
23
+
24
+
25
+ # _______________________________________
26
+ ### Update the book 2
27
+
28
+
29
+ PUT http://localhost:4440/agents/Gabriel%20Gray/api/book
30
+ Content-Type: text/plain
31
+ # <- TODO: [🎳] Mime type of book
32
+
33
+ Gabriel Gray
34
+
35
+ META COLOR #242424ff
36
+ PERSONA Strict and professional AI agent.
37
+ RULE Be strict and professional.
@@ -0,0 +1,74 @@
1
+ 'use client';
2
+
3
+ import { BookEditor } from '@promptbook-local/components';
4
+ import { string_book } from '@promptbook-local/types';
5
+ import { useState } from 'react';
6
+
7
+ type BookEditorWrapperProps = {
8
+ agentName: string;
9
+ initialAgentSource: string_book;
10
+ };
11
+
12
+ // TODO: !!!! Rename to BookEditorSavingWrapper
13
+
14
+ export function BookEditorWrapper({ agentName, initialAgentSource }: BookEditorWrapperProps) {
15
+ const [agentSource, setAgentSource] = useState<string_book>(initialAgentSource);
16
+ const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');
17
+
18
+ const handleChange = async (newSource: string_book) => {
19
+ setAgentSource(newSource);
20
+ setSaveStatus('saving');
21
+
22
+ try {
23
+ const response = await fetch(`/agents/${encodeURIComponent(agentName)}/api/book`, {
24
+ method: 'PUT',
25
+ headers: {
26
+ 'Content-Type': 'text/plain',
27
+ },
28
+ body: newSource,
29
+ });
30
+
31
+ if (!response.ok) {
32
+ throw new Error(`Failed to save: ${response.statusText}`);
33
+ }
34
+
35
+ setSaveStatus('saved');
36
+ setTimeout(() => setSaveStatus('idle'), 2000); // Reset status after 2 seconds
37
+ } catch (error) {
38
+ console.error('Error saving agent source:', error);
39
+ setSaveStatus('error');
40
+ setTimeout(() => setSaveStatus('idle'), 3000);
41
+ }
42
+ };
43
+
44
+ return (
45
+ <div className="w-full h-screen flex flex-col">
46
+ {saveStatus !== 'idle' && (
47
+ <div
48
+ className={`px-4 py-2 text-sm ${
49
+ saveStatus === 'saving'
50
+ ? 'bg-blue-100 text-blue-800'
51
+ : saveStatus === 'saved'
52
+ ? 'bg-green-100 text-green-800'
53
+ : 'bg-red-100 text-red-800'
54
+ }`}
55
+ >
56
+ {saveStatus === 'saving' && '💾 Saving...'}
57
+ {saveStatus === 'saved' && '✅ Saved successfully'}
58
+ {saveStatus === 'error' && '❌ Failed to save'}
59
+ </div>
60
+ )}
61
+ <div className="flex-1">
62
+ <BookEditor value={agentSource} onChange={handleChange} />
63
+ </div>
64
+ </div>
65
+ );
66
+ }
67
+
68
+ /**
69
+ * TODO: [🚗] Transfer the saving logic to `<BookEditor/>` be aware of CRDT / yjs approach to be implementable in future
70
+ * TODO: !!! Implement debouncing for auto-save
71
+ * TODO: !!! Add error handling and retry logic
72
+ * TODO: !!! Show save status indicator
73
+ * TODO: !!!!! Add file upload capability
74
+ */
@@ -0,0 +1,21 @@
1
+ 'use server';
2
+
3
+ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
4
+ import { headers } from 'next/headers';
5
+ import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
6
+ import { BookEditorWrapper } from './BookEditorWrapper';
7
+
8
+ export default async function AgentPage({ params }: { params: Promise<{ agentName: string }> }) {
9
+ $sideEffect(headers());
10
+
11
+ const { agentName } = await params;
12
+ const collection = await $provideAgentCollectionForServer();
13
+ const agentSourceSubject = await collection.getAgentSource(decodeURIComponent(agentName));
14
+ const agentSource = agentSourceSubject.getValue();
15
+
16
+ return <BookEditorWrapper agentName={agentName} initialAgentSource={agentSource} />;
17
+ }
18
+
19
+ /**
20
+ * TODO: [🚗] Components and pages here should be just tiny UI wrapper around proper agent logic and components
21
+ */
@@ -26,6 +26,7 @@ export default async function AgentPage({ params }: { params: Promise<{ agentNam
26
26
 
27
27
  // Build agent page URL for QR and copy
28
28
  const pageUrl = `https://s6.ptbk.io/agents/${encodeURIComponent(agentName)}`;
29
+ // <- TODO: !!! Better
29
30
 
30
31
  // Extract brand color from meta
31
32
  const brandColor = agentProfile.meta.color || '#3b82f6'; // Default to blue-600
@@ -124,13 +125,15 @@ export default async function AgentPage({ params }: { params: Promise<{ agentNam
124
125
  </div>
125
126
  <div className="flex gap-4 mt-6">
126
127
  <a
127
- href="#"
128
+ href={`${pageUrl}/chat`}
129
+ // <- !!!! Can I append path like this on current browser URL in href?
128
130
  className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded shadow font-semibold transition"
129
131
  >
130
132
  💬 Chat
131
133
  </a>
132
134
  <a
133
- href="#"
135
+ href={`${pageUrl}/book`}
136
+ // <- !!!! Can I append path like this on current browser URL in href?
134
137
  className="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded shadow font-semibold transition"
135
138
  >
136
139
  ✏️ Edit Agent Book
@@ -151,5 +154,7 @@ export default async function AgentPage({ params }: { params: Promise<{ agentNam
151
154
  }
152
155
 
153
156
  /**
157
+ * TODO: !!! Make this page look nice - 🃏
158
+ * TODO: !!! Show usage of LLM
154
159
  * TODO: [🚗] Components and pages here should be just tiny UI wraper around proper agent logic and conponents
155
160
  */
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-45';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-46';
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
@@ -3947,6 +3947,8 @@ function checkExpectations(expectations, value) {
3947
3947
  * This function provides a common abstraction for result validation that can be used
3948
3948
  * by both execution logic and caching logic to ensure consistency.
3949
3949
  *
3950
+ * Note: [🔂] This function is idempotent.
3951
+ *
3950
3952
  * @param options - The validation options including result string, expectations, and format
3951
3953
  * @returns Validation result with processed string and validity status
3952
3954
  * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
@@ -5714,6 +5716,8 @@ function isValidPipelineUrl(url) {
5714
5716
  * - if it is valid json
5715
5717
  * - if it is meaningful
5716
5718
  *
5719
+ * Note: [🔂] This function is idempotent.
5720
+ *
5717
5721
  * @param pipeline valid or invalid PipelineJson
5718
5722
  * @returns the same pipeline if it is logically valid
5719
5723
  * @throws {PipelineLogicError} on logical error in the pipeline
@@ -6030,6 +6034,8 @@ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"
6030
6034
  * Function `validatePipelineString` will validate the if the string is a valid pipeline string
6031
6035
  * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
6032
6036
  *
6037
+ * Note: [🔂] This function is idempotent.
6038
+ *
6033
6039
  * @param {string} pipelineString the candidate for a pipeline string
6034
6040
  * @returns {PipelineString} the same string as input, but validated as valid
6035
6041
  * @throws {ParseError} if the string is not a valid pipeline string
@@ -10086,6 +10092,8 @@ function removeQuotes(text) {
10086
10092
  * Function `validateParameterName` will normalize and validate a parameter name for use in pipelines.
10087
10093
  * It removes diacritics, emojis, and quotes, normalizes to camelCase, and checks for reserved names and invalid characters.
10088
10094
  *
10095
+ * Note: [🔂] This function is idempotent.
10096
+ *
10089
10097
  * @param parameterName The parameter name to validate and normalize.
10090
10098
  * @returns The validated and normalized parameter name.
10091
10099
  * @throws {ParseError} If the parameter name is empty, reserved, or contains invalid characters.
@@ -12066,6 +12074,8 @@ const PADDING_LINES = 11;
12066
12074
  /**
12067
12075
  * A function that adds padding to the book content
12068
12076
  *
12077
+ * Note: [🔂] This function is idempotent.
12078
+ *
12069
12079
  * @public exported from `@promptbook/core`
12070
12080
  */
12071
12081
  function padBook(content) {
@@ -15061,6 +15071,33 @@ function $initializeRunCommand(program) {
15061
15071
  * TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
15062
15072
  */
15063
15073
 
15074
+ /**
15075
+ * !!!!!
15076
+ * Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
15077
+ *
15078
+ * You can simply use `RemoteExecutionTools` on client-side javascript and connect to your remote server.
15079
+ * This is useful to make all logic on browser side but not expose your API keys or no need to use customer's GPU.
15080
+ *
15081
+ * @see https://github.com/webgptorg/promptbook#remote-server
15082
+ * @public exported from `@promptbook/remote-server`
15083
+ * <- TODO: !!!! Maybe change to `@promptbook/agent-server`
15084
+ */
15085
+ async function startAgentServer(options) {
15086
+ const { port = 4440 } = options;
15087
+ // TODO: !!!! [🌕]
15088
+ console.trace(`!!! Starting agents server on port ${port}...`);
15089
+ console.log(`!!! cwd`, process.cwd());
15090
+ console.log(`!!! __dirname`, __dirname);
15091
+ await $execCommand({
15092
+ cwd: './apps/agents-server',
15093
+ command: `next dev --port ${port} `,
15094
+ isVerbose: true,
15095
+ });
15096
+ }
15097
+ /**
15098
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
15099
+ */
15100
+
15064
15101
  /**
15065
15102
  * Initializes `start-agents-server` command for Promptbook CLI utilities
15066
15103
  *
@@ -15140,11 +15177,7 @@ function $initializeStartAgentsServerCommand(program) {
15140
15177
  isVerbose: true,
15141
15178
  });
15142
15179
  */
15143
- await $execCommand({
15144
- cwd: './apps/agents-server',
15145
- command: `next dev --port ${port} `,
15146
- isVerbose: true,
15147
- });
15180
+ await startAgentServer({ port });
15148
15181
  }));
15149
15182
  }
15150
15183
  /**