@promptbook/cli 0.112.0-125 → 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 +696 -941
  156. package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
  157. package/src/version.ts +2 -2
  158. package/src/versions.txt +2 -1
  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
package/README.md CHANGED
@@ -543,7 +543,7 @@ Prompts marked with `[-]` are not ready yet, prompts containing `@@@` are treate
543
543
  - **Multi-runner execution:** `openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini`
544
544
  - **Context injection:** `--agent agents/coding/developer.book --context AGENTS.md` or inline extra instructions
545
545
  - **Reasoning control:** `--thinking-level low|medium|high|xhigh` for supported runners
546
- - **Interactive or unattended runs:** default wait mode, or `--no-wait` for batch execution
546
+ - **Unattended or interactive runs:** default auto mode, or `--no-auto` to wait for user confirmation before each prompt
547
547
  - **Git safety:** clean working tree check by default, optional `--ignore-git-changes`
548
548
  - **Opt-in remote pushes:** commits stay local unless you explicitly pass `--auto-push`
549
549
  - **Prompt triage:** `--priority` to process only more important tasks first
@@ -565,7 +565,7 @@ npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gp
565
565
 
566
566
  npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --auto-push
567
567
 
568
- npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --ignore-git-changes --no-wait
568
+ npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --ignore-git-changes
569
569
 
570
570
  npx ts-node ./src/cli/test/ptbk.ts coder find-refactor-candidates
571
571
 
@@ -591,7 +591,7 @@ ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh -
591
591
 
592
592
  ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --auto-push
593
593
 
594
- ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --test npm run test --ignore-git-changes --no-wait
594
+ ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --agent agents/coding/developer.book --context AGENTS.md --test npm run test --ignore-git-changes
595
595
 
596
596
  ptbk coder find-refactor-candidates
597
597
 
@@ -621,7 +621,7 @@ ptbk coder verify
621
621
  | `--context <text-or-file>` | Appends extra instructions inline or from a file like `AGENTS.md`. |
622
622
  | `--test <command>` | Runs a verification command after each prompt attempt and feeds failing output back for retries. |
623
623
  | `--thinking-level <level>` | Sets reasoning effort for supported runners. |
624
- | `--no-wait` | Skips interactive pauses between prompts for unattended execution. |
624
+ | `--no-auto` | Waits for user confirmation before each prompt instead of running automatically through the queue. |
625
625
  | `--ignore-git-changes` | Disables the clean-working-tree guard. |
626
626
  | `--priority <n>` | Runs only prompts at or above the given priority. |
627
627
  | `--dry-run` | Prints which prompts are ready instead of executing them. |
@@ -634,7 +634,7 @@ ptbk coder verify
634
634
  1. Initialize once with `ptbk coder init`.
635
635
  2. Customize `prompts/templates/*.md` if needed, then create or write prompt files in `prompts/`.
636
636
  3. Customize the starter `AGENTS.md` with repository-specific instructions, then pass `--agent agents/coding/developer.book --context AGENTS.md`.
637
- 4. Run one prompt at a time interactively, or use `--no-wait` for unattended batches.
637
+ 4. Run unattended batches by default, or pass `--no-auto` to confirm each prompt interactively.
638
638
  5. Finish with `ptbk coder verify` so resolved prompts are archived and broken ones get explicit repair follow-ups.
639
639
 
640
640
 
@@ -41,6 +41,9 @@ ptbk agents-server start --harness github-copilot --model gpt-5.4 --thinking-lev
41
41
  <a id="agents-server-env-admin-password"></a>
42
42
  - `ADMIN_PASSWORD`: Password for the built-in `admin` login on a self-hosted Agents Server. Choose a private value before using the admin UI.
43
43
 
44
+ <a id="agents-server-env-session-secret"></a>
45
+ - `SESSION_SECRET`: HMAC signing key used to sign the session cookie. Must be set explicitly in production — the server refuses to start session signing when missing instead of falling back to a hardcoded default. Use a long random string, for example the output of `openssl rand -hex 32`. Keep it separate from `ADMIN_PASSWORD` so a leak of either credential cannot forge the other.
46
+
44
47
  ## Creating servers
