@promptbook/cli 0.104.0-5 โ†’ 0.104.0-7

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 (33) hide show
  1. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +3 -2
  2. package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +6 -2
  3. package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +15 -8
  4. package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
  5. package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +53 -38
  6. package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +6 -2
  7. package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
  8. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +3 -2
  9. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +3 -2
  10. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +3 -2
  11. package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +3 -2
  12. package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +10 -2
  13. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +8 -4
  14. package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +3 -1
  15. package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
  16. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +11 -2
  17. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +3 -1
  18. package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
  19. package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
  20. package/esm/index.es.js +8 -51
  21. package/esm/index.es.js.map +1 -1
  22. package/esm/typings/servers.d.ts +8 -0
  23. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  24. package/esm/typings/src/_packages/types.index.d.ts +2 -0
  25. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
  26. package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
  27. package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
  28. package/esm/typings/src/types/typeAliases.d.ts +11 -1
  29. package/esm/typings/src/version.d.ts +1 -1
  30. package/package.json +1 -1
  31. package/umd/index.umd.js +8 -51
  32. package/umd/index.umd.js.map +1 -1
  33. package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
@@ -8,6 +8,8 @@ import { notFound } from 'next/navigation';
8
8
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
9
9
  import { getAgentName, getAgentProfile } from '../_utils';
10
10
  import { generateAgentMetadata } from '../generateAgentMetadata';
11
+ import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
12
+ import { NEXT_PUBLIC_SITE_URL } from '@/config';
11
13
 
12
14
  export const generateMetadata = generateAgentMetadata;
13
15
 
