@promptbook/cli 0.112.0-126 → 0.112.0-127

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 (190) hide show
  1. package/README.md +5 -5
  2. package/apps/agents-server/README.md +3 -0
  3. package/apps/agents-server/playwright.config.ts +1 -0
  4. package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
  5. package/apps/agents-server/public/promptbook-logo-white.png +0 -0
  6. package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
  7. package/apps/agents-server/src/app/actions.ts +2 -2
  8. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
  9. package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
  11. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
  12. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
  13. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
  14. package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
  15. package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
  16. package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
  17. package/apps/agents-server/src/app/globals.css +78 -0
  18. package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
  19. package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
  20. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
  21. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
  22. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
  23. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
  24. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
  25. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
  26. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
  27. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
  28. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
  29. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
  30. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
  31. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
  32. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
  33. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
  34. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
  35. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
  36. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
  37. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
  38. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
  39. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
  40. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
  41. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
  42. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
  43. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
  44. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
  45. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
  46. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
  47. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
  48. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
  49. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
  50. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
  51. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
  52. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
  53. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
  54. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
  55. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
  56. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
  57. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
  58. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
  59. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
  60. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
  61. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
  62. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
  63. package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
  64. package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
  65. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
  66. package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
  67. package/apps/agents-server/src/database/getMetadata.ts +37 -1
  68. package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
  69. package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
  70. package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
  71. package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
  72. package/apps/agents-server/src/languages/translations/english.yaml +1 -1
  73. package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
  74. package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
  75. package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
  76. package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
  77. package/apps/agents-server/src/utils/session.ts +62 -5
  78. package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
  79. package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
  80. package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
  81. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
  82. package/esm/index.es.js +1052 -455
  83. package/esm/index.es.js.map +1 -1
  84. package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  85. package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  86. package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  87. package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  88. package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  89. package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  90. package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  91. package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  92. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  93. package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  94. package/esm/src/_packages/components.index.d.ts +2 -0
  95. package/esm/src/_packages/types.index.d.ts +2 -0
  96. package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  97. package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  98. package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  99. package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  100. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  101. package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  102. package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  103. package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  104. package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  105. package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  106. package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  107. package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  108. package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  109. package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  110. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  111. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  112. package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  113. package/esm/src/version.d.ts +1 -1
  114. package/package.json +1 -1
  115. package/src/_packages/components.index.ts +2 -0
  116. package/src/_packages/types.index.ts +2 -0
  117. package/src/avatars/avatarAnimationScheduler.ts +61 -20
  118. package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
  119. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
  120. package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
  121. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
  122. package/src/book-components/Chat/Chat/Chat.tsx +4 -0
  123. package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
  124. package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
  125. package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
  126. package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
  127. package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
  128. package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
  129. package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
  130. package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
  131. package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
  132. package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
  133. package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
  134. package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
  135. package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
  136. package/src/book-components/Chat/types/ChatMessage.ts +5 -0
  137. package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
  138. package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
  139. package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
  140. package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
  141. package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
  142. package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
  143. package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
  144. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  145. package/src/cli/cli-commands/coder/run.ts +17 -20
  146. package/src/cli/cli-commands/coder/server.ts +13 -16
  147. package/src/cli/common/$deprecateCliCommand.ts +10 -1
  148. package/src/commitments/GOAL/GOAL.ts +7 -2
  149. package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
  150. package/src/commitments/TEAM/TEAM.ts +12 -1
  151. package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
  152. package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
  153. package/src/import-plugins/TextFileImportPlugin.ts +8 -1
  154. package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
  155. package/src/other/templates/getTemplatesPipelineCollection.ts +681 -837
  156. package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
  157. package/src/version.ts +2 -2
  158. package/src/versions.txt +1 -0
  159. package/umd/index.umd.js +1055 -458
  160. package/umd/index.umd.js.map +1 -1
  161. package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  162. package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  163. package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  164. package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  165. package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  166. package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  167. package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  168. package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  169. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  170. package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  171. package/umd/src/_packages/components.index.d.ts +2 -0
  172. package/umd/src/_packages/types.index.d.ts +2 -0
  173. package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  174. package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  175. package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  176. package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  177. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  178. package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  179. package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  180. package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  181. package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  182. package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  183. package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  184. package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  185. package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  186. package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  187. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  188. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  189. package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  190. package/umd/src/version.d.ts +1 -1
