@promptbook/cli 0.104.0-2 → 0.104.0-3
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/package.json +3 -4
- package/apps/agents-server/public/swagger.json +115 -0
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +11 -7
- package/apps/agents-server/src/app/AddAgentButton.tsx +1 -2
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +1 -3
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +29 -16
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +3 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +4 -1
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +8 -6
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +33 -30
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +10 -12
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +1 -2
- package/apps/agents-server/src/app/api/agents/route.ts +1 -1
- package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
- package/apps/agents-server/src/app/api/docs/book.md/route.ts +3 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
- package/apps/agents-server/src/app/api/upload/route.ts +9 -0
- package/apps/agents-server/src/app/page.tsx +1 -1
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +4 -2
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
- package/apps/agents-server/src/components/Header/Header.tsx +27 -5
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +22 -3
- package/apps/agents-server/src/components/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/generated/reservedPaths.ts +6 -1
- package/apps/agents-server/src/middleware.ts +12 -3
- package/apps/agents-server/src/utils/auth.ts +117 -17
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +3 -1
- package/apps/agents-server/src/utils/handleChatCompletion.ts +9 -5
- package/apps/agents-server/src/utils/validateApiKey.ts +5 -10
- package/esm/index.es.js +55 -8
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/types.index.d.ts +2 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +7 -11
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +55 -8
- package/umd/index.umd.js.map +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import Editor from '@monaco-editor/react';
|
|
4
4
|
import { ArrowLeftIcon, ChevronDownIcon, CodeIcon } from 'lucide-react';
|
|
5
5
|
import Link from 'next/link';
|
|
6
|
-
import { useEffect, useState } from 'react';
|
|
6
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
type Transpiler = {
|
|
9
9
|
name: string;
|
|
@@ -61,39 +61,42 @@ export default function AgentCodePage({ params }: { params: Promise<{ agentName:
|
|
|
61
61
|
.catch((err) => console.error('Error fetching transpilers:', err));
|
|
62
62
|
}, [agentName]);
|
|
63
63
|
|
|
64
|
+
const transpileCode = useCallback(
|
|
65
|
+
async (transpilerName: string) => {
|
|
66
|
+
setLoading(true);
|
|
67
|
+
setError('');
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`/agents/${encodeURIComponent(agentName)}/code/api`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: {
|
|
73
|
+
'Content-Type': 'application/json',
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({ transpilerName }),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
const errorData = await response.json();
|
|
80
|
+
throw new Error(errorData.error || 'Failed to transpile code');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result: TranspilationResult = await response.json();
|
|
84
|
+
setTranspiledCode(result.code);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
setError(err instanceof Error ? err.message : 'Failed to transpile code');
|
|
87
|
+
setTranspiledCode('');
|
|
88
|
+
} finally {
|
|
89
|
+
setLoading(false);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
[agentName],
|
|
93
|
+
);
|
|
94
|
+
|
|
64
95
|
useEffect(() => {
|
|
65
96
|
if (selectedTranspiler && agentName) {
|
|
66
97
|
transpileCode(selectedTranspiler.name);
|
|
67
98
|
}
|
|
68
|
-
}, [selectedTranspiler, agentName]);
|
|
69
|
-
|
|
70
|
-
const transpileCode = async (transpilerName: string) => {
|
|
71
|
-
setLoading(true);
|
|
72
|
-
setError('');
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const response = await fetch(`/agents/${encodeURIComponent(agentName)}/code/api`, {
|
|
76
|
-
method: 'POST',
|
|
77
|
-
headers: {
|
|
78
|
-
'Content-Type': 'application/json',
|
|
79
|
-
},
|
|
80
|
-
body: JSON.stringify({ transpilerName }),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
if (!response.ok) {
|
|
84
|
-
const errorData = await response.json();
|
|
85
|
-
throw new Error(errorData.error || 'Failed to transpile code');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const result: TranspilationResult = await response.json();
|
|
89
|
-
setTranspiledCode(result.code);
|
|
90
|
-
} catch (err) {
|
|
91
|
-
setError(err instanceof Error ? err.message : 'Failed to transpile code');
|
|
92
|
-
setTranspiledCode('');
|
|
93
|
-
} finally {
|
|
94
|
-
setLoading(false);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
99
|
+
}, [selectedTranspiler, agentName, transpileCode]);
|
|
97
100
|
|
|
98
101
|
if (!agentProfile) {
|
|
99
102
|
return (
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
// POST /api/agents/[agentName]/clone
|
|
2
1
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
3
|
-
import { AgentBasicInformation } from '../../../../../../../../src/book-2.0/agent-source/AgentBasicInformation';
|
|
4
|
-
import { string_book } from '../../../../../../../../src/book-2.0/agent-source/string_book';
|
|
5
2
|
import { TODO_any } from '@promptbook-local/types';
|
|
6
3
|
import { NextResponse } from 'next/server';
|
|
4
|
+
import { string_book } from '../../../../../../../../src/book-2.0/agent-source/string_book';
|
|
7
5
|
|
|
8
6
|
export async function POST(request: Request, { params }: { params: Promise<{ agentName: string }> }) {
|
|
9
7
|
const { agentName } = await params;
|
|
@@ -21,14 +19,14 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
21
19
|
while (true) {
|
|
22
20
|
try {
|
|
23
21
|
await collection.getAgentSource(newAgentName);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
// If success, it means it exists, so we try next one
|
|
23
|
+
counter++;
|
|
24
|
+
newAgentName = `${agentName} (Copy ${counter})`;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// If error, it likely means it does not exist (NotFoundError), so we can use it
|
|
27
|
+
// TODO: [🧠] Check if it is really NotFoundError
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
const lines = source.split('\n');
|
|
@@ -36,7 +34,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ age
|
|
|
36
34
|
const newSource = lines.join('\n') as string_book;
|
|
37
35
|
|
|
38
36
|
const newAgent = await collection.createAgent(newSource);
|
|
39
|
-
|
|
37
|
+
|
|
40
38
|
return NextResponse.json(newAgent);
|
|
41
39
|
} catch (error) {
|
|
42
40
|
return NextResponse.json(
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { $getTableName } from '@/src/database/$getTableName';
|
|
5
5
|
import { $provideSupabaseForServer } from '@/src/database/$provideSupabaseForServer';
|
|
6
6
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
7
|
-
import { $provideServer } from '@/src/tools/$provideServer';
|
|
8
7
|
import { TODO_any } from '@promptbook-local/types';
|
|
9
8
|
import { NextResponse } from 'next/server';
|
|
10
9
|
|
|
@@ -23,7 +22,7 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ ag
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
const supabase = $provideSupabaseForServer();
|
|
26
|
-
const { tablePrefix } = await $provideServer();
|
|
25
|
+
// const { tablePrefix } = await $provideServer();
|
|
27
26
|
|
|
28
27
|
const updateResult = await supabase
|
|
29
28
|
.from(await $getTableName(`Agent`))
|
|
@@ -12,7 +12,7 @@ export async function GET() {
|
|
|
12
12
|
const collection = await $provideAgentCollectionForServer();
|
|
13
13
|
const allAgents = await collection.listAgents();
|
|
14
14
|
const federatedServers = await getFederatedServersFromMetadata();
|
|
15
|
-
const { publicUrl
|
|
15
|
+
const { publicUrl } = await $provideServer();
|
|
16
16
|
|
|
17
17
|
// Filter to only include PUBLIC agents for federated API
|
|
18
18
|
const supabase = $provideSupabaseForServer();
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
1
4
|
import { $getTableName } from '../../../database/$getTableName';
|
|
2
5
|
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
3
6
|
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
4
|
-
import { randomUUID } from 'crypto';
|
|
5
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
6
7
|
|
|
7
8
|
export async function GET(request: NextRequest) {
|
|
9
|
+
keepUnused(request);
|
|
10
|
+
|
|
8
11
|
if (!(await isUserAdmin())) {
|
|
9
12
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
10
13
|
}
|
|
@@ -35,11 +38,7 @@ export async function POST(request: NextRequest) {
|
|
|
35
38
|
const supabase = $provideSupabase();
|
|
36
39
|
const table = await $getTableName('ApiTokens');
|
|
37
40
|
|
|
38
|
-
const { data, error } = await supabase
|
|
39
|
-
.from(table)
|
|
40
|
-
.insert({ token, note })
|
|
41
|
-
.select()
|
|
42
|
-
.single();
|
|
41
|
+
const { data, error } = await supabase.from(table).insert({ token, note }).select().single();
|
|
43
42
|
|
|
44
43
|
if (error) {
|
|
45
44
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import spaceTrim from 'spacetrim';
|
|
3
3
|
import { getGroupedCommitmentDefinitions } from '../../../../../../../src/commitments';
|
|
4
|
+
import { keepUnused } from '../../../../../../../src/utils/organization/keepUnused';
|
|
4
5
|
|
|
5
6
|
export const dynamic = 'force-static';
|
|
6
7
|
|
|
7
8
|
export async function GET(request: NextRequest) {
|
|
9
|
+
keepUnused(request);
|
|
10
|
+
|
|
8
11
|
const groupedCommitments = getGroupedCommitmentDefinitions();
|
|
9
12
|
|
|
10
13
|
const content = spaceTrim(
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
1
3
|
import { $getTableName } from '../../../database/$getTableName';
|
|
2
4
|
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
3
5
|
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
4
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
5
6
|
|
|
6
7
|
export async function GET(request: NextRequest) {
|
|
8
|
+
keepUnused(request);
|
|
9
|
+
|
|
7
10
|
if (!(await isUserAdmin())) {
|
|
8
11
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
9
12
|
}
|
|
@@ -36,11 +39,7 @@ export async function POST(request: NextRequest) {
|
|
|
36
39
|
const supabase = $provideSupabase();
|
|
37
40
|
const table = await $getTableName('Metadata');
|
|
38
41
|
|
|
39
|
-
const { data, error } = await supabase
|
|
40
|
-
.from(table)
|
|
41
|
-
.insert({ key, value, note })
|
|
42
|
-
.select()
|
|
43
|
-
.single();
|
|
42
|
+
const { data, error } = await supabase.from(table).insert({ key, value, note }).select().single();
|
|
44
43
|
|
|
45
44
|
if (error) {
|
|
46
45
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
@@ -155,3 +155,12 @@ export async function POST(request: NextRequest) {
|
|
|
155
155
|
);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* TODO: !!!! Change uploaded URLs from `storageUrl` to `shortUrl`
|
|
161
|
+
* TODO: !!!! Record both `storageUrl` (actual storage location) and `shortUrl` in `File` table
|
|
162
|
+
* TODO: !!!! Record `purpose` in `File` table
|
|
163
|
+
* TODO: !!!! Record `userId` in `File` table
|
|
164
|
+
* TODO: !!!! Record all things into `File` table
|
|
165
|
+
* TODO: !!!! File type (mime type) of `.book` files should be `application/book` <- [🧠] !!!! Best mime type?!
|
|
166
|
+
*/
|
|
@@ -42,7 +42,7 @@ export default async function HomePage() {
|
|
|
42
42
|
|
|
43
43
|
// Filter agents based on visibility and user authentication
|
|
44
44
|
const supabase = $provideSupabaseForServer();
|
|
45
|
-
const { tablePrefix } = await $provideServer();
|
|
45
|
+
// const { tablePrefix } = await $provideServer();
|
|
46
46
|
|
|
47
47
|
// Get visibility for all agents
|
|
48
48
|
const visibilityResult = await supabase
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import dynamic from 'next/dynamic';
|
|
4
|
+
import 'swagger-ui-react/swagger-ui.css';
|
|
5
|
+
|
|
6
|
+
const SwaggerUI = dynamic(() => import('swagger-ui-react'), { ssr: false });
|
|
7
|
+
|
|
8
|
+
export default function SwaggerPage() {
|
|
9
|
+
return (
|
|
10
|
+
<div className="swagger-container bg-white min-h-screen">
|
|
11
|
+
<SwaggerUI url="/swagger.json" />
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -78,7 +78,7 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
78
78
|
|
|
79
79
|
if (fontString) {
|
|
80
80
|
// [🧠] TODO: Properly parse font string to get family name
|
|
81
|
-
const primaryFont = fontString.split(',')[0].trim().replace(/['"]/g, '');
|
|
81
|
+
// const primaryFont = fontString.split(',')[0].trim().replace(/['"]/g, '');
|
|
82
82
|
fontStyle = {
|
|
83
83
|
fontFamily: fontString,
|
|
84
84
|
};
|
|
@@ -139,8 +139,10 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
139
139
|
backfaceVisibility: 'hidden',
|
|
140
140
|
backgroundColor: brandColorDarkHex,
|
|
141
141
|
boxShadow: `0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px ${brandColorLightHex}40`,
|
|
142
|
+
|
|
143
|
+
// Note: Make it squircle
|
|
142
144
|
// borderRadius: '50%',
|
|
143
|
-
// ['cornerShape' as really_any]: 'squircle ',
|
|
145
|
+
// ['cornerShape' as really_any /* <- Note: `cornerShape` is non standard CSS property */]: 'squircle ',
|
|
144
146
|
}}
|
|
145
147
|
>
|
|
146
148
|
{imageUrl ? (
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { useRouter } from 'next/navigation';
|
|
5
4
|
|
|
6
5
|
type AuthControlsProps = {
|
|
7
6
|
initialUser: { username: string; isAdmin: boolean } | null;
|
|
8
7
|
};
|
|
9
8
|
|
|
10
9
|
export function AuthControls({ initialUser }: AuthControlsProps) {
|
|
11
|
-
const router = useRouter();
|
|
12
|
-
const [user
|
|
10
|
+
// const router = useRouter();
|
|
11
|
+
const [user] = useState(initialUser);
|
|
13
12
|
const [isLoginOpen, setIsLoginOpen] = useState(false);
|
|
14
13
|
const [username, setUsername] = useState('');
|
|
15
14
|
const [password, setPassword] = useState('');
|
|
@@ -52,7 +51,9 @@ export function AuthControls({ initialUser }: AuthControlsProps) {
|
|
|
52
51
|
<div className="flex items-center space-x-4">
|
|
53
52
|
<span className="text-gray-600">
|
|
54
53
|
Logged in as <strong>{user.username}</strong>
|
|
55
|
-
{user.isAdmin &&
|
|
54
|
+
{user.isAdmin && (
|
|
55
|
+
<span className="ml-2 bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded">Admin</span>
|
|
56
|
+
)}
|
|
56
57
|
</span>
|
|
57
58
|
<button
|
|
58
59
|
onClick={handleLogout}
|
|
@@ -4,7 +4,6 @@ import promptbookLogoBlueTransparent from '@/public/logo-blue-white-256.png';
|
|
|
4
4
|
import { $createAgentAction, logoutAction } from '@/src/app/actions';
|
|
5
5
|
import { ArrowRight, ChevronDown, Lock, LogIn, LogOut, User } from 'lucide-react';
|
|
6
6
|
import Image from 'next/image';
|
|
7
|
-
import { HeadlessLink, useIsHeadless, pushWithHeadless } from '../_utils/headlessParam';
|
|
8
7
|
import { useRouter } from 'next/navigation';
|
|
9
8
|
import { ReactNode, useState } from 'react';
|
|
10
9
|
import { AgentBasicInformation } from '../../../../../src/book-2.0/agent-source/AgentBasicInformation';
|
|
@@ -13,6 +12,7 @@ import { useMenuHoisting } from '../../../../../src/book-components/_common/Menu
|
|
|
13
12
|
import { just } from '../../../../../src/utils/organization/just';
|
|
14
13
|
import type { UserInfo } from '../../utils/getCurrentUser';
|
|
15
14
|
import { getVisibleCommitmentDefinitions } from '../../utils/getVisibleCommitmentDefinitions';
|
|
15
|
+
import { HeadlessLink, pushWithHeadless, useIsHeadless } from '../_utils/headlessParam';
|
|
16
16
|
import { ChangePasswordDialog } from '../ChangePasswordDialog/ChangePasswordDialog';
|
|
17
17
|
import { LoginDialog } from '../LoginDialog/LoginDialog';
|
|
18
18
|
import { useUsersAdmin } from '../UsersList/useUsersAdmin';
|
|
@@ -119,16 +119,22 @@ export function Header(props: HeaderProps) {
|
|
|
119
119
|
|
|
120
120
|
// Federated servers dropdown items (respect logo, only current is not clickable)
|
|
121
121
|
const [isFederatedOpen, setIsFederatedOpen] = useState(false);
|
|
122
|
-
const [isMobileFederatedOpen, setIsMobileFederatedOpen] = useState(false);
|
|
122
|
+
// const [isMobileFederatedOpen, setIsMobileFederatedOpen] = useState(false);
|
|
123
123
|
|
|
124
|
-
const federatedDropdownItems: SubMenuItem[] = federatedServers.map(server => {
|
|
124
|
+
const federatedDropdownItems: SubMenuItem[] = federatedServers.map((server) => {
|
|
125
125
|
const isCurrent = server.url === (typeof window !== 'undefined' ? window.location.origin : '');
|
|
126
126
|
return isCurrent
|
|
127
127
|
? {
|
|
128
128
|
label: (
|
|
129
129
|
<span className="flex items-center gap-2">
|
|
130
130
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
131
|
-
<img
|
|
131
|
+
<img
|
|
132
|
+
src={server.logoUrl || serverLogoUrl || promptbookLogoBlueTransparent.src}
|
|
133
|
+
alt={server.title}
|
|
134
|
+
width={20}
|
|
135
|
+
height={20}
|
|
136
|
+
className="w-5 h-5 object-contain rounded-full"
|
|
137
|
+
/>
|
|
132
138
|
<span className="font-semibold">{server.title.replace(/^Federated: /, '')}</span>
|
|
133
139
|
<span className="ml-1 text-xs text-blue-600">(current)</span>
|
|
134
140
|
</span>
|
|
@@ -140,7 +146,13 @@ export function Header(props: HeaderProps) {
|
|
|
140
146
|
label: (
|
|
141
147
|
<span className="flex items-center gap-2">
|
|
142
148
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
143
|
-
<img
|
|
149
|
+
<img
|
|
150
|
+
src={server.logoUrl || promptbookLogoBlueTransparent.src}
|
|
151
|
+
alt={server.title}
|
|
152
|
+
width={20}
|
|
153
|
+
height={20}
|
|
154
|
+
className="w-5 h-5 object-contain rounded-full"
|
|
155
|
+
/>
|
|
144
156
|
<span>{server.title.replace(/^Federated: /, '')}</span>
|
|
145
157
|
</span>
|
|
146
158
|
),
|
|
@@ -169,6 +181,12 @@ export function Header(props: HeaderProps) {
|
|
|
169
181
|
isBold: true,
|
|
170
182
|
isBordered: true,
|
|
171
183
|
} as SubMenuItem,
|
|
184
|
+
{
|
|
185
|
+
label: 'API Reference',
|
|
186
|
+
href: '/swagger',
|
|
187
|
+
isBold: true,
|
|
188
|
+
isBordered: true,
|
|
189
|
+
} as SubMenuItem,
|
|
172
190
|
...getVisibleCommitmentDefinitions().map(
|
|
173
191
|
({ primary, aliases }) =>
|
|
174
192
|
({
|
|
@@ -263,6 +281,10 @@ export function Header(props: HeaderProps) {
|
|
|
263
281
|
isMobileOpen: isMobileSystemOpen,
|
|
264
282
|
setIsMobileOpen: setIsMobileSystemOpen,
|
|
265
283
|
items: [
|
|
284
|
+
{
|
|
285
|
+
label: 'OpenAPI Documentation',
|
|
286
|
+
href: '/swagger',
|
|
287
|
+
},
|
|
266
288
|
{
|
|
267
289
|
label: 'API Tokens',
|
|
268
290
|
href: '/admin/api-tokens',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { really_any } from '@promptbook-local/types';
|
|
3
4
|
import { EyeIcon, EyeOffIcon, RotateCcwIcon } from 'lucide-react';
|
|
4
5
|
import Link from 'next/link';
|
|
5
6
|
import { AgentBasicInformation } from '../../../../../src/book-2.0/agent-source/AgentBasicInformation';
|
|
@@ -19,7 +20,16 @@ type AgentCardProps = {
|
|
|
19
20
|
const ACTION_BUTTON_CLASSES =
|
|
20
21
|
'text-white px-3 py-1 rounded shadow text-xs font-medium transition-colors uppercase tracking-wider opacity-80 hover:opacity-100';
|
|
21
22
|
|
|
22
|
-
export function AgentCard({
|
|
23
|
+
export function AgentCard({
|
|
24
|
+
agent,
|
|
25
|
+
href,
|
|
26
|
+
isAdmin,
|
|
27
|
+
onDelete,
|
|
28
|
+
onClone,
|
|
29
|
+
onToggleVisibility,
|
|
30
|
+
onRestore,
|
|
31
|
+
visibility,
|
|
32
|
+
}: AgentCardProps) {
|
|
23
33
|
const { meta, agentName } = agent;
|
|
24
34
|
const fullname = (meta.fullname as string) || agentName || 'Agent';
|
|
25
35
|
const imageUrl = (meta.image as string) || null;
|
|
@@ -41,9 +51,14 @@ export function AgentCard({ agent, href, isAdmin, onDelete, onClone, onToggleVis
|
|
|
41
51
|
<div className="p-6 flex flex-col items-center flex-grow backdrop-blur-[2px]">
|
|
42
52
|
{/* Image container */}
|
|
43
53
|
<div
|
|
44
|
-
className="w-32 h-32 mb-4
|
|
54
|
+
className="w-32 h-32 mb-4 shadow-lg overflow-hidden flex-shrink-0 bg-black/20"
|
|
45
55
|
style={{
|
|
46
56
|
boxShadow: `0 10px 20px -5px rgba(0, 0, 0, 0.2), 0 0 0 1px ${brandColorLightHex}40`,
|
|
57
|
+
|
|
58
|
+
// Note: Make it squircle
|
|
59
|
+
borderRadius: '50%',
|
|
60
|
+
['cornerShape' as really_any /* <- Note: `cornerShape` is non standard CSS property */]:
|
|
61
|
+
'squircle ',
|
|
47
62
|
}}
|
|
48
63
|
>
|
|
49
64
|
{imageUrl ? (
|
|
@@ -89,7 +104,11 @@ export function AgentCard({ agent, href, isAdmin, onDelete, onClone, onToggleVis
|
|
|
89
104
|
{isAdmin && !onRestore && (
|
|
90
105
|
<div className="absolute top-2 right-2 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity z-10">
|
|
91
106
|
<button
|
|
92
|
-
className={`${
|
|
107
|
+
className={`${
|
|
108
|
+
visibility === 'PUBLIC'
|
|
109
|
+
? 'bg-green-500 hover:bg-green-600'
|
|
110
|
+
: 'bg-gray-500 hover:bg-gray-600'
|
|
111
|
+
} ${ACTION_BUTTON_CLASSES}`}
|
|
93
112
|
onClick={(e) => {
|
|
94
113
|
e.preventDefault();
|
|
95
114
|
onToggleVisibility?.(agent.permanentId || agent.agentName);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Utility to append ?headless param if present in current URL
|
|
2
|
-
import { usePathname, useSearchParams } from 'next/navigation';
|
|
3
2
|
import Link, { LinkProps } from 'next/link';
|
|
3
|
+
import { useSearchParams } from 'next/navigation';
|
|
4
4
|
import { useMemo } from 'react';
|
|
5
5
|
|
|
6
6
|
// Returns true if ?headless is present in current search params
|
|
@@ -18,7 +18,11 @@ export function appendHeadlessParam(href: string, isHeadless: boolean): string {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// Custom Link that preserves headless param
|
|
21
|
-
export function HeadlessLink({
|
|
21
|
+
export function HeadlessLink({
|
|
22
|
+
href,
|
|
23
|
+
children,
|
|
24
|
+
...rest
|
|
25
|
+
}: LinkProps & { children: React.ReactNode } & React.AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
22
26
|
const isHeadless = useIsHeadless();
|
|
23
27
|
const finalHref = useMemo(() => appendHeadlessParam(String(href), isHeadless), [href, isHeadless]);
|
|
24
28
|
return (
|
|
@@ -28,7 +32,7 @@ export function HeadlessLink({ href, children, ...rest }: LinkProps & { children
|
|
|
28
32
|
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
import { useRouter } from
|
|
35
|
+
import { useRouter } from 'next/navigation';
|
|
32
36
|
|
|
33
37
|
// Helper for router.push
|
|
34
38
|
export function pushWithHeadless(router: ReturnType<typeof useRouter>, href: string, isHeadless: boolean) {
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
6
6
|
*
|
|
7
|
-
* @see /apps/agents-server/src/app - source directory
|
|
7
|
+
* @see /apps/agents-server/src/app - source directory for routes
|
|
8
|
+
* @see /apps/agents-server/public - source directory for static files
|
|
8
9
|
* @see /apps/agents-server/src/middleware.ts - where this is used
|
|
9
10
|
*/
|
|
10
11
|
export const RESERVED_PATHS: readonly string[] = [
|
|
@@ -15,7 +16,9 @@ export const RESERVED_PATHS: readonly string[] = [
|
|
|
15
16
|
"docs",
|
|
16
17
|
"embed",
|
|
17
18
|
"favicon.ico",
|
|
19
|
+
"fonts",
|
|
18
20
|
"humans.txt",
|
|
21
|
+
"logo-blue-white-256.png",
|
|
19
22
|
"manifest.webmanifest",
|
|
20
23
|
"recycle-bin",
|
|
21
24
|
"restricted",
|
|
@@ -23,5 +26,7 @@ export const RESERVED_PATHS: readonly string[] = [
|
|
|
23
26
|
"security.txt",
|
|
24
27
|
"sitemap.xml",
|
|
25
28
|
"sw.js",
|
|
29
|
+
"swagger",
|
|
30
|
+
"swagger.json",
|
|
26
31
|
"test"
|
|
27
32
|
] as const;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TODO_any } from '@promptbook-local/types';
|
|
2
2
|
import { createClient } from '@supabase/supabase-js';
|
|
3
3
|
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
-
import { SERVERS
|
|
4
|
+
import { SERVERS } from '../config';
|
|
5
5
|
import { $getTableName } from './database/$getTableName';
|
|
6
6
|
import { RESERVED_PATHS } from './generated/reservedPaths';
|
|
7
7
|
import { isIpAllowed } from './utils/isIpAllowed';
|
|
@@ -9,7 +9,7 @@ import { isIpAllowed } from './utils/isIpAllowed';
|
|
|
9
9
|
// Note: Re-implementing normalizeTo_PascalCase to avoid importing from @promptbook-local/utils which might have Node.js dependencies !!!!
|
|
10
10
|
function normalizeTo_PascalCase(text: string): string {
|
|
11
11
|
return text
|
|
12
|
-
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word
|
|
12
|
+
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => {
|
|
13
13
|
return word.toUpperCase();
|
|
14
14
|
})
|
|
15
15
|
.replace(/\s+/g, '');
|
|
@@ -35,8 +35,12 @@ export async function middleware(req: NextRequest) {
|
|
|
35
35
|
const host = req.headers.get('host');
|
|
36
36
|
|
|
37
37
|
if (host) {
|
|
38
|
+
/*
|
|
39
|
+
Note: [🐔] This code was commented out because results of it are unused
|
|
40
|
+
|
|
38
41
|
let tablePrefix = SUPABASE_TABLE_PREFIX;
|
|
39
42
|
|
|
43
|
+
|
|
40
44
|
if (SERVERS && SERVERS.length > 0) {
|
|
41
45
|
// Logic mirrored from src/tools/$provideServer.ts
|
|
42
46
|
if (SERVERS.some((server) => server === host)) {
|
|
@@ -46,6 +50,7 @@ export async function middleware(req: NextRequest) {
|
|
|
46
50
|
tablePrefix = `server_${serverName}_`;
|
|
47
51
|
}
|
|
48
52
|
}
|
|
53
|
+
*/
|
|
49
54
|
|
|
50
55
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
51
56
|
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
@@ -84,6 +89,9 @@ export async function middleware(req: NextRequest) {
|
|
|
84
89
|
const token = authHeader.split(' ')[1];
|
|
85
90
|
|
|
86
91
|
if (token.startsWith('ptbk_')) {
|
|
92
|
+
/*
|
|
93
|
+
Note: [🐔] This code was commented out because results of it are unused
|
|
94
|
+
|
|
87
95
|
const host = req.headers.get('host');
|
|
88
96
|
let tablePrefix = SUPABASE_TABLE_PREFIX;
|
|
89
97
|
|
|
@@ -95,6 +103,7 @@ export async function middleware(req: NextRequest) {
|
|
|
95
103
|
tablePrefix = `server_${serverName}_`;
|
|
96
104
|
}
|
|
97
105
|
}
|
|
106
|
+
*/
|
|
98
107
|
|
|
99
108
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
100
109
|
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
@@ -230,7 +239,7 @@ export async function middleware(req: NextRequest) {
|
|
|
230
239
|
let serverName = serverHost;
|
|
231
240
|
serverName = serverName.replace(/\.ptbk\.io$/, '');
|
|
232
241
|
serverName = normalizeTo_PascalCase(serverName);
|
|
233
|
-
const prefix = `server_${serverName}_`;
|
|
242
|
+
// const prefix = `server_${serverName}_`;
|
|
234
243
|
|
|
235
244
|
// Search for agent with matching META LINK
|
|
236
245
|
// agentProfile->links is an array of strings
|