45
48
 
46
49
  When creating new Agents server, search across the repository for [☁]
@@ -26,6 +26,7 @@ const APP_URL = `http://127.0.0.1:${APP_PORT}`;
26
26
  */
27
27
  const APP_E2E_ENV = {
28
28
  ADMIN_PASSWORD: 'e2e-admin-password',
29
+ SESSION_SECRET: 'e2e-session-secret-must-differ-from-admin-password',
29
30
  NEXT_DIST_DIR: '.next-e2e',
30
31
  NEXT_PUBLIC_SITE_URL: APP_URL,
31
32
  PTBK_AGENTS_SERVER_DATABASE: 'supabase',
@@ -0,0 +1 @@
1
+ export { default, generateMetadata } from '../agents/[agentName]/layout';
@@ -5,7 +5,7 @@ import { string_agent_name, string_book } from '@promptbook-local/types';
5
5
  import { revalidatePath } from 'next/cache';
6
6
  import { string_agent_permanent_id } from '../../../../src/types/typeAliases';
7
7
  import { DEFAULT_NAME_POOL, NAME_POOL_METADATA_KEY, parseNamePool } from '../constants/namePool';
8
- import { NEW_AGENT_WIZZARD_METADATA_KEY, parseNewAgentWizardMode } from '../constants/newAgentWizard';
8
+ import { NEW_AGENT_WIZARD_METADATA_KEY, parseNewAgentWizardMode } from '../constants/newAgentWizard';
9
9
  import { getMetadata } from '../database/getMetadata';
10
10
  import { $provideAgentCollectionForServer } from '../tools/$provideAgentCollectionForServer';
11
11
  import { invalidateCachedActiveOrganizationSnapshots } from '../utils/agentOrganization/loadAgentOrganizationState';
@@ -73,7 +73,7 @@ export async function $getNewAgentCreationSettingsAction(): Promise<{
73
73
  defaultVisibility: AgentVisibility;
74
74
  }> {
75
75
  return {
76
- mode: parseNewAgentWizardMode(await getMetadata(NEW_AGENT_WIZZARD_METADATA_KEY)),
76
+ mode: parseNewAgentWizardMode(await getMetadata(NEW_AGENT_WIZARD_METADATA_KEY)),
77
77
  defaultVisibility: parseAgentVisibility(await getMetadata('DEFAULT_VISIBILITY')),
78
78
  };
79
79
  }
@@ -67,32 +67,44 @@ export function UpdateClient() {
67
67
  /**
68
68
  * Loads the latest self-update overview from the server.
69
69
  */
70
- const loadOverview = useCallback(async (options?: { readonly isSilent?: boolean }): Promise<void> => {
71
- try {
72
- if (!options?.isSilent) {
73
- setIsLoading(true);
74
- }
75
- setErrorMessage(null);
76
-
77
- const response = await fetch('/api/admin/update', { cache: 'no-store' });
78
- const payload = (await response.json()) as UpdateOverview;
79
-
80
- if (!response.ok) {
81
- throw new Error(payload.error || 'Failed to load the update overview.');
70
+ const loadOverview = useCallback(
71
+ async (options?: { readonly isSilent?: boolean; readonly isRestartExpected?: boolean }): Promise<void> => {
72
+ try {
73
+ if (!options?.isSilent) {
74
+ setIsLoading(true);
75
+ }
76
+ setErrorMessage(null);
77
+
78
+ const response = await fetch('/api/admin/update', { cache: 'no-store' });
79
+ const payload = (await response.json()) as UpdateOverview;
80
+
81
+ if (!response.ok) {
82
+ throw new Error(payload.error || 'Failed to load the update overview.');
83
+ }
84
+
85
+ setOverview(payload);
86
+ setSelectedEnvironmentId(
87
+ (currentSelectedEnvironmentId) => currentSelectedEnvironmentId || payload.currentEnvironment.id,
88
+ );
89
+ if (payload.job.status === 'succeeded') {
90
+ setSuccessMessage(getUpdateJobSuccessMessage(payload.job));
91
+ } else if (payload.job.status === 'failed') {
92
+ setSuccessMessage(null);
93
+ }
94
+ } catch (error) {
95
+ if (options?.isRestartExpected) {
96
+ return;
97
+ }
98
+
99
+ setErrorMessage(error instanceof Error ? error.message : 'Failed to load the update overview.');
100
+ } finally {
101
+ if (!options?.isSilent) {
102
+ setIsLoading(false);
103
+ }
82
104
  }
83
-
84
- setOverview(payload);
85
- setSelectedEnvironmentId((currentSelectedEnvironmentId) =>
86
- currentSelectedEnvironmentId || payload.currentEnvironment.id,
87
- );
88
- } catch (error) {
89
- setErrorMessage(error instanceof Error ? error.message : 'Failed to load the update overview.');
90
- } finally {
91
- if (!options?.isSilent) {
92
- setIsLoading(false);
93
- }
94
- }
95
- }, []);
105
+ },
106
+ [],
107
+ );
96
108
 
97
109
  useEffect(() => {
98
110
  void loadOverview();
@@ -104,7 +116,7 @@ export function UpdateClient() {
104
116
  }
105
117
 
106
118
  const interval = window.setInterval(() => {
107
- void loadOverview({ isSilent: true });
119
+ void loadOverview({ isSilent: true, isRestartExpected: true });
108
120
  }, 4000);
109
121
 
110
122
  return () => {
@@ -365,10 +377,10 @@ export function UpdateClient() {
365
377
  overview?.job.status === 'running'
366
378
  ? 'border-blue-200 bg-blue-50 text-blue-700'
367
379
  : overview?.job.status === 'failed'
368
- ? 'border-rose-200 bg-rose-50 text-rose-700'
369
- : overview?.job.status === 'succeeded'
370
- ? 'border-emerald-200 bg-emerald-50 text-emerald-700'
371
- : 'border-slate-200 bg-slate-50 text-slate-500'
380
+ ? 'border-rose-200 bg-rose-50 text-rose-700'
381
+ : overview?.job.status === 'succeeded'
382
+ ? 'border-emerald-200 bg-emerald-50 text-emerald-700'
383
+ : 'border-slate-200 bg-slate-50 text-slate-500'
372
384
  }`}
373
385
  >
374
386
  {overview?.job.status || 'idle'}
@@ -394,14 +406,14 @@ export function UpdateClient() {
394
406
  </div>
395
407
  </dl>
396
408
 
397
- {overview?.job.errorMessage && (
398
- <div className="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
399
- {overview.job.errorMessage}
409
+ {overview?.job.status === 'succeeded' && (
410
+ <div className="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700">
411
+ {getUpdateJobSuccessMessage(overview.job)}
400
412
  </div>
401
413
  )}
402
- {overview?.job.isStale && (
403
- <div className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
404
- The previous background update process stopped unexpectedly. You can start the update again.
414
+ {overview?.job.status === 'failed' && (
415
+ <div className="rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
416
+ {getUpdateJobFailureMessage(overview.job)}
405
417
  </div>
406
418
  )}
407
419
  {overview?.job.logFilePath && (
@@ -424,6 +436,26 @@ export function UpdateClient() {
424
436
  );
425
437
  }
426
438
 
439
+ /**
440
+ * Builds the success message for a finished standalone VPS update.
441
+ *
442
+ * @param job - Completed update job snapshot.
443
+ * @returns Human-readable success message.
444
+ */
445
+ function getUpdateJobSuccessMessage(job: UpdateJobSnapshot): string {
446
+ return job.currentStep || 'Standalone VPS update finished successfully.';
447
+ }
448
+
449
+ /**
450
+ * Builds the failure message for a failed standalone VPS update.
451
+ *
452
+ * @param job - Failed update job snapshot.
453
+ * @returns Human-readable failure message.
454
+ */
455
+ function getUpdateJobFailureMessage(job: UpdateJobSnapshot): string {
456
+ return job.errorMessage || 'The standalone VPS update failed. Review the installer log for details.';
457
+ }
458
+
427
459
  /**
428
460
  * Formats optional timestamps for the status cards.
429
461
  *
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+
3
+ import {
4
+ useRegisterActiveAgentBreadcrumbInfo,
5
+ type ActiveAgentBreadcrumbInfo,
6
+ } from '../../../components/Header/ActiveAgentBreadcrumbContext';
7
+
8
+ /**
9
+ * Props for the active-agent breadcrumb binder.
10
+ *
11
+ * @private type of agent routes
12
+ */
13
+ type ActiveAgentBreadcrumbBinderProps = {
14
+ /**
15
+ * Resolved active agent that should be shown in the Header breadcrumb.
16
+ */
17
+ readonly agent: ActiveAgentBreadcrumbInfo;
18
+ };
19
+
20
+ /**
21
+ * Registers the active agent with the Header breadcrumb context while the agent route is mounted.
22
+ * Renders nothing on its own; its sole purpose is to make sure the Header can render the agent's
23
+ * human-readable name instead of falling back to its URL identifier.
24
+ *
25
+ * @private function of agent routes
26
+ */
27
+ export function ActiveAgentBreadcrumbBinder({ agent }: ActiveAgentBreadcrumbBinderProps) {
28
+ useRegisterActiveAgentBreadcrumbInfo(agent);
29
+ return null;
30
+ }
@@ -21,6 +21,7 @@ import { useSoundSystem } from '../../../components/SoundSystemProvider/SoundSys
21
21
  import { fetchCalendarOAuthStatus, type CalendarOAuthStatusResponse } from '../../../utils/calendarOAuthClient';
22
22
  import { createDefaultChatEffects } from '../../../utils/chat/createDefaultChatEffects';
23
23
  import { executeQuickActionButton } from '../../../utils/chat/executeQuickActionButton';
24
+ import { resolveAgentsServerCitationLabel } from '../../../utils/chat/resolveAgentsServerCitationLabel';
24
25
  import {
25
26
  isChatFeedbackEnabled,
26
27
  toChatComponentFeedbackMode,
@@ -458,6 +459,7 @@ export function AgentChatWrapper(props: AgentChatWrapperProps) {
458
459
  onReset={onStartNewChat}
459
460
  resetMode={onStartNewChat ? 'delegate' : undefined}
460
461
  teamAgentProfiles={teamAgentProfiles}
462
+ resolveCitationLabel={resolveAgentsServerCitationLabel}
461
463
  >
462
464
  {allowFileAttachments && !fileUploadAvailability.isUploadAvailable && (
463
465
  <FileUploadUnavailableNotice className="mx-4 mt-4" />
@@ -34,6 +34,7 @@ export const AgentChatHistoryPayloadState = {
34
34
  applySnapshotStateUpdate,
35
35
  clearActiveChatRuntimeState,
36
36
  replaceChatInList,
37
+ sortUserChatSummariesByTimeDescending,
37
38
  };
38
39
 
39
40
  /**
@@ -175,7 +176,7 @@ function applySnapshotStateUpdate(params: {
175
176
  } = params;
176
177
 
177
178
  const reason = options.reason || 'snapshot-update';
178
- setChats(snapshot.chats);
179
+ setChats(sortUserChatSummariesByTimeDescending(snapshot.chats));
179
180
  if (!snapshot.activeChatId) {
180
181
  if (options.allowSelectionAdoption !== true) {
181
182
  logChatSelection('selection_skip_snapshot_missing_active_chat', {
@@ -616,11 +617,44 @@ function applyResolvedChatPayload(params: {
616
617
  }
617
618
 
618
619
  /**
619
- * Moves one chat summary to the top of the sidebar list.
620
+ * Inserts or updates one chat summary in the sidebar list while keeping the list ordered
621
+ * by latest activity time (newest first), so the currently selected chat stays in its
622
+ * chronological position instead of being hoisted to the top.
620
623
  *
621
624
  * @private function of useAgentChatHistoryClientState
622
625
  */
623
626
  function replaceChatInList(chats: ReadonlyArray<UserChatSummary>, targetChat: UserChatSummary): Array<UserChatSummary> {
624
- const remainingChats = chats.filter((chat) => chat.id !== targetChat.id);
625
- return [targetChat, ...remainingChats];
627
+ const hasExistingEntry = chats.some((chat) => chat.id === targetChat.id);
628
+ const updatedChats = hasExistingEntry
629
+ ? chats.map((chat) => (chat.id === targetChat.id ? targetChat : chat))
630
+ : [...chats, targetChat];
631
+ return sortUserChatSummariesByTimeDescending(updatedChats);
632
+ }
633
+
634
+ /**
635
+ * Resolves the timestamp used to order one chat summary in the sidebar tray.
636
+ *
637
+ * Prefers the latest message timestamp, falls back to the chat's last update time, and finally
638
+ * to its creation time. This mirrors the timestamp displayed next to each chat row.
639
+ *
640
+ * @private function of useAgentChatHistoryClientState
641
+ */
642
+ function resolveUserChatSummaryOrderTime(chat: UserChatSummary): number {
643
+ const timestamp = chat.lastMessageAt || chat.updatedAt || chat.createdAt;
644
+ const parsedTime = new Date(timestamp).getTime();
645
+ return Number.isFinite(parsedTime) ? parsedTime : 0;
646
+ }
647
+
648
+ /**
649
+ * Returns one new array of chat summaries sorted by latest activity time, newest first.
650
+ *
651
+ * @private function of useAgentChatHistoryClientState
652
+ */
653
+ function sortUserChatSummariesByTimeDescending(
654
+ chats: ReadonlyArray<UserChatSummary>,
655
+ ): Array<UserChatSummary> {
656
+ return [...chats].sort(
657
+ (leftChat, rightChat) =>
658
+ resolveUserChatSummaryOrderTime(rightChat) - resolveUserChatSummaryOrderTime(leftChat),
659
+ );
626
660
  }
@@ -90,7 +90,10 @@ async function createBootstrapChatFromSnapshot(params: {
90
90
  currentInitialOptimisticChatBootstrap.optimisticChatId,
91
91
  createdChat.chat,
92
92
  )
93
- : [createdChat.chat, ...snapshot.chats.filter((chat) => chat.id !== createdChat.chat.id)],
93
+ : AgentChatHistoryPayloadState.sortUserChatSummariesByTimeDescending([
94
+ createdChat.chat,
95
+ ...snapshot.chats.filter((chat) => chat.id !== createdChat.chat.id),
96
+ ]),
94
97
  );
95
98
  }
96
99
 
@@ -15,8 +15,9 @@ import { ChatThreadLoadingSkeleton } from '../../../../components/Skeleton/ChatT
15
15
  import { useSoundSystem } from '../../../../components/SoundSystemProvider/SoundSystemProvider';
16
16
  import { usePromptbookTheme } from '../../../../components/ThemeMode/usePromptbookTheme';
17
17
  import { createDefaultChatEffects } from '../../../../utils/chat/createDefaultChatEffects';
18
- import { downloadChatPdfFromServer } from '../../../../utils/chatExport/downloadChatPdfFromServer';
19
18
  import { executeQuickActionButton } from '../../../../utils/chat/executeQuickActionButton';
19
+ import { resolveAgentsServerCitationLabel } from '../../../../utils/chat/resolveAgentsServerCitationLabel';
20
+ import { downloadChatPdfFromServer } from '../../../../utils/chatExport/downloadChatPdfFromServer';
20
21
  import {
21
22
  isChatFeedbackEnabled,
22
23
  toChatComponentFeedbackMode,
@@ -127,6 +128,7 @@ export function CanonicalAgentChatSurface({
127
128
  agentAvatarSrc: state.agentAvatarSrc,
128
129
  agentAvatarVisualId: state.agentAvatarVisualId,
129
130
  agentDisplayName: state.agentDisplayName,
131
+ agentKnowledgeSources: state.agentKnowledgeSources,
130
132
  brandColorHex,
131
133
  }),
132
134
  [
@@ -135,6 +137,7 @@ export function CanonicalAgentChatSurface({
135
137
  state.agentAvatarSrc,
136
138
  state.agentAvatarVisualId,
137
139
  state.agentDisplayName,
140
+ state.agentKnowledgeSources,
138
141
  ],
139
142
  );
140
143
  const { language, t: translateText } = useServerLanguage();
@@ -181,20 +184,17 @@ export function CanonicalAgentChatSurface({
181
184
  </button>
182
185
  );
183
186
  }, [cancellableJob, isReadOnly, onCancelActiveJob, translateText]);
184
- const handlePdfSaveFormat = useCallback(
185
- async ({ title, messages, participants }: ChatSaveFormatHandlerOptions) => {
186
- try {
187
- await downloadChatPdfFromServer({
188
- title,
189
- messages,
190
- participants,
191
- });
192
- } catch (error) {
193
- notifyError(error instanceof Error ? error.message : 'Failed to export chat as PDF.');
194
- }
195
- },
196
- [],
197
- );
187
+ const handlePdfSaveFormat = useCallback(async ({ title, messages, participants }: ChatSaveFormatHandlerOptions) => {
188
+ try {
189
+ await downloadChatPdfFromServer({
190
+ title,
191
+ messages,
192
+ participants,
193
+ });
194
+ } catch (error) {
195
+ notifyError(error instanceof Error ? error.message : 'Failed to export chat as PDF.');
196
+ }
197
+ }, []);
198
198
  const saveFormatHandlers = useMemo(
199
199
  () => ({
200
200
  pdf: handlePdfSaveFormat,
@@ -266,6 +266,7 @@ export function CanonicalAgentChatSurface({
266
266
  teamAgentProfiles={state.teamAgentProfiles}
267
267
  extraActions={extraActionNodes}
268
268
  saveFormatHandlers={saveFormatHandlers}
269
+ resolveCitationLabel={resolveAgentsServerCitationLabel}
269
270
  theme={promptbookTheme}
270
271
  >
271
272
  {!isReadOnly && areFileAttachmentsEnabled && !fileUploadAvailability.isUploadAvailable && (
@@ -322,12 +323,14 @@ function createCanonicalAgentChatParticipants({
322
323
  agentAvatarDefinition,
323
324
  agentAvatarSrc,
324
325
  agentAvatarVisualId,
326
+ agentKnowledgeSources,
325
327
  brandColorHex,
326
328
  }: {
327
329
  agentDisplayName: string;
328
330
  agentAvatarDefinition: CanonicalAgentChatPanelState['surface']['agentAvatarDefinition'];
329
331
  agentAvatarSrc: CanonicalAgentChatPanelState['surface']['agentAvatarSrc'];
330
332
  agentAvatarVisualId: CanonicalAgentChatPanelState['surface']['agentAvatarVisualId'];
333
+ agentKnowledgeSources: CanonicalAgentChatPanelState['surface']['agentKnowledgeSources'];
331
334
  brandColorHex: string;
332
335
  }): ReadonlyArray<ChatParticipant> {
333
336
  return [
@@ -339,6 +342,7 @@ function createCanonicalAgentChatParticipants({
339
342
  avatarVisualId: agentAvatarVisualId || undefined,
340
343
  color: brandColorHex,
341
344
  isMe: false,
345
+ knowledgeSources: agentKnowledgeSources,
342
346
  },
343
347
  {
344
348
  name: 'USER',
@@ -60,6 +60,23 @@ type CanonicalAgentChatFeedback = {
60
60
  url: string;
61
61
  };
62
62
 
63
+ /**
64
+ * Knowledge source metadata passed from the remote agent profile into Chat participants.
65
+ *
66
+ * @private type of CanonicalAgentChatPanel
67
+ */
68
+ type CanonicalAgentKnowledgeSource = {
69
+ /**
70
+ * Fetchable source URL.
71
+ */
72
+ readonly url: string;
73
+
74
+ /**
75
+ * Filename used by model citations.
76
+ */
77
+ readonly filename: string;
78
+ };
79
+
63
80
  /**
64
81
  * Inputs required to orchestrate the canonical durable-chat panel state.
65
82
  *
@@ -109,6 +126,7 @@ export type CanonicalAgentChatPanelState = {
109
126
  readonly agentAvatarSrc: string | null;
110
127
  readonly agentAvatarVisualId: AvatarVisualId | null;
111
128
  readonly agentDisplayName: string;
129
+ readonly agentKnowledgeSources: ReadonlyArray<CanonicalAgentKnowledgeSource>;
112
130
  readonly elevenLabsVoiceId: string | undefined;
113
131
  readonly initialMessage: string | undefined;
114
132
  readonly isSpeechPlaybackEnabled: boolean;
@@ -343,6 +361,7 @@ export function useCanonicalAgentChatPanelState(
343
361
  });
344
362
 
345
363
  const agentDisplayName = useMemo(() => resolveAgentDisplayName(agent, agentName), [agent, agentName]);
364
+ const agentKnowledgeSources = useMemo(() => resolveAgentKnowledgeSources(agent), [agent]);
346
365
  const resolvedAgentAvatar = useMemo(
347
366
  () => resolveResolvedAgentAvatar(agent, agentName, agentUrl),
348
367
  [agent, agentName, agentUrl],
@@ -400,11 +419,11 @@ export function useCanonicalAgentChatPanelState(
400
419
 
401
420
  return {
402
421
  surface: {
403
- agentAvatarDefinition:
404
- resolvedAgentAvatar?.type === 'visual' ? resolvedAgentAvatar.avatarDefinition : null,
422
+ agentAvatarDefinition: resolvedAgentAvatar?.type === 'visual' ? resolvedAgentAvatar.avatarDefinition : null,
405
423
  agentAvatarSrc: resolvedAgentAvatar?.type === 'image' ? resolvedAgentAvatar.imageUrl : null,
406
424
  agentAvatarVisualId: resolvedAgentAvatar?.type === 'visual' ? resolvedAgentAvatar.visualId : null,
407
425
  agentDisplayName,
426
+ agentKnowledgeSources,
408
427
  elevenLabsVoiceId: agent?.meta.voice,
409
428
  initialMessage,
410
429
  isSpeechPlaybackEnabled: agent?.isVoiceTtsSttEnabled ?? false,
@@ -658,15 +677,47 @@ function resolveAgentDisplayName(agent: RemoteAgent | null | undefined, agentNam
658
677
  }
659
678
 
660
679
  /**
661
- * Resolves the avatar shown for the agent participant in the chat thread.
680
+ * Resolves valid knowledge sources exposed by the remote agent profile.
681
+ *
682
+ * @param agent - Connected remote agent.
683
+ * @returns Knowledge sources usable by the shared Chat citation URL resolver.
662
684
  *
663
685
  * @private function of CanonicalAgentChatPanel
664
686
  */
665
- function resolveResolvedAgentAvatar(
687
+ function resolveAgentKnowledgeSources(
666
688
  agent: RemoteAgent | null | undefined,
667
- agentName: string,
668
- agentUrl: string,
669
- ) {
689
+ ): ReadonlyArray<CanonicalAgentKnowledgeSource> {
690
+ const knowledgeSources = (agent as { knowledgeSources?: unknown } | null | undefined)?.knowledgeSources;
691
+ if (!Array.isArray(knowledgeSources)) {
692
+ return [];
693
+ }
694
+
695
+ return knowledgeSources.filter(isCanonicalAgentKnowledgeSource);
696
+ }
697
+
698
+ /**
699
+ * Checks whether one remote profile value is a usable knowledge source.
700
+ *
701
+ * @param value - Candidate knowledge source.
702
+ * @returns True when the candidate has URL and filename strings.
703
+ *
704
+ * @private function of CanonicalAgentChatPanel
705
+ */
706
+ function isCanonicalAgentKnowledgeSource(value: unknown): value is CanonicalAgentKnowledgeSource {
707
+ return (
708
+ typeof value === 'object' &&
709
+ value !== null &&
710
+ typeof (value as CanonicalAgentKnowledgeSource).url === 'string' &&
711
+ typeof (value as CanonicalAgentKnowledgeSource).filename === 'string'
712
+ );
713
+ }
714
+
715
+ /**
716
+ * Resolves the avatar shown for the agent participant in the chat thread.
717
+ *
718
+ * @private function of CanonicalAgentChatPanel
719
+ */
720
+ function resolveResolvedAgentAvatar(agent: RemoteAgent | null | undefined, agentName: string, agentUrl: string) {
670
721
  return resolveAgentAvatar({
671
722
  agent: {
672
723
  agentName: agent?.agentName || agentName,
@@ -1,7 +1,11 @@
1
1
  'use server';
2
2
 
3
3
  import type { Metadata } from 'next';
4
+ import { resolveAgentRouteTarget } from '../../../utils/agentRouting/resolveAgentRouteTarget';
5
+ import { ActiveAgentBreadcrumbBinder } from './ActiveAgentBreadcrumbBinder';
6
+ import { getAgentName, getAgentProfile } from './_utils';
4
7
  import { generateAgentMetadata } from './generateAgentMetadata';
8
+ import type { ActiveAgentBreadcrumbInfo } from '../../../components/Header/ActiveAgentBreadcrumbContext';
5
9
 
6
10
  /**
7
11
  * Generates shared branded metadata for all pages under `/agents/[agentName]`.
@@ -13,13 +17,55 @@ export async function generateMetadata({ params }: { params: Promise<{ agentName
13
17
  return generateAgentMetadata({ params });
14
18
  }
15
19
 
20
+ /**
21
+ * Resolves the breadcrumb info for the route's active agent so the Header can show its name
22
+ * instead of falling back to the URL identifier. Failures are swallowed because the layout
23
+ * must keep rendering even when the agent cannot be resolved (the page will handle the error).
24
+ *
25
+ * @param rawAgentIdentifier - Decoded route parameter for the active agent.
26
+ * @returns Breadcrumb info for the active agent or `null` when unavailable.
27
+ *
28
+ * @private function of agent routes
29
+ */
30
+ async function tryResolveActiveAgentBreadcrumbInfo(
31
+ rawAgentIdentifier: string,
32
+ ): Promise<ActiveAgentBreadcrumbInfo | null> {
33
+ try {
34
+ const routeTarget = await resolveAgentRouteTarget(rawAgentIdentifier);
35
+ if (!routeTarget || routeTarget.kind !== 'local') {
36
+ return null;
37
+ }
38
+
39
+ const agentProfile = await getAgentProfile(routeTarget.canonicalAgentId);
40
+
41
+ return {
42
+ agentName: agentProfile.agentName,
43
+ agentHash: agentProfile.agentHash,
44
+ permanentId: agentProfile.permanentId,
45
+ meta: agentProfile.meta,
46
+ };
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
16
52
  /**
17
53
  * Shared route layout for all pages under `/agents/[agentName]`.
18
54
  */
19
55
  export default async function AgentLayout({
20
56
  children,
57
+ params,
21
58
  }: Readonly<{
22
59
  children: React.ReactNode;
60
+ params: Promise<{ agentName: string }>;
23
61
  }>) {
24
- return <>{children}</>;
62
+ const rawAgentIdentifier = await getAgentName(params);
63
+ const activeAgentBreadcrumbInfo = await tryResolveActiveAgentBreadcrumbInfo(rawAgentIdentifier);
64
+
65
+ return (
66
+ <>
67
+ {activeAgentBreadcrumbInfo && <ActiveAgentBreadcrumbBinder agent={activeAgentBreadcrumbInfo} />}
68
+ {children}
69
+ </>
70
+ );
25
71
  }