@@ -2,6 +2,7 @@ import { spaceTrim } from 'spacetrim';
2
2
  import type { ChatMessage } from '../../types/ChatMessage';
3
3
  import type { ChatParticipant } from '../../types/ChatParticipant';
4
4
  import { resolveCitationPreviewUrl } from '../../utils/citationHelpers';
5
+ import { parseMessageButtons } from '../../utils/parseMessageButtons';
5
6
  import { renderMarkdown } from '../../utils/renderMarkdown';
6
7
  import type { ChatSaveFormatDefinition } from '../_common/ChatSaveFormatDefinition';
7
8
  import {
@@ -30,6 +31,13 @@ const CITATION_FOOTNOTE_REFERENCE_HTML_REGEX = /<sup data-citation-footnote="(\d
30
31
  */
31
32
  export const CHAT_HTML_EXPORT_RENDER_ROOT_CLASS_NAME = 'chat-html-export-render-root';
32
33
 
34
+ /**
35
+ * Roles whose messages are aligned to the right side of the exported transcript.
36
+ *
37
+ * @private Internal helper of `htmlSaveFormatDefinition`.
38
+ */
39
+ const RIGHT_ALIGNED_SENDER_ROLES = new Set(['USER']);
40
+
33
41
  /**
34
42
  * Escapes HTML-sensitive text before embedding it into the export document.
35
43
  *
@@ -44,6 +52,43 @@ function escapeHtml(value: string | number): string {
44
52
  .replace(/'/g, '&#39;');
45
53
  }
46
54
 
55
+ /**
56
+ * Returns the first uppercase character of a display name, used for the fallback avatar glyph.
57
+ *
58
+ * @private Internal helper of `htmlSaveFormatDefinition`.
59
+ */
60
+ function getAvatarInitial(displayName: string): string {
61
+ const trimmedName = displayName.trim();
62
+ if (!trimmedName) {
63
+ return '?';
64
+ }
65
+
66
+ return Array.from(trimmedName)[0]!.toUpperCase();
67
+ }
68
+
69
+ /**
70
+ * Renders the avatar bubble shown next to one exported message.
71
+ *
72
+ * @private Internal helper of `htmlSaveFormatDefinition`.
73
+ */
74
+ function buildAvatarMarkup(participant: ChatParticipant | undefined, displayName: string, accentColor: string): string {
75
+ const avatarStyle = `background-color:${escapeHtml(accentColor)};`;
76
+
77
+ if (participant?.avatarSrc) {
78
+ return spaceTrim(`
79
+ <div class="message-avatar" aria-hidden="true" style="${avatarStyle}">
80
+ <img src="${escapeHtml(participant.avatarSrc)}" alt="" loading="lazy" />
81
+ </div>
82
+ `);
83
+ }
84
+
85
+ return spaceTrim(`
86
+ <div class="message-avatar message-avatar--initial" aria-hidden="true" style="${avatarStyle}">
87
+ <span>${escapeHtml(getAvatarInitial(displayName))}</span>
88
+ </div>
89
+ `);
90
+ }
91
+
47
92
  /**
48
93
  * Renders attachments for one exported message as a compact supporting section.
49
94
  *
@@ -113,6 +158,17 @@ function buildCitationsMarkup(message: ChatMessage): string {
113
158
  `);
114
159
  }
115
160
 
161
+ /**
162
+ * Removes quick action and quick message buttons from the markdown body before rendering.
163
+ *
164
+ * Quick buttons are interactive UI affordances and have no meaning inside a static export.
165
+ *
166
+ * @private Internal helper of `htmlSaveFormatDefinition`.
167
+ */
168
+ function stripQuickButtonsFromContent(content: ChatMessage['content']): ChatMessage['content'] {
169
+ return parseMessageButtons(content).contentWithoutButtons as ChatMessage['content'];
170
+ }
171
+
116
172
  /**
117
173
  * Converts one markdown message body to HTML with document-wide source references.
118
174
  *
@@ -122,7 +178,10 @@ function renderFootnotedMarkdown(
122
178
  message: Pick<ChatMessage, 'content' | 'citations'>,
123
179
  citationFootnotes: ChatExportCitationFootnoteRegistry,
124
180
  ): { readonly html: string; readonly renderModel: ChatExportCitationRenderModel } {
125
- const renderModel = createChatExportCitationRenderModel(citationFootnotes, message);
181
+ const renderModel = createChatExportCitationRenderModel(citationFootnotes, {
182
+ ...message,
183
+ content: stripQuickButtonsFromContent(message.content),
184
+ });
126
185
  const html = linkCitationFootnoteReferences(renderMarkdown(renderModel.content));
127
186
 
128
187
  return {
@@ -170,7 +229,49 @@ function buildReplyingToMarkup(message: ChatMessage, citationFootnotes: ChatExpo
170
229
  }
171
230
 
172
231
  /**
173
- * Renders one message card for the standalone HTML export.
232
+ * Determines whether a message bubble should sit on the right side of the transcript.
233
+ *
234
+ * @private Internal helper of `htmlSaveFormatDefinition`.
235
+ */
236
+ function isRightAlignedMessage(participant: ChatParticipant | undefined, sender: string): boolean {
237
+ if (participant?.isMe === true) {
238
+ return true;
239
+ }
240
+
241
+ return RIGHT_ALIGNED_SENDER_ROLES.has(sender.toUpperCase());
242
+ }
243
+
244
+ /**
245
+ * Detects whether a message would render with no body, attachments, or supporting metadata after sanitization.
246
+ *
247
+ * Such messages exist only to carry quick buttons in the live chat UI and add no value to a printed transcript.
248
+ *
249
+ * @private Internal helper of `htmlSaveFormatDefinition`.
250
+ */
251
+ function isMessageEmptyForExport(message: ChatMessage): boolean {
252
+ const trimmedContent = stripQuickButtonsFromContent(message.content).trim();
253
+
254
+ if (trimmedContent.length > 0) {
255
+ return false;
256
+ }
257
+
258
+ if (message.attachments && message.attachments.length > 0) {
259
+ return false;
260
+ }
261
+
262
+ if (message.citations && message.citations.length > 0) {
263
+ return false;
264
+ }
265
+
266
+ if (message.replyingTo) {
267
+ return false;
268
+ }
269
+
270
+ return true;
271
+ }
272
+
273
+ /**
274
+ * Renders one message bubble for the standalone HTML export.
174
275
  *
175
276
  * @private Internal helper of `htmlSaveFormatDefinition`.
176
277
  */
@@ -180,30 +281,35 @@ function renderMessageBlock(
180
281
  citationFootnotes: ChatExportCitationFootnoteRegistry,
181
282
  ): string {
182
283
  const sender = String(message.sender || 'SYSTEM');
183
- const upperSender = sender.toUpperCase();
284
+ const participant = participants.get(sender) ?? participants.get(sender.toUpperCase());
184
285
  const visuals = resolveChatExportParticipantVisuals(participants, sender);
185
286
  const timestamp = formatChatExportTimestamp(message.createdAt);
186
287
  const durationLabel =
187
288
  typeof message.generationDurationMs === 'number' ? `${(message.generationDurationMs / 1000).toFixed(1)}s` : '';
188
289
  const replyingToMarkup = buildReplyingToMarkup(message, citationFootnotes);
189
290
  const { html: messageBody, renderModel } = renderFootnotedMarkdown(message, citationFootnotes);
291
+ const isRightAligned = isRightAlignedMessage(participant, sender);
292
+ const avatarMarkup = buildAvatarMarkup(participant, visuals.displayName, visuals.accentColor);
293
+ const alignmentClass = isRightAligned ? 'message--mine' : 'message--theirs';
190
294
 
191
295
  return spaceTrim(`
192
- <article class="message-card" style="--message-accent:${escapeHtml(visuals.accentColor)};">
193
- <header class="message-header">
194
- <div class="message-header-main">
296
+ <article class="message ${alignmentClass}" style="--message-accent:${escapeHtml(visuals.accentColor)};">
297
+ ${avatarMarkup}
298
+ <div class="message-body">
299
+ <header class="message-meta">
195
300
  <span class="message-sender">${escapeHtml(visuals.displayName)}</span>
196
- <span class="message-role">${escapeHtml(upperSender)}</span>
301
+ ${timestamp ? `<time class="message-time">${escapeHtml(timestamp)}</time>` : ''}
302
+ </header>
303
+ <div class="message-bubble">
304
+ ${replyingToMarkup}
305
+ <div class="message-content markdown-content">
306
+ ${messageBody || '<p class="message-empty">No text provided.</p>'}
307
+ </div>
197
308
  </div>
198
- ${timestamp ? `<time class="message-time">${escapeHtml(timestamp)}</time>` : ''}
199
- </header>
200
- ${replyingToMarkup}
201
- <section class="message-content markdown-content">
202
- ${messageBody || '<p class="message-empty">No text provided.</p>'}
203
- </section>
204
- ${durationLabel ? `<p class="message-duration">Responded in ${escapeHtml(durationLabel)}</p>` : ''}
205
- ${buildAttachmentsMarkup(message)}
206
- ${renderModel.footnotes.length === 0 ? buildCitationsMarkup(message) : ''}
309
+ ${durationLabel ? `<p class="message-footnote">Responded in ${escapeHtml(durationLabel)}</p>` : ''}
310
+ ${buildAttachmentsMarkup(message)}
311
+ ${renderModel.footnotes.length === 0 ? buildCitationsMarkup(message) : ''}
312
+ </div>
207
313
  </article>
208
314
  `);
209
315
  }
@@ -284,9 +390,12 @@ export function buildChatHtml(
284
390
  const participantLookup = buildChatExportParticipantMap(participants);
285
391
  const citationFootnotes = createChatExportCitationFootnoteRegistry();
286
392
  const exportedLabel = formatChatExportTimestamp(new Date());
393
+ const messagesForExport = messages.filter((message) => !isMessageEmptyForExport(message));
287
394
  const messageMarkup =
288
- messages.length > 0
289
- ? messages.map((message) => renderMessageBlock(message, participantLookup, citationFootnotes)).join('')
395
+ messagesForExport.length > 0
396
+ ? messagesForExport
397
+ .map((message) => renderMessageBlock(message, participantLookup, citationFootnotes))
398
+ .join('')
290
399
  : '<div class="empty-state">No messages were available in this chat export.</div>';
291
400
  const documentSourcesMarkup = buildDocumentSourcesMarkup(citationFootnotes, participants);
292
401
 
@@ -301,6 +410,17 @@ export function buildChatHtml(
301
410
  <style>
302
411
  :root {
303
412
  color-scheme: light;
413
+ --chat-export-background: #f4f6fb;
414
+ --chat-export-surface: #ffffff;
415
+ --chat-export-text: #0f172a;
416
+ --chat-export-muted: #64748b;
417
+ --chat-export-soft-border: #e2e8f0;
418
+ --chat-export-bubble-theirs-bg: #ffffff;
419
+ --chat-export-bubble-theirs-text: #0f172a;
420
+ --chat-export-bubble-theirs-border: #e2e8f0;
421
+ --chat-export-bubble-mine-bg: #115EB6;
422
+ --chat-export-bubble-mine-text: #ffffff;
423
+ --chat-export-link: #0f6cbd;
304
424
  }
305
425
 
306
426
  * {
@@ -310,25 +430,27 @@ export function buildChatHtml(
310
430
  body,
311
431
  .${CHAT_HTML_EXPORT_RENDER_ROOT_CLASS_NAME} {
312
432
  margin: 0;
313
- background: #f8fafc;
314
- color: #0f172a;
315
- font-family: Inter, "Segoe UI", Arial, sans-serif;
433
+ background: var(--chat-export-background);
434
+ color: var(--chat-export-text);
435
+ font-family: Inter, "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
436
+ font-size: 15px;
437
+ line-height: 1.55;
316
438
  }
317
439
 
318
440
  a {
319
- color: #0f6cbd;
441
+ color: var(--chat-export-link);
320
442
  }
321
443
 
322
444
  .document {
323
- max-width: 860px;
445
+ max-width: 820px;
324
446
  margin: 0 auto;
325
- padding: 32px 20px 48px;
447
+ padding: 40px 24px 56px;
326
448
  }
327
449
 
328
450
  .document-header {
329
- margin-bottom: 24px;
330
- padding-bottom: 16px;
331
- border-bottom: 1px solid #e2e8f0;
451
+ margin-bottom: 28px;
452
+ padding-bottom: 18px;
453
+ border-bottom: 1px solid var(--chat-export-soft-border);
332
454
  }
333
455
 
334
456
  .document-eyebrow {
@@ -336,7 +458,7 @@ export function buildChatHtml(
336
458
  font-size: 11px;
337
459
  letter-spacing: 0.14em;
338
460
  text-transform: uppercase;
339
- color: #64748b;
461
+ color: var(--chat-export-muted);
340
462
  }
341
463
 
342
464
  .document-title {
@@ -347,89 +469,174 @@ export function buildChatHtml(
347
469
 
348
470
  .document-meta {
349
471
  margin: 10px 0 0;
350
- color: #475569;
351
- font-size: 14px;
472
+ color: var(--chat-export-muted);
473
+ font-size: 13px;
352
474
  }
353
475
 
354
476
  .message-list {
355
477
  display: flex;
356
478
  flex-direction: column;
357
- gap: 16px;
358
- }
359
-
360
- .message-card {
361
- background: #ffffff;
362
- border: 1px solid #dbe4f0;
363
- border-left-width: 4px;
364
- border-left-color: var(--message-accent, #64748b);
365
- border-radius: 14px;
366
- padding: 16px 18px;
479
+ gap: 22px;
367
480
  }
368
481
 
369
- .message-header {
482
+ .message {
370
483
  display: flex;
371
- justify-content: space-between;
372
484
  align-items: flex-start;
373
485
  gap: 12px;
374
- margin-bottom: 12px;
375
486
  }
376
487
 
377
- .message-header-main {
488
+ .message--mine {
489
+ flex-direction: row-reverse;
490
+ }
491
+
492
+ .message-avatar {
493
+ flex-shrink: 0;
494
+ width: 40px;
495
+ height: 40px;
496
+ border-radius: 50%;
497
+ overflow: hidden;
498
+ background-color: var(--message-accent, #64748b);
499
+ color: #ffffff;
378
500
  display: flex;
379
- flex-wrap: wrap;
380
501
  align-items: center;
502
+ justify-content: center;
503
+ }
504
+
505
+ .message-avatar img {
506
+ width: 100%;
507
+ height: 100%;
508
+ object-fit: cover;
509
+ display: block;
510
+ }
511
+
512
+ .message-avatar--initial span {
513
+ font-size: 16px;
514
+ font-weight: 600;
515
+ line-height: 1;
516
+ }
517
+
518
+ .message-body {
519
+ flex: 1 1 auto;
520
+ min-width: 0;
521
+ max-width: 78%;
522
+ display: flex;
523
+ flex-direction: column;
524
+ gap: 6px;
525
+ }
526
+
527
+ .message--mine .message-body {
528
+ align-items: flex-end;
529
+ }
530
+
531
+ .message-meta {
532
+ display: flex;
533
+ flex-wrap: wrap;
534
+ align-items: baseline;
381
535
  gap: 8px;
536
+ padding: 0 4px;
537
+ }
538
+
539
+ .message--mine .message-meta {
540
+ justify-content: flex-end;
382
541
  }
383
542
 
384
543
  .message-sender {
385
- font-size: 16px;
544
+ font-size: 13px;
386
545
  font-weight: 600;
387
- color: var(--message-accent, #0f172a);
546
+ color: var(--message-accent, var(--chat-export-text));
547
+ }
548
+
549
+ .message--mine .message-sender {
550
+ color: var(--chat-export-text);
388
551
  }
389
552
 
390
- .message-role {
553
+ .message-time {
391
554
  font-size: 11px;
392
- letter-spacing: 0.12em;
393
- text-transform: uppercase;
394
- color: #64748b;
555
+ color: var(--chat-export-muted);
395
556
  }
396
557
 
397
- .message-time,
398
- .message-duration {
399
- font-size: 12px;
400
- color: #64748b;
558
+ .message-bubble {
559
+ padding: 14px 16px;
560
+ border-radius: 16px;
561
+ background: var(--chat-export-bubble-theirs-bg);
562
+ color: var(--chat-export-bubble-theirs-text);
563
+ border: 1px solid var(--chat-export-bubble-theirs-border);
564
+ border-top-left-radius: 4px;
565
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
566
+ max-width: 100%;
567
+ overflow-wrap: anywhere;
401
568
  }
402
569
 
403
- .message-duration {
404
- margin: 12px 0 0;
570
+ .message--mine .message-bubble {
571
+ background: var(--chat-export-bubble-mine-bg);
572
+ color: var(--chat-export-bubble-mine-text);
573
+ border-color: transparent;
574
+ border-top-left-radius: 16px;
575
+ border-top-right-radius: 4px;
576
+ }
577
+
578
+ .message--mine .message-bubble a {
579
+ color: #d4e8ff;
580
+ }
581
+
582
+ .message--mine .message-bubble code {
583
+ background: rgba(255, 255, 255, 0.18);
584
+ color: inherit;
585
+ }
586
+
587
+ .message--mine .message-bubble pre {
588
+ background: rgba(15, 23, 42, 0.35);
589
+ color: #f8fafc;
590
+ }
591
+
592
+ .message--mine .message-bubble blockquote {
593
+ color: rgba(255, 255, 255, 0.85);
594
+ border-color: rgba(255, 255, 255, 0.5);
595
+ }
596
+
597
+ .message-footnote {
598
+ margin: 2px 4px 0;
599
+ font-size: 11px;
600
+ color: var(--chat-export-muted);
405
601
  }
406
602
 
407
603
  .message-empty {
408
- color: #64748b;
604
+ color: var(--chat-export-muted);
409
605
  font-style: italic;
606
+ margin: 0;
410
607
  }
411
608
 
412
609
  .reply-context {
413
- margin-bottom: 14px;
414
- padding: 12px 14px;
610
+ margin: 0 0 10px;
611
+ padding: 8px 12px;
415
612
  border-radius: 10px;
416
- border: 1px solid #e2e8f0;
417
- background: #f8fafc;
613
+ border-left: 3px solid var(--message-accent, #cbd5e1);
614
+ background: rgba(15, 23, 42, 0.04);
615
+ }
616
+
617
+ .message--mine .reply-context {
618
+ background: rgba(255, 255, 255, 0.18);
619
+ border-left-color: rgba(255, 255, 255, 0.7);
418
620
  }
419
621
 
420
622
  .reply-context-title,
421
623
  .message-supporting-title {
422
- margin-bottom: 8px;
624
+ margin-bottom: 6px;
423
625
  font-size: 11px;
424
- letter-spacing: 0.12em;
626
+ letter-spacing: 0.1em;
425
627
  text-transform: uppercase;
426
- color: #64748b;
628
+ color: var(--chat-export-muted);
629
+ }
630
+
631
+ .message--mine .reply-context-title {
632
+ color: rgba(255, 255, 255, 0.8);
427
633
  }
428
634
 
429
635
  .message-supporting-list {
430
- margin-top: 14px;
431
- padding-top: 12px;
432
- border-top: 1px solid #e2e8f0;
636
+ margin-top: 10px;
637
+ padding: 10px 14px;
638
+ border-radius: 10px;
639
+ background: rgba(15, 23, 42, 0.03);
433
640
  }
434
641
 
435
642
  .message-supporting-list ul {
@@ -439,18 +646,14 @@ export function buildChatHtml(
439
646
 
440
647
  .message-supporting-meta {
441
648
  margin-right: 6px;
442
- color: #64748b;
649
+ color: var(--chat-export-muted);
443
650
  font-size: 12px;
444
651
  }
445
652
 
446
653
  .message-supporting-excerpt {
447
- margin-top: 6px;
654
+ margin-top: 4px;
448
655
  color: #475569;
449
- }
450
-
451
- .markdown-content {
452
- font-size: 15px;
453
- line-height: 1.65;
656
+ font-size: 13px;
454
657
  }
455
658
 
456
659
  .markdown-content > *:first-child {
@@ -478,7 +681,7 @@ export function buildChatHtml(
478
681
  .markdown-content pre,
479
682
  .markdown-content table,
480
683
  .markdown-content details {
481
- margin: 0 0 14px;
684
+ margin: 0 0 12px;
482
685
  }
483
686
 
484
687
  .markdown-content ul,
@@ -488,7 +691,7 @@ export function buildChatHtml(
488
691
 
489
692
  .markdown-content code {
490
693
  font-family: ui-monospace, "SFMono-Regular", monospace;
491
- background: #f1f5f9;
694
+ background: rgba(15, 23, 42, 0.06);
492
695
  border-radius: 4px;
493
696
  padding: 1px 5px;
494
697
  font-size: 0.94em;
@@ -540,7 +743,7 @@ export function buildChatHtml(
540
743
 
541
744
  .markdown-content details {
542
745
  padding: 12px 14px;
543
- border: 1px solid #e2e8f0;
746
+ border: 1px solid var(--chat-export-soft-border);
544
747
  border-radius: 10px;
545
748
  background: #f8fafc;
546
749
  }
@@ -562,7 +765,7 @@ export function buildChatHtml(
562
765
  }
563
766
 
564
767
  .markdown-content sup[data-citation-footnote] a {
565
- color: #0f6cbd;
768
+ color: inherit;
566
769
  text-decoration: none;
567
770
  }
568
771
 
@@ -575,14 +778,14 @@ export function buildChatHtml(
575
778
  border: 1px dashed #cbd5e1;
576
779
  border-radius: 14px;
577
780
  text-align: center;
578
- color: #64748b;
579
- background: #ffffff;
781
+ color: var(--chat-export-muted);
782
+ background: var(--chat-export-surface);
580
783
  }
581
784
 
582
785
  .document-sources {
583
- margin-top: 24px;
584
- padding-top: 16px;
585
- border-top: 1px solid #e2e8f0;
786
+ margin-top: 32px;
787
+ padding-top: 18px;
788
+ border-top: 1px solid var(--chat-export-soft-border);
586
789
  }
587
790
 
588
791
  .document-sources-title {
@@ -608,26 +811,50 @@ export function buildChatHtml(
608
811
  }
609
812
 
610
813
  .document-footer {
611
- margin-top: 24px;
814
+ margin-top: 28px;
612
815
  padding-top: 16px;
613
- border-top: 1px solid #e2e8f0;
614
- color: #64748b;
816
+ border-top: 1px solid var(--chat-export-soft-border);
817
+ color: var(--chat-export-muted);
615
818
  font-size: 12px;
819
+ text-align: center;
616
820
  }
617
821
 
618
822
  .document-footer strong {
619
823
  color: #475569;
620
824
  }
621
825
 
826
+ @page {
827
+ size: Letter;
828
+ margin: 0.5in;
829
+ }
830
+
622
831
  @media print {
623
- body {
832
+ body,
833
+ .${CHAT_HTML_EXPORT_RENDER_ROOT_CLASS_NAME} {
624
834
  background: #ffffff;
835
+ font-size: 12pt;
625
836
  }
626
837
 
627
838
  .document {
628
839
  max-width: none;
629
840
  padding: 0;
630
841
  }
842
+
843
+ .message {
844
+ page-break-inside: avoid;
845
+ break-inside: avoid;
846
+ }
847
+
848
+ .message-bubble {
849
+ box-shadow: none;
850
+ }
851
+
852
+ .markdown-content pre,
853
+ .message-supporting-list,
854
+ .reply-context {
855
+ page-break-inside: avoid;
856
+ break-inside: avoid;
857
+ }
631
858
  }
632
859
  </style>
633
860
  </head>
@@ -19,7 +19,13 @@ const PROMPTBOOK_REACT_EXPORT_BRANDING_COMMENT = createPromptbookReactExportBran
19
19
  function createPromptbookReactExportBrandingComment(): string {
20
20
  const branding = getPromptbookExportBranding();
21
21
 
22
- return ['/*', ...branding.commentLines.map((line) => ` * ${line}`), ' */'].join('\n');
22
+ return spaceTrim(
23
+ (block) => `
24
+ /*
25
+ ${block(branding.commentLines.map((line) => ` * ${line}`).join('\n'))}
26
+ */
27
+ `,
28
+ );
23
29
  }
24
30
 
25
31
  /**
@@ -302,6 +302,11 @@ export type ChatMessage = Omit<Message<id>, 'direction' | 'recipients' | 'thread
302
302
  */
303
303
  url?: string;
304
304
 
305
+ /**
306
+ * Optional human-readable source title.
307
+ */
308
+ title?: string;
309
+
305
310
  /**
306
311
  * Optional preview/excerpt from the source
307
312
  */
@@ -57,7 +57,7 @@ export type ChatParticipant = {
57
57
  * Knowledge sources (documents, URLs) used by the agent
58
58
  * Used for resolving document citations when the agent references sources
59
59
  */
60
- knowledgeSources?: Array<{ url: string; filename: string }>;
60
+ knowledgeSources?: ReadonlyArray<{ url: string; filename: string }>;
61
61
  };
62
62
 
63
63
  // TODO: [🕛] Unite `AgentBasicInformation`, `ChatParticipant`, `LlmExecutionTools` + `LlmToolsMetadata`
@@ -0,0 +1,9 @@
1
+ import type { Promisable } from 'type-fest';
2
+ import type { ParsedCitation } from '../utils/parseCitationsFromContent';
3
+
4
+ /**
5
+ * Optional host-provided resolver for citation display labels.
6
+ *
7
+ * @public exported from `@promptbook/components`
8
+ */
9
+ export type CitationLabelResolver = (citation: ParsedCitation) => Promisable<string | null | undefined>;