@promptbook/cli 0.103.0-55 → 0.103.0-56

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 (61) hide show
  1. package/apps/agents-server/package-lock.json +1163 -0
  2. package/apps/agents-server/package.json +6 -0
  3. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +3 -1
  4. package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +216 -0
  5. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +78 -0
  6. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileView.tsx +233 -0
  7. package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +4 -4
  8. package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +2 -2
  9. package/apps/agents-server/src/app/agents/[agentName]/QrCodeModal.tsx +90 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +80 -0
  11. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +3 -1
  12. package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +11 -1
  13. package/apps/agents-server/src/app/agents/[agentName]/api/openai/models/route.ts +93 -0
  14. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/chat/completions/route.ts +10 -0
  15. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/models/route.ts +93 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +4 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +9 -2
  18. package/apps/agents-server/src/app/agents/[agentName]/integration/SdkCodeTabs.tsx +31 -0
  19. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +271 -30
  20. package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +61 -97
  21. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +108 -165
  22. package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +61 -0
  23. package/apps/agents-server/src/app/api/openai/v1/chat/completions/route.ts +6 -0
  24. package/apps/agents-server/src/app/api/openai/v1/models/route.ts +65 -0
  25. package/apps/agents-server/src/app/docs/[docId]/page.tsx +12 -32
  26. package/apps/agents-server/src/app/docs/page.tsx +42 -17
  27. package/apps/agents-server/src/app/globals.css +129 -0
  28. package/apps/agents-server/src/app/layout.tsx +8 -2
  29. package/apps/agents-server/src/app/manifest.ts +1 -1
  30. package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +87 -0
  31. package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +20 -0
  32. package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +18 -0
  33. package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +18 -0
  34. package/apps/agents-server/src/database/migrations/2025-12-0070-chat-history-source.sql +2 -0
  35. package/apps/agents-server/src/database/schema.ts +6 -0
  36. package/apps/agents-server/src/utils/handleChatCompletion.ts +186 -14
  37. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +13 -6
  38. package/apps/agents-server/src/utils/validateApiKey.ts +128 -0
  39. package/apps/agents-server/tailwind.config.ts +1 -1
  40. package/esm/index.es.js +865 -441
  41. package/esm/index.es.js.map +1 -1
  42. package/esm/typings/src/_packages/core.index.d.ts +6 -8
  43. package/esm/typings/src/_packages/types.index.d.ts +1 -1
  44. package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
  45. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +6 -0
  46. package/esm/typings/src/commitments/META_FONT/META_FONT.d.ts +42 -0
  47. package/esm/typings/src/commitments/USE/USE.d.ts +53 -0
  48. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.d.ts +38 -0
  49. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.test.d.ts +1 -0
  50. package/esm/typings/src/commitments/{IMPORTANT/IMPORTANT.d.ts → USE_MCP/USE_MCP.d.ts} +16 -5
  51. package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +38 -0
  52. package/esm/typings/src/commitments/index.d.ts +93 -1
  53. package/esm/typings/src/playground/playground.d.ts +3 -0
  54. package/esm/typings/src/utils/color/Color.d.ts +8 -0
  55. package/esm/typings/src/utils/color/css-colors.d.ts +1 -0
  56. package/esm/typings/src/version.d.ts +1 -1
  57. package/package.json +1 -1
  58. package/umd/index.umd.js +861 -437
  59. package/umd/index.umd.js.map +1 -1
  60. package/esm/typings/src/commitments/registry.d.ts +0 -68
  61. package/esm/typings/src/playground/playground1.d.ts +0 -2
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+
3
+ import { AgentBasicInformation } from '@promptbook-local/types';
4
+ import { XIcon } from 'lucide-react';
5
+ import { useEffect } from 'react';
6
+ import { AgentQrCode } from './AgentQrCode';
7
+
8
+ type QrCodeModalProps = {
9
+ isOpen: boolean;
10
+ onClose: () => void;
11
+ agentName: string;
12
+ meta: AgentBasicInformation['meta'];
13
+ personaDescription: string;
14
+ agentUrl: string;
15
+ agentEmail: string;
16
+ brandColorHex: string;
17
+ };
18
+
19
+ export function QrCodeModal({
20
+ isOpen,
21
+ onClose,
22
+ agentName,
23
+ meta,
24
+ personaDescription,
25
+ agentUrl,
26
+ agentEmail,
27
+ brandColorHex,
28
+ }: QrCodeModalProps) {
29
+ useEffect(() => {
30
+ if (isOpen) {
31
+ document.body.style.overflow = 'hidden';
32
+ } else {
33
+ document.body.style.overflow = '';
34
+ }
35
+ return () => {
36
+ document.body.style.overflow = '';
37
+ };
38
+ }, [isOpen]);
39
+
40
+ useEffect(() => {
41
+ function handleEscape(event: KeyboardEvent) {
42
+ if (event.key === 'Escape') {
43
+ onClose();
44
+ }
45
+ }
46
+
47
+ if (isOpen) {
48
+ document.addEventListener('keydown', handleEscape);
49
+ }
50
+ return () => document.removeEventListener('keydown', handleEscape);
51
+ }, [isOpen, onClose]);
52
+
53
+ if (!isOpen) return null;
54
+
55
+ return (
56
+ <div
57
+ className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm"
58
+ onClick={onClose}
59
+ >
60
+ <div
61
+ className="relative bg-white rounded-2xl shadow-2xl p-8 max-w-sm w-full mx-4 animate-in zoom-in-95 duration-200"
62
+ onClick={(e) => e.stopPropagation()}
63
+ >
64
+ <button
65
+ onClick={onClose}
66
+ className="absolute top-4 right-4 p-2 rounded-full hover:bg-gray-100 transition-colors"
67
+ aria-label="Close"
68
+ >
69
+ <XIcon className="w-5 h-5 text-gray-500" />
70
+ </button>
71
+
72
+ <h3 className="text-xl font-semibold text-gray-900 mb-6 text-center">Scan to Chat</h3>
73
+
74
+ <div className="flex justify-center">
75
+ <AgentQrCode
76
+ agentName={agentName}
77
+ meta={meta}
78
+ personaDescription={personaDescription}
79
+ agentUrl={agentUrl}
80
+ agentEmail={agentEmail}
81
+ />
82
+ </div>
83
+
84
+ <p className="mt-6 text-sm text-gray-500 text-center">
85
+ Scan this QR code to start chatting with {(meta.fullname as string) || agentName}
86
+ </p>
87
+ </div>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,80 @@
1
+ import {
2
+ BookOpenIcon,
3
+ CodeIcon,
4
+ GlobeIcon,
5
+ HistoryIcon,
6
+ LinkIcon,
7
+ MessageSquareIcon,
8
+ NotebookPenIcon,
9
+ } from 'lucide-react';
10
+ import type { ComponentType } from 'react';
11
+
12
+ type AgentLink = {
13
+ title: string;
14
+ href: string;
15
+ icon: ComponentType<{ className?: string }>;
16
+ description?: string;
17
+ target?: '_blank' | '_self';
18
+ rel?: string;
19
+ };
20
+
21
+ export const getAgentLinks = (agentName: string): AgentLink[] => {
22
+ const encodedName = encodeURIComponent(agentName);
23
+ return [
24
+ {
25
+ title: 'Chat with Agent',
26
+ href: `/agents/${encodedName}`,
27
+ icon: MessageSquareIcon,
28
+ description: 'Direct interface to converse with the agent.',
29
+ },
30
+ {
31
+ title: 'Edit Book',
32
+ href: `/agents/${encodedName}/book`,
33
+ icon: NotebookPenIcon,
34
+ description: "Edit the agent's knowledge book.",
35
+ },
36
+ {
37
+ title: 'Integration',
38
+ href: `/agents/${encodedName}/integration`,
39
+ icon: CodeIcon,
40
+ description: 'Learn how to integrate this agent into your applications.',
41
+ },
42
+ {
43
+ title: 'History & Feedback',
44
+ href: `/agents/${encodedName}/history`,
45
+ icon: HistoryIcon,
46
+ description: 'View past conversations and provide feedback.',
47
+ },
48
+ {
49
+ title: 'All Links',
50
+ href: `/agents/${encodedName}/links`,
51
+ icon: LinkIcon,
52
+ description: 'Signpost & Links',
53
+ },
54
+ {
55
+ title: 'Website Integration',
56
+ href: `/agents/${encodedName}/website-integration`,
57
+ icon: GlobeIcon,
58
+ description: 'Embed the agent chat widget directly into your React application.',
59
+ },
60
+ ];
61
+ };
62
+
63
+ export const getAgentExternalLinks = (): AgentLink[] => [
64
+ {
65
+ title: 'Promptbook Studio',
66
+ href: 'https://promptbook.studio',
67
+ icon: BookOpenIcon,
68
+ description: 'Create and manage your own agents',
69
+ target: '_blank',
70
+ rel: 'noopener noreferrer',
71
+ },
72
+ {
73
+ title: 'GitHub Repository',
74
+ href: 'https://github.com/webgptorg/promptbook',
75
+ icon: CodeIcon,
76
+ description: 'Star us and contribute to the project',
77
+ target: '_blank',
78
+ rel: 'noopener noreferrer',
79
+ },
80
+ ];
@@ -1,4 +1,5 @@
1
1
  import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
2
+ import { resolveInheritedAgentSource } from '@/src/utils/resolveInheritedAgentSource';
2
3
  import { padBook, validateBook } from '@promptbook-local/core';
3
4
  import { serializeError } from '@promptbook-local/utils';
4
5
  import spaceTrim from 'spacetrim';
@@ -13,8 +14,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
13
14
  try {
14
15
  const collection = await $provideAgentCollectionForServer();
15
16
  const agentSource = await collection.getAgentSource(agentName);
17
+ const effectiveAgentSource = await resolveInheritedAgentSource(agentSource, collection);
16
18
 
17
- return new Response(agentSource, {
19
+ return new Response(effectiveAgentSource, {
18
20
  status: 200,
19
21
  headers: { 'Content-Type': 'text/plain' /* <- TODO: [🎳] Mime type of book */ },
20
22
  });
@@ -77,11 +77,15 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
77
77
  userAgent,
78
78
  language,
79
79
  platform,
80
+ source: 'AGENT_PAGE_CHAT',
81
+ apiKey: null,
80
82
  });
81
83
 
82
84
  const encoder = new TextEncoder();
83
85
  const readableStream = new ReadableStream({
84
86
  start(controller) {
87
+ let previousContent = '';
88
+
85
89
  agent.callChatModelStream!(
86
90
  {
87
91
  title: `Chat with agent ${
@@ -95,7 +99,11 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
95
99
  thread,
96
100
  },
97
101
  (chunk) => {
98
- controller.enqueue(encoder.encode(chunk.content));
102
+ const fullContent = chunk.content;
103
+ const deltaContent = fullContent.substring(previousContent.length);
104
+ previousContent = fullContent;
105
+
106
+ controller.enqueue(encoder.encode(deltaContent));
99
107
  },
100
108
  )
101
109
  .then(async (response) => {
@@ -119,6 +127,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
119
127
  userAgent,
120
128
  language,
121
129
  platform,
130
+ source: 'AGENT_PAGE_CHAT',
131
+ apiKey: null,
122
132
  });
123
133
 
124
134
  // Note: [🐱‍🚀] Save the learned data
@@ -0,0 +1,93 @@
1
+ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
2
+ import { validateApiKey } from '@/src/utils/validateApiKey';
3
+ import { NextRequest, NextResponse } from 'next/server';
4
+
5
+ /**
6
+ * GET /agents/[agentName]/api/openai/models
7
+ *
8
+ * Lists available models for the OpenAI-compatible API.
9
+ * This endpoint is required for OpenAI-compatible clients (like Jan, LM Studio, etc.)
10
+ * to discover available models.
11
+ */
12
+ export async function GET(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
13
+ const { agentName } = await params;
14
+
15
+ // Validate API key explicitly (in addition to middleware)
16
+ const apiKeyValidation = await validateApiKey(request);
17
+ if (!apiKeyValidation.isValid) {
18
+ return NextResponse.json(
19
+ {
20
+ error: {
21
+ message: apiKeyValidation.error || 'Invalid API key',
22
+ type: 'authentication_error',
23
+ },
24
+ },
25
+ { status: 401 },
26
+ );
27
+ }
28
+
29
+ try {
30
+ const collection = await $provideAgentCollectionForServer();
31
+
32
+ let agentSource;
33
+ try {
34
+ agentSource = await collection.getAgentSource(agentName);
35
+ } catch (error) {
36
+ return NextResponse.json(
37
+ { error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
38
+ { status: 404 },
39
+ );
40
+ }
41
+
42
+ if (!agentSource) {
43
+ return NextResponse.json(
44
+ { error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
45
+ { status: 404 },
46
+ );
47
+ }
48
+
49
+ // Return the agent as a single model in OpenAI format
50
+ // The model ID is the agent name, which clients will use when making chat completion requests
51
+ const models = [
52
+ {
53
+ id: agentName,
54
+ object: 'model',
55
+ created: Math.floor(Date.now() / 1000),
56
+ owned_by: 'promptbook',
57
+ permission: [
58
+ {
59
+ id: `modelperm-${agentName}`,
60
+ object: 'model_permission',
61
+ created: Math.floor(Date.now() / 1000),
62
+ allow_create_engine: false,
63
+ allow_sampling: true,
64
+ allow_logprobs: false,
65
+ allow_search_indices: false,
66
+ allow_view: true,
67
+ allow_fine_tuning: false,
68
+ organization: '*',
69
+ group: null,
70
+ is_blocking: false,
71
+ },
72
+ ],
73
+ root: agentName,
74
+ parent: null,
75
+ },
76
+ ];
77
+
78
+ return NextResponse.json({
79
+ object: 'list',
80
+ data: models,
81
+ });
82
+ } catch (error) {
83
+ console.error('Error in models listing handler:', error);
84
+ return NextResponse.json(
85
+ { error: { message: (error as Error).message || 'Internal Server Error', type: 'server_error' } },
86
+ { status: 500 },
87
+ );
88
+ }
89
+ }
90
+
91
+ /**
92
+ * TODO: [🧠] Consider listing all available agents as models when agentName is a wildcard or special value
93
+ */
@@ -0,0 +1,10 @@
1
+ import { handleChatCompletion } from '@/src/utils/handleChatCompletion';
2
+ import { NextRequest } from 'next/server';
3
+
4
+ export async function POST(
5
+ request: NextRequest,
6
+ { params }: { params: Promise<{ agentName: string }> },
7
+ ) {
8
+ const { agentName } = await params;
9
+ return handleChatCompletion(request, { agentName }, 'OpenAI API Chat Completion');
10
+ }
@@ -0,0 +1,93 @@
1
+ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
2
+ import { validateApiKey } from '@/src/utils/validateApiKey';
3
+ import { NextRequest, NextResponse } from 'next/server';
4
+
5
+ /**
6
+ * GET /agents/[agentName]/api/openai/v1/models
7
+ *
8
+ * Lists available models for the OpenAI-compatible API.
9
+ * This endpoint is required for OpenAI-compatible clients (like Jan, LM Studio, etc.)
10
+ * to discover available models.
11
+ */
12
+ export async function GET(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
13
+ const { agentName } = await params;
14
+
15
+ // Validate API key explicitly (in addition to middleware)
16
+ const apiKeyValidation = await validateApiKey(request);
17
+ if (!apiKeyValidation.isValid) {
18
+ return NextResponse.json(
19
+ {
20
+ error: {
21
+ message: apiKeyValidation.error || 'Invalid API key',
22
+ type: 'authentication_error',
23
+ },
24
+ },
25
+ { status: 401 },
26
+ );
27
+ }
28
+
29
+ try {
30
+ const collection = await $provideAgentCollectionForServer();
31
+
32
+ let agentSource;
33
+ try {
34
+ agentSource = await collection.getAgentSource(agentName);
35
+ } catch (error) {
36
+ return NextResponse.json(
37
+ { error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
38
+ { status: 404 },
39
+ );
40
+ }
41
+
42
+ if (!agentSource) {
43
+ return NextResponse.json(
44
+ { error: { message: `Agent '${agentName}' not found.`, type: 'invalid_request_error' } },
45
+ { status: 404 },
46
+ );
47
+ }
48
+
49
+ // Return the agent as a single model in OpenAI format
50
+ // The model ID is the agent name, which clients will use when making chat completion requests
51
+ const models = [
52
+ {
53
+ id: agentName,
54
+ object: 'model',
55
+ created: Math.floor(Date.now() / 1000),
56
+ owned_by: 'promptbook',
57
+ permission: [
58
+ {
59
+ id: `modelperm-${agentName}`,
60
+ object: 'model_permission',
61
+ created: Math.floor(Date.now() / 1000),
62
+ allow_create_engine: false,
63
+ allow_sampling: true,
64
+ allow_logprobs: false,
65
+ allow_search_indices: false,
66
+ allow_view: true,
67
+ allow_fine_tuning: false,
68
+ organization: '*',
69
+ group: null,
70
+ is_blocking: false,
71
+ },
72
+ ],
73
+ root: agentName,
74
+ parent: null,
75
+ },
76
+ ];
77
+
78
+ return NextResponse.json({
79
+ object: 'list',
80
+ data: models,
81
+ });
82
+ } catch (error) {
83
+ console.error('Error in models listing handler:', error);
84
+ return NextResponse.json(
85
+ { error: { message: (error as Error).message || 'Internal Server Error', type: 'server_error' } },
86
+ { status: 500 },
87
+ );
88
+ }
89
+ }
90
+
91
+ /**
92
+ * TODO: [🧠] Consider listing all available agents as models when agentName is a wildcard or special value
93
+ */
@@ -98,6 +98,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
98
98
  userAgent,
99
99
  language,
100
100
  platform,
101
+ source: 'AGENT_PAGE_CHAT',
102
+ apiKey: null,
101
103
  });
102
104
 
103
105
  // Call Agent
@@ -131,6 +133,8 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
131
133
  userAgent,
132
134
  language,
133
135
  platform,
136
+ source: 'AGENT_PAGE_CHAT',
137
+ apiKey: null,
134
138
  });
135
139
 
136
140
  // Learning
@@ -7,16 +7,23 @@ import { AgentChatWrapper } from '../AgentChatWrapper';
7
7
 
8
8
  export const generateMetadata = generateAgentMetadata;
9
9
 
10
- export default async function AgentChatPage({ params }: { params: Promise<{ agentName: string }> }) {
10
+ export default async function AgentChatPage({
11
+ params,
12
+ searchParams,
13
+ }: {
14
+ params: Promise<{ agentName: string }>;
15
+ searchParams: Promise<{ message?: string }>;
16
+ }) {
11
17
  $sideEffect(headers());
12
18
  let { agentName } = await params;
13
19
  agentName = decodeURIComponent(agentName);
20
+ const { message } = await searchParams;
14
21
 
15
22
  const agentUrl = `/agents/${agentName}`;
16
23
 
17
24
  return (
18
25
  <main className={`w-screen h-screen`}>
19
- <AgentChatWrapper agentUrl={agentUrl} />
26
+ <AgentChatWrapper agentUrl={agentUrl} autoExecuteMessage={message} />
20
27
  </main>
21
28
  );
22
29
  }
@@ -0,0 +1,31 @@
1
+ 'use client';
2
+
3
+ import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
4
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../../../_common/components/Tabs/Tabs';
5
+
6
+ type SdkCodeTabsProps = {
7
+ curlCode: string;
8
+ pythonCode: string;
9
+ jsCode: string;
10
+ };
11
+
12
+ export function SdkCodeTabs({ curlCode, pythonCode, jsCode }: SdkCodeTabsProps) {
13
+ return (
14
+ <Tabs defaultValue="curl" className="w-full">
15
+ <TabsList>
16
+ <TabsTrigger value="curl">cURL</TabsTrigger>
17
+ <TabsTrigger value="python">Python SDK</TabsTrigger>
18
+ <TabsTrigger value="javascript">JavaScript/TypeScript SDK</TabsTrigger>
19
+ </TabsList>
20
+ <TabsContent value="curl">
21
+ <CodePreview code={curlCode} language="bash" />
22
+ </TabsContent>
23
+ <TabsContent value="python">
24
+ <CodePreview code={pythonCode} language="python" />
25
+ </TabsContent>
26
+ <TabsContent value="javascript">
27
+ <CodePreview code={jsCode} language="typescript" />
28
+ </TabsContent>
29
+ </Tabs>
30
+ );
31
+ }