@@ -44,7 +46,7 @@ export default async function AgentSystemMessagePage({ params }: { params: Promi
44
46
  {agentProfile.meta.image && (
45
47
  // eslint-disable-next-line @next/next/no-img-element
46
48
  <img
47
- src={agentProfile.meta.image as string}
49
+ src={agentProfile.meta.image|| agentProfile.permanentId ||generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
48
50
  alt={agentProfile.meta.fullname || agentName}
49
51
  className="w-16 h-16 rounded-full object-cover border-2 border-gray-200"
50
52
  />
@@ -0,0 +1,48 @@
1
+ import { $getTableName } from '../../../../../database/$getTableName';
2
+ import { $provideSupabaseForServer } from '../../../../../database/$provideSupabaseForServer';
3
+ import { parseInboundSendgridEmail } from '../../../../../message-providers/email/sendgrid/parseInboundSendgridEmail';
4
+ import { NextRequest, NextResponse } from 'next/server';
5
+
6
+ export async function POST(request: NextRequest) {
7
+ try {
8
+ const formData = await request.formData();
9
+ const rawEmail = formData.get('email');
10
+
11
+ if (typeof rawEmail !== 'string') {
12
+ return NextResponse.json({ error: 'Missing email field' }, { status: 400 });
13
+ }
14
+
15
+ const email = await parseInboundSendgridEmail(rawEmail);
16
+
17
+ const supabase = await $provideSupabaseForServer();
18
+ const { error } = await supabase
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ .from(await $getTableName('Message'))
21
+ .insert({
22
+ channel: 'EMAIL',
23
+ direction: 'INBOUND',
24
+ sender: email.sender,
25
+ recipients: email.recipients,
26
+ content: email.content,
27
+ metadata: {
28
+ subject: email.subject,
29
+ cc: email.cc,
30
+ ...email.metadata,
31
+ },
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ } as any);
34
+
35
+ if (error) {
36
+ console.error('Failed to insert message', error);
37
+ return NextResponse.json({ error: error.message }, { status: 500 });
38
+ }
39
+
40
+ return NextResponse.json({ success: true });
41
+ } catch (error) {
42
+ console.error('Error processing inbound email', error);
43
+ return NextResponse.json(
44
+ { error: error instanceof Error ? error.message : 'Unknown error' },
45
+ { status: 500 },
46
+ );
47
+ }
48
+ }
@@ -1,11 +1,13 @@
1
1
  'use client';
2
2
 
3
- import { AgentBasicInformation } from '@promptbook-local/types';
3
+ import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
4
+ import { AgentBasicInformation, string_agent_permanent_id } from '@promptbook-local/types';
4
5
  import { RepeatIcon } from 'lucide-react';
5
6
  import { useState } from 'react';
6
7
  import { AgentQrCode } from './AgentQrCode';
7
8
  import { QrCodeModal } from './QrCodeModal';
8
9
  import { useAgentBackground } from './useAgentBackground';
10
+ import { NEXT_PUBLIC_SITE_URL } from '@/config';
9
11
 
10
12
  type AgentProfileProps = {
11
13
  /**
@@ -13,6 +15,11 @@ type AgentProfileProps = {
13
15
  */
14
16
  readonly agent: AgentBasicInformation;
15
17
 
18
+ /**
19
+ * The permanent ID of the agent
20
+ */
21
+ readonly permanentId: string_agent_permanent_id;
22
+
16
23
  /**
17
24
  * URL of the agent page
18
25
  *
@@ -58,16 +65,18 @@ export function AgentProfile(props: AgentProfileProps) {
58
65
  agent,
59
66
  agentUrl = '',
60
67
  agentEmail = '',
68
+ permanentId,
61
69
  renderMenu,
62
70
  children,
63
71
  actions,
64
72
  isHeadless = false,
65
73
  className,
66
74
  } = props;
75
+ console.log('!!!!', { agent });
67
76
  const { meta, agentName } = agent;
68
77
  const fullname = (meta.fullname as string) || agentName || 'Agent';
69
78
  const personaDescription = agent.personaDescription || '';
70
- const imageUrl = (meta.image as string) || null;
79
+ const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(permanentId, NEXT_PUBLIC_SITE_URL);
71
80
 
72
81
  const [isQrModalOpen, setIsQrModalOpen] = useState(false);
73
82
  const [isFlipped, setIsFlipped] = useState(false);
@@ -1,5 +1,7 @@
1
1
  'use client';
2
2
 
3
+ import { NEXT_PUBLIC_SITE_URL } from '@/config';
4
+ import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
3
5
  import { really_any } from '@promptbook-local/types';
4
6
  import { EyeIcon, EyeOffIcon, RotateCcwIcon } from 'lucide-react';
5
7
  import Link from 'next/link';
@@ -32,7 +34,7 @@ export function AgentCard({
32
34
  }: AgentCardProps) {
33
35
  const { meta, agentName } = agent;
34
36
  const fullname = (meta.fullname as string) || agentName || 'Agent';
35
- const imageUrl = (meta.image as string) || null;
37
+ const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL);
36
38
  const personaDescription = agent.personaDescription || '';
37
39
 
38
40
  const { brandColorLightHex, brandColorDarkHex, backgroundImage } = useAgentBackground(meta.color);
@@ -0,0 +1,49 @@
1
+ import { string_markdown } from '@promptbook-local/types';
2
+ import { simpleParser } from 'mailparser';
3
+ import TurndownService from 'turndown';
4
+ import { extractBodyContentFromHtml } from '../../../utils/content/extractBodyContentFromHtml';
5
+ import type { InboundEmail } from '../_common/Email';
6
+ import { parseEmailAddress } from '../_common/utils/parseEmailAddress';
7
+ import { parseEmailAddresses } from '../_common/utils/parseEmailAddresses';
8
+
9
+ /**
10
+ * Function parseInboundSendgridEmail will parse raw inbound email from Sendgrid and return Email object
11
+ */
12
+ export async function parseInboundSendgridEmail(rawEmail: string): Promise<InboundEmail> {
13
+ const parsedEmail = await simpleParser(rawEmail);
14
+
15
+ const toArray = !Array.isArray(parsedEmail.to)
16
+ ? parsedEmail.to === undefined
17
+ ? []
18
+ : [parsedEmail.to]
19
+ : parsedEmail.to;
20
+ const to = toArray.flatMap((_) => parseEmailAddresses(_.text));
21
+
22
+ const ccArray = !Array.isArray(parsedEmail.cc)
23
+ ? parsedEmail.cc === undefined
24
+ ? []
25
+ : [parsedEmail.cc]
26
+ : parsedEmail.cc;
27
+ const cc = ccArray.flatMap((_) => parseEmailAddresses(_.text));
28
+
29
+ const turndownService = new TurndownService();
30
+
31
+ const content = (parsedEmail.html
32
+ ? turndownService.turndown(extractBodyContentFromHtml(parsedEmail.html))
33
+ : parsedEmail.text || '') as string_markdown;
34
+
35
+ const email: InboundEmail = {
36
+ channel: 'EMAIL',
37
+ direction: 'INBOUND',
38
+ sender: parseEmailAddress(parsedEmail.from?.text || '').fullEmail,
39
+ recipients: to.map((_) => _.fullEmail),
40
+ cc,
41
+ subject: parsedEmail.subject || '',
42
+ content,
43
+ attachments: [
44
+ /* <- TODO: [๐Ÿ“ฏ] Parse attachments */
45
+ ],
46
+ };
47
+
48
+ return email;
49
+ }
@@ -0,0 +1,19 @@
1
+ import type { string_html } from '@promptbook-local/types';
2
+
3
+ /**
4
+ * Extract the first heading from HTML
5
+ *
6
+ * @param contentText HTML
7
+ * @returns heading
8
+ */
9
+ export function extractBodyContentFromHtml(html: string_html): string_html {
10
+ // Note: Not using DOMParser, because it's overkill for this simple task
11
+
12
+ const match = html.match(/<body[^>]*>(?<bodyContent>[\s\S]*)<\/body>/s);
13
+
14
+ if (!match) {
15
+ return html;
16
+ }
17
+
18
+ return match.groups!.bodyContent!;
19
+ }
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.104.0-5';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-7';
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
@@ -57,6 +57,8 @@ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-5';
57
57
  * Core Promptbook server configuration.
58
58
  *
59
59
  * This server is also used for auto-federation in the Agents Server.
60
+ *
61
+ * @public exported from `@promptbook/core`
60
62
  */
61
63
  const CORE_SERVER = {
62
64
  title: 'Promptbook Core',
@@ -11402,11 +11404,7 @@ const modelCommandParser = {
11402
11404
  // TODO: [๐Ÿšœ] DRY
11403
11405
  if ($taskJson.modelRequirements[command.key] !== undefined) {
11404
11406
  if ($taskJson.modelRequirements[command.key] === command.value) {
11405
- console.warn(`Multiple commands \`MODEL ${{
11406
- modelName: 'NAME',
11407
- modelVariant: 'VARIANT',
11408
- maxTokens: '???',
11409
- }[command.key]} ${command.value}\` in the task "${$taskJson.title || $taskJson.name}"`);
11407
+ console.warn(`Multiple commands \`MODEL ${command.key} ${command.value}\` in the task "${$taskJson.title || $taskJson.name}"`);
11410
11408
  // <- TODO: [๐Ÿฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
11411
11409
  }
11412
11410
  else {
@@ -19892,13 +19890,14 @@ class OpenAiCompatibleExecutionTools {
19892
19890
  const modelName = currentModelRequirements.modelName || this.getDefaultImageGenerationModel().modelName;
19893
19891
  const modelSettings = {
19894
19892
  model: modelName,
19895
- // size: currentModelRequirements.size,
19896
- // quality: currentModelRequirements.quality,
19897
- // style: currentModelRequirements.style,
19893
+ size: currentModelRequirements.size,
19894
+ quality: currentModelRequirements.quality,
19895
+ style: currentModelRequirements.style,
19898
19896
  };
19899
19897
  const rawPromptContent = templateParameters(content, { ...parameters, modelName });
19900
19898
  const rawRequest = {
19901
19899
  ...modelSettings,
19900
+ size: modelSettings.size || '1024x1024',
19902
19901
  prompt: rawPromptContent,
19903
19902
  user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
19904
19903
  response_format: 'url', // TODO: [๐Ÿง ] Maybe allow b64_json
@@ -26463,44 +26462,6 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
26463
26462
  };
26464
26463
  }
26465
26464
 
26466
- /**
26467
- * Generates a gravatar URL based on agent name for fallback avatar
26468
- *
26469
- * @param agentName The agent name to generate avatar for
26470
- * @returns Gravatar URL
26471
- *
26472
- * @private - [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
26473
- */
26474
- function generateGravatarUrl(agentName) {
26475
- // Use a default name if none provided
26476
- const safeName = agentName || 'Anonymous Agent';
26477
- // Create a simple hash from the name for consistent avatar
26478
- let hash = 0;
26479
- for (let i = 0; i < safeName.length; i++) {
26480
- const char = safeName.charCodeAt(i);
26481
- hash = (hash << 5) - hash + char;
26482
- hash = hash & hash; // Convert to 32bit integer
26483
- }
26484
- const avatarId = Math.abs(hash).toString();
26485
- return `https://www.gravatar.com/avatar/${avatarId}?default=robohash&size=200&rating=x`;
26486
- }
26487
-
26488
- /**
26489
- * Generates an image for the agent to use as profile image
26490
- *
26491
- * @param agentName The agent name to generate avatar for
26492
- * @returns The placeholder profile image URL for the agent
26493
- *
26494
- * @public exported from `@promptbook/core`
26495
- */
26496
- function generatePlaceholderAgentProfileImageUrl(agentName) {
26497
- // Note: [๐Ÿคน] The fact that profile image is Gravatar is just implementation detail which should be hidden for consumer
26498
- return generateGravatarUrl(agentName);
26499
- }
26500
- /**
26501
- * TODO: [๐Ÿคน] Figure out best placeholder image generator https://i.pravatar.cc/1000?u=568
26502
- */
26503
-
26504
26465
  /**
26505
26466
  * Computes SHA-256 hash of the agent source
26506
26467
  *
@@ -26598,10 +26559,6 @@ function parseAgentSource(agentSource) {
26598
26559
  const metaType = normalizeTo_camelCase(metaTypeRaw);
26599
26560
  meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
26600
26561
  }
26601
- // Generate gravatar fallback if no meta image specified
26602
- if (!meta.image) {
26603
- meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
26604
- }
26605
26562
  // Generate fullname fallback if no meta fullname specified
26606
26563
  if (!meta.fullname) {
26607
26564
  meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);