@promptbook/cli 0.112.0-103 → 0.112.0-104
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.
- package/apps/agents-server/src/app/AddAgentButton.tsx +0 -5
- package/apps/agents-server/src/app/actions.ts +50 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +3 -4
- package/apps/agents-server/src/app/api/health/route.ts +18 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +1 -4
- package/apps/agents-server/src/components/Header/Header.tsx +0 -11
- package/apps/agents-server/src/components/Header/useHeaderAgentMenus.tsx +0 -5
- package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +39 -16
- package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
- package/apps/agents-server/src/database/migrations/2026-06-0200-default-agent-avatar-visual-octopus3d3.sql +16 -0
- package/apps/agents-server/src/middleware.ts +2 -1
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +43 -2
- package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +27 -4
- package/apps/agents-server/src/utils/defaultAgents/defaultAgents.ts +168 -0
- package/apps/agents-server/src/utils/defaultAgents/installDefaultAgents.ts +139 -0
- package/esm/index.es.js +518 -7
- package/esm/index.es.js.map +1 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
- package/package.json +1 -1
- package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
- package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +903 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +784 -716
- package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
- package/src/version.ts +1 -1
- package/src/versions.txt +1 -1
- package/umd/index.umd.js +518 -7
- package/umd/index.umd.js.map +1 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useRouter } from 'next/navigation';
|
|
4
3
|
import { FileCard } from '../components/Homepage/FileCard';
|
|
5
4
|
import { useAgentNaming } from '../components/AgentNaming/AgentNamingContext';
|
|
6
5
|
import { showAlert } from '../components/AsyncDialogs/asyncDialogs';
|
|
@@ -21,15 +20,11 @@ type AddAgentButtonProps = {
|
|
|
21
20
|
* Renders the add-agent card and creation dialog workflow.
|
|
22
21
|
*/
|
|
23
22
|
export function AddAgentButton({ currentFolderId }: AddAgentButtonProps) {
|
|
24
|
-
const router = useRouter();
|
|
25
23
|
const { formatText } = useAgentNaming();
|
|
26
24
|
const { t } = useServerLanguage();
|
|
27
25
|
const addButtonLabel = formatText(t('agentCreation.addButtonLabel'));
|
|
28
26
|
|
|
29
27
|
const { isPreparingDialog, openNewAgentDialog, dialog } = useNewAgentDialog({
|
|
30
|
-
onCreated: ({ targetPath }) => {
|
|
31
|
-
router.push(targetPath);
|
|
32
|
-
},
|
|
33
28
|
onCreateFailed: async (error) => {
|
|
34
29
|
console.error('Failed to create agent:', error);
|
|
35
30
|
await showAlert({
|
|
@@ -8,6 +8,9 @@ import { DEFAULT_NAME_POOL, NAME_POOL_METADATA_KEY, parseNamePool } from '../con
|
|
|
8
8
|
import { NEW_AGENT_WIZZARD_METADATA_KEY, parseNewAgentWizardMode } from '../constants/newAgentWizard';
|
|
9
9
|
import { getMetadata } from '../database/getMetadata';
|
|
10
10
|
import { $provideAgentCollectionForServer } from '../tools/$provideAgentCollectionForServer';
|
|
11
|
+
import { invalidateCachedActiveOrganizationSnapshots } from '../utils/agentOrganization/loadAgentOrganizationState';
|
|
12
|
+
import { resolveAgentRouteTarget } from '../utils/agentRouting/resolveAgentRouteTarget';
|
|
13
|
+
import { buildAgentChatHref, buildAgentProfileHref } from '../utils/agentRouting/agentRouteHrefs';
|
|
11
14
|
import { type AgentVisibility, parseAgentVisibility } from '../utils/agentVisibility';
|
|
12
15
|
import { authenticateUser } from '../utils/authenticateUser';
|
|
13
16
|
import { createAgentWithDefaultVisibility } from '../utils/createAgentWithDefaultVisibility';
|
|
@@ -15,6 +18,16 @@ import { resolveCurrentUserIdentity } from '../utils/currentUserIdentity';
|
|
|
15
18
|
import { isUserAdmin } from '../utils/isUserAdmin';
|
|
16
19
|
import { clearSession, setSession } from '../utils/session';
|
|
17
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Maximum attempts used to confirm a freshly created agent route resolves before navigation starts.
|
|
23
|
+
*/
|
|
24
|
+
const CREATED_AGENT_ROUTE_READY_ATTEMPTS = 20;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Delay between created-agent route-resolution retries.
|
|
28
|
+
*/
|
|
29
|
+
const CREATED_AGENT_ROUTE_READY_DELAY_MS = 100;
|
|
30
|
+
|
|
18
31
|
/**
|
|
19
32
|
* Creates a new agent from the generated boilerplate template.
|
|
20
33
|
*
|
|
@@ -34,6 +47,8 @@ export async function $createAgentAction(): Promise<{ agentName: string_agent_na
|
|
|
34
47
|
const { agentName, permanentId } = await createAgentWithDefaultVisibility(collection, agentSource, {
|
|
35
48
|
userId: currentUserIdentity?.userId,
|
|
36
49
|
});
|
|
50
|
+
revalidateCreatedAgentPaths(permanentId);
|
|
51
|
+
await waitForCreatedAgentRoute(permanentId);
|
|
37
52
|
|
|
38
53
|
return { agentName, permanentId };
|
|
39
54
|
}
|
|
@@ -63,6 +78,39 @@ export async function $getNewAgentCreationSettingsAction(): Promise<{
|
|
|
63
78
|
};
|
|
64
79
|
}
|
|
65
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Clears cached organization snapshots and route payloads after a new agent is created.
|
|
83
|
+
*
|
|
84
|
+
* @param permanentId - Canonical identifier of the newly created agent.
|
|
85
|
+
*/
|
|
86
|
+
function revalidateCreatedAgentPaths(permanentId: string_agent_permanent_id): void {
|
|
87
|
+
invalidateCachedActiveOrganizationSnapshots();
|
|
88
|
+
revalidatePath('/', 'layout');
|
|
89
|
+
revalidatePath('/');
|
|
90
|
+
revalidatePath('/agents');
|
|
91
|
+
revalidatePath('/dashboard');
|
|
92
|
+
revalidatePath(buildAgentProfileHref(permanentId));
|
|
93
|
+
revalidatePath(buildAgentChatHref(permanentId));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Waits until the new agent can be resolved by the same routing helper the chat page uses.
|
|
98
|
+
*
|
|
99
|
+
* @param permanentId - Canonical identifier of the newly created agent.
|
|
100
|
+
*/
|
|
101
|
+
async function waitForCreatedAgentRoute(permanentId: string_agent_permanent_id): Promise<void> {
|
|
102
|
+
for (let attempt = 0; attempt < CREATED_AGENT_ROUTE_READY_ATTEMPTS; attempt++) {
|
|
103
|
+
const routeTarget = await resolveAgentRouteTarget(permanentId, { forceRefresh: true });
|
|
104
|
+
if (routeTarget?.kind === 'local' && routeTarget.canonicalAgentId === permanentId) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await new Promise((resolve) => setTimeout(resolve, CREATED_AGENT_ROUTE_READY_DELAY_MS));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
throw new Error(`Created agent "${permanentId}" could not be resolved for routing immediately after creation.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
66
114
|
/**
|
|
67
115
|
* Creates a new agent using provided book content.
|
|
68
116
|
*
|
|
@@ -89,6 +137,8 @@ export async function $createAgentFromBookAction(
|
|
|
89
137
|
visibility: visibility ?? undefined,
|
|
90
138
|
userId: currentUserIdentity?.userId,
|
|
91
139
|
});
|
|
140
|
+
revalidateCreatedAgentPaths(permanentId);
|
|
141
|
+
await waitForCreatedAgentRoute(permanentId);
|
|
92
142
|
|
|
93
143
|
return { agentName, permanentId };
|
|
94
144
|
}
|
|
@@ -4,7 +4,6 @@ import { usePromise } from '@common/hooks/usePromise';
|
|
|
4
4
|
import { Chat } from '@promptbook-local/components';
|
|
5
5
|
import { RemoteAgent } from '@promptbook-local/core';
|
|
6
6
|
import { string_book, type ChatMessage } from '@promptbook-local/types';
|
|
7
|
-
import { useRouter } from 'next/navigation';
|
|
8
7
|
import { useCallback, useMemo, useState, type MouseEvent as ReactMouseEvent } from 'react';
|
|
9
8
|
import { spaceTrim } from 'spacetrim';
|
|
10
9
|
import { string_agent_url, string_color } from '../../../../../../src/types/typeAliases';
|
|
@@ -24,6 +23,7 @@ import { useServerLanguage } from '../../../components/ServerLanguage/ServerLang
|
|
|
24
23
|
import { ChatThreadLoadingSkeleton } from '../../../components/Skeleton/ChatThreadLoadingSkeleton';
|
|
25
24
|
import { usePromptbookTheme } from '../../../components/ThemeMode/usePromptbookTheme';
|
|
26
25
|
import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
|
|
26
|
+
import { buildFreshAgentChatHref } from '../../../utils/agentRouting/agentRouteHrefs';
|
|
27
27
|
import { executeQuickActionButton } from '../../../utils/chat/executeQuickActionButton';
|
|
28
28
|
import { resolveChatMessageValidationIssue } from '../../../utils/chat/validateChatMessageContent';
|
|
29
29
|
import { createServerLanguageMoment } from '../../../utils/localization/createServerLanguageMoment';
|
|
@@ -277,7 +277,6 @@ export function AgentProfileChat({
|
|
|
277
277
|
isHistoryEnabled = false,
|
|
278
278
|
areFileAttachmentsEnabled = true,
|
|
279
279
|
}: AgentProfileChatProps) {
|
|
280
|
-
const router = useRouter();
|
|
281
280
|
const [isCreatingAgent, setIsCreatingAgent] = useState(false);
|
|
282
281
|
const [optimisticNavigationState, setOptimisticNavigationState] = useState<OptimisticChatNavigationState | null>(null);
|
|
283
282
|
const { formatText } = useAgentNaming();
|
|
@@ -409,7 +408,7 @@ export function AgentProfileChat({
|
|
|
409
408
|
try {
|
|
410
409
|
const { permanentId } = await $createAgentFromBookAction(bookContent as string_book);
|
|
411
410
|
if (permanentId) {
|
|
412
|
-
|
|
411
|
+
window.location.assign(buildFreshAgentChatHref(permanentId));
|
|
413
412
|
}
|
|
414
413
|
} catch (error) {
|
|
415
414
|
console.error('Failed to create agent:', error);
|
|
@@ -421,7 +420,7 @@ export function AgentProfileChat({
|
|
|
421
420
|
setIsCreatingAgent(false);
|
|
422
421
|
}
|
|
423
422
|
},
|
|
424
|
-
[formatText
|
|
423
|
+
[formatText],
|
|
425
424
|
);
|
|
426
425
|
const handleFileUpload = useCallback(async (file: File) => chatFileUploadHandler(file), []);
|
|
427
426
|
const fallbackInitialMessage = useMemo(() => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ensures the readiness route runs in the same runtime as the standalone server.
|
|
5
|
+
*/
|
|
6
|
+
export const runtime = 'nodejs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Prevents a cached response from hiding readiness failures during deployment handoff.
|
|
10
|
+
*/
|
|
11
|
+
export const dynamic = 'force-dynamic';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Lightweight readiness endpoint used by standalone VPS pm2/nginx handoffs.
|
|
15
|
+
*/
|
|
16
|
+
export async function GET() {
|
|
17
|
+
return NextResponse.json({ status: 'ok' });
|
|
18
|
+
}
|
|
@@ -186,10 +186,7 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
186
186
|
) : (
|
|
187
187
|
<div className="flex h-full w-full items-center justify-center overflow-hidden p-4 md:p-8">
|
|
188
188
|
{/* Keep built-in visuals inside a centered square stage so different avatar renderers fit the tall profile card consistently. */}
|
|
189
|
-
<div
|
|
190
|
-
className="flex h-full w-full max-h-[80%] max-w-[80%] items-center justify-center"
|
|
191
|
-
style={{ aspectRatio: '1 / 1' }}
|
|
192
|
-
>
|
|
189
|
+
<div className="flex aspect-square w-[80%] items-center justify-center">
|
|
193
190
|
<AgentAvatar
|
|
194
191
|
agent={agent}
|
|
195
192
|
baseUrl={publicUrl}
|
|
@@ -9,7 +9,6 @@ import { HamburgerMenu } from '../../../../../src/book-components/_common/Hambur
|
|
|
9
9
|
import { useMenuHoisting } from '../../../../../src/book-components/_common/MenuHoisting/MenuHoistingContext';
|
|
10
10
|
import { just } from '../../../../../src/utils/organization/just';
|
|
11
11
|
import { getVisibleCommitmentDefinitions } from '../../utils/getVisibleCommitmentDefinitions';
|
|
12
|
-
import { pushWithHeadless, useIsHeadless } from '../_utils/headlessParam';
|
|
13
12
|
import { useInstallPromptState, type AgentContextMenuRenamePayload } from '../AgentContextMenu/AgentContextMenu';
|
|
14
13
|
import { useAgentNaming } from '../AgentNaming/AgentNamingContext';
|
|
15
14
|
import { QrCodeModal } from '../AgentProfile/QrCodeModal';
|
|
@@ -58,11 +57,9 @@ export function Header(props: HeaderProps) {
|
|
|
58
57
|
feedbackMode = 'stars',
|
|
59
58
|
shibbolethAuthenticationStatus,
|
|
60
59
|
} = props;
|
|
61
|
-
|
|
62
60
|
const [isChangePasswordOpen, setIsChangePasswordOpen] = useState(false);
|
|
63
61
|
const router = useRouter();
|
|
64
62
|
const pathname = usePathname();
|
|
65
|
-
const isHeadless = useIsHeadless();
|
|
66
63
|
const menuHoisting = useMenuHoisting();
|
|
67
64
|
const mobileMenuHoisting = useMobileMenuHoisting();
|
|
68
65
|
const { naming } = useAgentNaming();
|
|
@@ -73,13 +70,6 @@ export function Header(props: HeaderProps) {
|
|
|
73
70
|
() => buildDocumentationDropdownItems(visibleDocumentationCommitments, t),
|
|
74
71
|
[t, visibleDocumentationCommitments],
|
|
75
72
|
);
|
|
76
|
-
|
|
77
|
-
const fallbackNavigateToHref = useCallback(
|
|
78
|
-
(href: string) => {
|
|
79
|
-
pushWithHeadless(router, href, isHeadless);
|
|
80
|
-
},
|
|
81
|
-
[isHeadless, router],
|
|
82
|
-
);
|
|
83
73
|
const hoistedMobileMenuItems = mobileMenuHoisting?.menuItems || EMPTY_HOISTED_MOBILE_MENU_ITEMS;
|
|
84
74
|
const {
|
|
85
75
|
cancelMenuClose,
|
|
@@ -201,7 +191,6 @@ export function Header(props: HeaderProps) {
|
|
|
201
191
|
isAdmin,
|
|
202
192
|
isAuthenticated: Boolean(currentUser),
|
|
203
193
|
isInstalled,
|
|
204
|
-
navigateToHref: fallbackNavigateToHref,
|
|
205
194
|
namingPlural: naming.plural,
|
|
206
195
|
namingSingular: naming.singular,
|
|
207
196
|
onAgentRenamed: handleAgentRenamedFromHeader,
|
|
@@ -44,7 +44,6 @@ type UseHeaderAgentMenusOptions = {
|
|
|
44
44
|
readonly isAdmin: boolean;
|
|
45
45
|
readonly isAuthenticated: boolean;
|
|
46
46
|
readonly isInstalled: boolean;
|
|
47
|
-
readonly navigateToHref: (href: string) => void;
|
|
48
47
|
readonly namingPlural: string;
|
|
49
48
|
readonly namingSingular: string;
|
|
50
49
|
readonly onAgentRenamed: (payload: AgentContextMenuRenamePayload) => void;
|
|
@@ -160,7 +159,6 @@ export function useHeaderAgentMenus({
|
|
|
160
159
|
isAdmin,
|
|
161
160
|
isAuthenticated,
|
|
162
161
|
isInstalled,
|
|
163
|
-
navigateToHref,
|
|
164
162
|
namingPlural,
|
|
165
163
|
namingSingular,
|
|
166
164
|
onAgentRenamed,
|
|
@@ -214,9 +212,6 @@ export function useHeaderAgentMenus({
|
|
|
214
212
|
openNewAgentDialog,
|
|
215
213
|
dialog: newAgentDialog,
|
|
216
214
|
} = useNewAgentDialog({
|
|
217
|
-
onCreated: ({ targetPath }) => {
|
|
218
|
-
navigateToHref(targetPath);
|
|
219
|
-
},
|
|
220
215
|
onCreateFailed: async (error) => {
|
|
221
216
|
await showNewAgentFailure('Failed to create agent:', error, namingSingular, translate);
|
|
222
217
|
},
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import type { string_book } from '@promptbook-local/types';
|
|
4
4
|
import type { ReactElement } from 'react';
|
|
5
5
|
import { useCallback, useState } from 'react';
|
|
6
|
+
import { appendHeadlessParam, useIsHeadless } from '../_utils/headlessParam';
|
|
6
7
|
import type { AgentVisibility } from '../../utils/agentVisibility';
|
|
8
|
+
import { buildFreshAgentChatHref } from '../../utils/agentRouting/agentRouteHrefs';
|
|
7
9
|
import {
|
|
8
10
|
$createAgentFromBookAction,
|
|
9
11
|
$generateAgentBoilerplateAction,
|
|
@@ -51,9 +53,9 @@ type CreatedAgentPayload = {
|
|
|
51
53
|
*/
|
|
52
54
|
type UseNewAgentDialogOptions = {
|
|
53
55
|
/**
|
|
54
|
-
*
|
|
56
|
+
* Optional callback invoked after the new agent payload is prepared and before navigation starts.
|
|
55
57
|
*/
|
|
56
|
-
readonly onCreated
|
|
58
|
+
readonly onCreated?: (agent: CreatedAgentPayload) => Promise<void> | void;
|
|
57
59
|
/**
|
|
58
60
|
* Optional callback invoked when creating an agent fails.
|
|
59
61
|
*/
|
|
@@ -120,11 +122,27 @@ function extractAgentNameFromBoilerplate(boilerplate: string_book): string {
|
|
|
120
122
|
);
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Creates the navigation payload returned after one agent is persisted.
|
|
127
|
+
*
|
|
128
|
+
* @param agentName - Persisted display name of the agent.
|
|
129
|
+
* @param permanentId - Canonical immutable identifier of the agent.
|
|
130
|
+
* @returns Shared created-agent payload used by all creation surfaces.
|
|
131
|
+
*/
|
|
132
|
+
function createCreatedAgentPayload(agentName: string, permanentId: string): CreatedAgentPayload {
|
|
133
|
+
return {
|
|
134
|
+
agentName,
|
|
135
|
+
permanentId,
|
|
136
|
+
targetPath: buildFreshAgentChatHref(permanentId),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
123
140
|
/**
|
|
124
141
|
* Provides a shared "create new agent" workflow with boilerplate loading and a book-editing dialog.
|
|
125
142
|
*/
|
|
126
143
|
export function useNewAgentDialog(options: UseNewAgentDialogOptions): UseNewAgentDialogResult {
|
|
127
144
|
const { onCreated, onCreateFailed, onPrepareFailed } = options;
|
|
145
|
+
const isHeadless = useIsHeadless();
|
|
128
146
|
const [isPreparingDialog, setIsPreparingDialog] = useState(false);
|
|
129
147
|
const [dialogState, setDialogState] = useState<NewAgentDialogState | null>(null);
|
|
130
148
|
|
|
@@ -132,6 +150,21 @@ export function useNewAgentDialog(options: UseNewAgentDialogOptions): UseNewAgen
|
|
|
132
150
|
setDialogState(null);
|
|
133
151
|
}, []);
|
|
134
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Finalizes one successful creation by hard-navigating to the new chat route.
|
|
155
|
+
*
|
|
156
|
+
* The App Router can transiently keep the just-created dynamic route in a stale not-found
|
|
157
|
+
* state, so new-agent creation intentionally uses a full navigation once the route is ready.
|
|
158
|
+
*/
|
|
159
|
+
const handleCreatedAgent = useCallback(
|
|
160
|
+
async (agent: CreatedAgentPayload) => {
|
|
161
|
+
await onCreated?.(agent);
|
|
162
|
+
setDialogState(null);
|
|
163
|
+
window.location.assign(appendHeadlessParam(agent.targetPath, isHeadless));
|
|
164
|
+
},
|
|
165
|
+
[isHeadless, onCreated],
|
|
166
|
+
);
|
|
167
|
+
|
|
135
168
|
const openNewAgentDialog = useCallback(
|
|
136
169
|
async (openOptions?: OpenNewAgentDialogOptions) => {
|
|
137
170
|
setIsPreparingDialog(true);
|
|
@@ -200,17 +233,12 @@ export function useNewAgentDialog(options: UseNewAgentDialogOptions): UseNewAgen
|
|
|
200
233
|
surface: 'editor',
|
|
201
234
|
folderId: dialogState.targetFolderId,
|
|
202
235
|
});
|
|
203
|
-
await
|
|
204
|
-
agentName,
|
|
205
|
-
permanentId,
|
|
206
|
-
targetPath: `/agents/${encodeURIComponent(permanentId)}`,
|
|
207
|
-
});
|
|
208
|
-
setDialogState(null);
|
|
236
|
+
await handleCreatedAgent(createCreatedAgentPayload(agentName, permanentId));
|
|
209
237
|
} catch (error) {
|
|
210
238
|
await onCreateFailed?.(error);
|
|
211
239
|
}
|
|
212
240
|
},
|
|
213
|
-
[dialogState,
|
|
241
|
+
[dialogState, handleCreatedAgent, onCreateFailed],
|
|
214
242
|
);
|
|
215
243
|
|
|
216
244
|
const handleCreateFromWizard = useCallback(
|
|
@@ -232,17 +260,12 @@ export function useNewAgentDialog(options: UseNewAgentDialogOptions): UseNewAgen
|
|
|
232
260
|
knowledgeCount: request.knowledgeCount,
|
|
233
261
|
});
|
|
234
262
|
|
|
235
|
-
await
|
|
236
|
-
agentName,
|
|
237
|
-
permanentId,
|
|
238
|
-
targetPath: `/agents/${encodeURIComponent(permanentId)}`,
|
|
239
|
-
});
|
|
240
|
-
setDialogState(null);
|
|
263
|
+
await handleCreatedAgent(createCreatedAgentPayload(agentName, permanentId));
|
|
241
264
|
} catch (error) {
|
|
242
265
|
await onCreateFailed?.(error);
|
|
243
266
|
}
|
|
244
267
|
},
|
|
245
|
-
[dialogState,
|
|
268
|
+
[dialogState, handleCreatedAgent, onCreateFailed],
|
|
246
269
|
);
|
|
247
270
|
|
|
248
271
|
const handleOpenEditorFromWizard = useCallback((request: NewAgentWizardOpenEditorRequest) => {
|
|
@@ -53,7 +53,7 @@ export const DEFAULT_AGENT_AVATAR_VISUAL_METADATA_VALUES = DEFAULT_AGENT_AVATAR_
|
|
|
53
53
|
export const DEFAULT_AGENT_AVATAR_VISUAL_METADATA_VALUE =
|
|
54
54
|
DEFAULT_AGENT_AVATAR_VISUAL_METADATA_OPTIONS.find(
|
|
55
55
|
({ visualId }) => visualId === SHARED_DEFAULT_AGENT_AVATAR_VISUAL_ID,
|
|
56
|
-
)?.metadataValue || '
|
|
56
|
+
)?.metadataValue || 'OCTOPUS3D3';
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* Resolves one raw metadata value to a supported built-in avatar visual id.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
INSERT INTO "prefix_Metadata" ("key", "value", "note", "createdAt", "updatedAt")
|
|
2
|
+
SELECT 'DEFAULT_AGENT_AVATAR_VISUAL',
|
|
3
|
+
'OCTOPUS3D3',
|
|
4
|
+
'Default built-in avatar visual used for agents without `META IMAGE` or `META AVATAR`. Allowed values: PIXEL_ART, OCTOPUS, OCTOPUS2, OCTOPUS3, OCTOPUS3D, OCTOPUS3D2, OCTOPUS3D3, ASCII_OCTOPUS, MINECRAFT, MINECRAFT2, FRACTAL, ORB.',
|
|
5
|
+
NOW(),
|
|
6
|
+
NOW()
|
|
7
|
+
WHERE NOT EXISTS (SELECT 1 FROM "prefix_Metadata" WHERE "key" = 'DEFAULT_AGENT_AVATAR_VISUAL');
|
|
8
|
+
|
|
9
|
+
UPDATE "prefix_Metadata"
|
|
10
|
+
SET "value" = CASE
|
|
11
|
+
WHEN UPPER(COALESCE("value", '')) = 'OCTOPUS3' THEN 'OCTOPUS3D3'
|
|
12
|
+
ELSE "value"
|
|
13
|
+
END,
|
|
14
|
+
"note" = 'Default built-in avatar visual used for agents without `META IMAGE` or `META AVATAR`. Allowed values: PIXEL_ART, OCTOPUS, OCTOPUS2, OCTOPUS3, OCTOPUS3D, OCTOPUS3D2, OCTOPUS3D3, ASCII_OCTOPUS, MINECRAFT, MINECRAFT2, FRACTAL, ORB.',
|
|
15
|
+
"updatedAt" = NOW()
|
|
16
|
+
WHERE "key" = 'DEFAULT_AGENT_AVATAR_VISUAL';
|
|
@@ -53,8 +53,9 @@ export const config = {
|
|
|
53
53
|
* - favicon.ico (favicon file)
|
|
54
54
|
* - robots.txt (should not block on middleware DB lookups)
|
|
55
55
|
* - public folder
|
|
56
|
+
* - api/health (standalone VPS readiness probe)
|
|
56
57
|
* - api/internal (worker/cron routes are authorized separately)
|
|
57
58
|
*/
|
|
58
|
-
'/((?!_next/static|_next/image|favicon.ico|logo-|fonts/|robots.txt|api/internal).*)',
|
|
59
|
+
'/((?!_next/static|_next/image|favicon.ico|logo-|fonts/|robots.txt|api/health|api/internal).*)',
|
|
59
60
|
],
|
|
60
61
|
};
|
|
@@ -4,6 +4,20 @@ import { TrackedFilesStorage } from '../utils/cdn/classes/TrackedFilesStorage';
|
|
|
4
4
|
import { VercelBlobStorage } from '../utils/cdn/classes/VercelBlobStorage';
|
|
5
5
|
import { IIFilesStorageWithCdn } from '../utils/cdn/interfaces/IFilesStorage';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Region expected by the bundled VersityGW S3-compatible storage.
|
|
9
|
+
*
|
|
10
|
+
* @private internal default for `$provideCdnForServer`
|
|
11
|
+
*/
|
|
12
|
+
const SELF_CONTAINED_S3_DEFAULT_REGION = 'us-east-1';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Legacy fallback used by Cloudflare R2-style external S3 configuration.
|
|
16
|
+
*
|
|
17
|
+
* @private internal default for `$provideCdnForServer`
|
|
18
|
+
*/
|
|
19
|
+
const EXTERNAL_S3_DEFAULT_REGION = 'auto';
|
|
20
|
+
|
|
7
21
|
/**
|
|
8
22
|
* Cache of CDN instance
|
|
9
23
|
*
|
|
@@ -40,7 +54,7 @@ function createCdnStorageForServer(): IIFilesStorageWithCdn {
|
|
|
40
54
|
cdnPublicUrl: new URL(process.env.NEXT_PUBLIC_CDN_PUBLIC_URL!),
|
|
41
55
|
gzip: true,
|
|
42
56
|
forcePathStyle: process.env.CDN_FORCE_PATH_STYLE === 'true',
|
|
43
|
-
region:
|
|
57
|
+
region: resolveS3CompatibleStorageRegion(),
|
|
44
58
|
});
|
|
45
59
|
}
|
|
46
60
|
|
|
@@ -57,7 +71,7 @@ function createCdnStorageForServer(): IIFilesStorageWithCdn {
|
|
|
57
71
|
* @private helper of `$provideCdnForServer`
|
|
58
72
|
*/
|
|
59
73
|
function isS3CompatibleStorageSelected(): boolean {
|
|
60
|
-
const storageMode = (
|
|
74
|
+
const storageMode = getS3CompatibleStorageMode();
|
|
61
75
|
const isS3StorageMode =
|
|
62
76
|
storageMode === 's3' || storageMode === 'external-s3' || storageMode === 'self-contained-s3';
|
|
63
77
|
|
|
@@ -68,6 +82,33 @@ function isS3CompatibleStorageSelected(): boolean {
|
|
|
68
82
|
return !process.env.VERCEL_BLOB_READ_WRITE_TOKEN && hasS3CompatibleStorageConfiguration();
|
|
69
83
|
}
|
|
70
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Resolves the configured S3-compatible storage mode.
|
|
87
|
+
*
|
|
88
|
+
* @private helper of `$provideCdnForServer`
|
|
89
|
+
*/
|
|
90
|
+
function getS3CompatibleStorageMode(): string {
|
|
91
|
+
return (process.env.PTBK_FILE_STORAGE_MODE || process.env.CDN_PROVIDER || '').toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Resolves the S3 signing region used by AWS SDK requests.
|
|
96
|
+
*
|
|
97
|
+
* @private helper of `$provideCdnForServer`
|
|
98
|
+
*/
|
|
99
|
+
function resolveS3CompatibleStorageRegion(): string {
|
|
100
|
+
const configuredRegion = process.env.CDN_REGION?.trim();
|
|
101
|
+
if (configuredRegion) {
|
|
102
|
+
return configuredRegion;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (getS3CompatibleStorageMode() === 'self-contained-s3') {
|
|
106
|
+
return SELF_CONTAINED_S3_DEFAULT_REGION;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return EXTERNAL_S3_DEFAULT_REGION;
|
|
110
|
+
}
|
|
111
|
+
|
|
71
112
|
/**
|
|
72
113
|
* Checks whether all S3-compatible storage environment variables are present.
|
|
73
114
|
*
|
|
@@ -56,15 +56,21 @@ type PseudoAgentRouteTarget = {
|
|
|
56
56
|
export type AgentRouteTarget = LocalAgentRouteTarget | RemoteAgentRouteTarget | PseudoAgentRouteTarget;
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* Resolves any incoming `/agents/:agentId` token into a canonical target URL.
|
|
59
|
+
* Resolves any incoming `/agents/:agentId` token into a canonical target URL without memoization.
|
|
60
60
|
*
|
|
61
61
|
* Supported inputs include plain IDs/names, `@name`, `{name}`, `{id}`, and absolute `/agents/...` URLs.
|
|
62
62
|
* Pseudo-agent tokens such as `{User}`, `{Void}`, or `{Null}` resolve to dedicated documentation pages.
|
|
63
63
|
*
|
|
64
64
|
* @param rawReference - Raw decoded route parameter value.
|
|
65
|
+
* @param options - Optional cache-bypass controls used by create-agent flows.
|
|
65
66
|
* @returns Canonical local/remote route target or `null` when the reference cannot be resolved.
|
|
66
67
|
*/
|
|
67
|
-
|
|
68
|
+
async function resolveAgentRouteTargetUncached(
|
|
69
|
+
rawReference: string,
|
|
70
|
+
options?: {
|
|
71
|
+
readonly forceRefresh?: boolean;
|
|
72
|
+
},
|
|
73
|
+
): Promise<AgentRouteTarget | null> {
|
|
68
74
|
const parsedBookScopedAgentIdentifier = parseBookScopedAgentIdentifier(rawReference);
|
|
69
75
|
if (parsedBookScopedAgentIdentifier) {
|
|
70
76
|
const { publicUrl } = await $provideServer();
|
|
@@ -96,7 +102,7 @@ const getCachedAgentRouteTarget = cache(async (rawReference: string): Promise<Ag
|
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
const resolver = await $provideAgentReferenceResolver();
|
|
105
|
+
const resolver = await $provideAgentReferenceResolver({ forceRefresh: options?.forceRefresh });
|
|
100
106
|
let resolvedUrlValue: string;
|
|
101
107
|
|
|
102
108
|
try {
|
|
@@ -137,15 +143,32 @@ const getCachedAgentRouteTarget = cache(async (rawReference: string): Promise<Ag
|
|
|
137
143
|
canonicalAgentId,
|
|
138
144
|
canonicalUrl: `${localServerUrl}${AGENT_PATH_PREFIX}${encodeURIComponent(canonicalAgentId)}`,
|
|
139
145
|
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Memoized route-target resolver used for normal page rendering.
|
|
150
|
+
*/
|
|
151
|
+
const getCachedAgentRouteTarget = cache(async (rawReference: string): Promise<AgentRouteTarget | null> => {
|
|
152
|
+
return resolveAgentRouteTargetUncached(rawReference);
|
|
140
153
|
});
|
|
141
154
|
|
|
142
155
|
/**
|
|
143
156
|
* Resolves any incoming `/agents/:agentId` token into a canonical target URL.
|
|
144
157
|
*
|
|
145
158
|
* @param rawReference - Raw decoded route parameter value.
|
|
159
|
+
* @param options - Optional cache-bypass controls used by create-agent flows.
|
|
146
160
|
* @returns Canonical local/remote route target or `null` when the reference cannot be resolved.
|
|
147
161
|
*/
|
|
148
|
-
export async function resolveAgentRouteTarget(
|
|
162
|
+
export async function resolveAgentRouteTarget(
|
|
163
|
+
rawReference: string,
|
|
164
|
+
options?: {
|
|
165
|
+
readonly forceRefresh?: boolean;
|
|
166
|
+
},
|
|
167
|
+
): Promise<AgentRouteTarget | null> {
|
|
168
|
+
if (options?.forceRefresh) {
|
|
169
|
+
return resolveAgentRouteTargetUncached(rawReference, options);
|
|
170
|
+
}
|
|
171
|
+
|
|
149
172
|
return getCachedAgentRouteTarget(rawReference);
|
|
150
173
|
}
|
|
151
174
|
|