@promptbook/cli 0.103.0-51 → 0.103.0-53

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 (114) hide show
  1. package/apps/agents-server/README.md +1 -1
  2. package/apps/agents-server/config.ts +3 -3
  3. package/apps/agents-server/next.config.ts +1 -1
  4. package/apps/agents-server/public/sw.js +16 -0
  5. package/apps/agents-server/src/app/AddAgentButton.tsx +24 -4
  6. package/apps/agents-server/src/app/actions.ts +15 -13
  7. package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +541 -0
  8. package/apps/agents-server/src/app/admin/chat-feedback/page.tsx +22 -0
  9. package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +532 -0
  10. package/apps/agents-server/src/app/admin/chat-history/page.tsx +21 -0
  11. package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +241 -27
  12. package/apps/agents-server/src/app/admin/models/page.tsx +22 -0
  13. package/apps/agents-server/src/app/admin/users/[userId]/UserDetailClient.tsx +131 -0
  14. package/apps/agents-server/src/app/admin/users/[userId]/page.tsx +21 -0
  15. package/apps/agents-server/src/app/admin/users/page.tsx +18 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/AgentQrCode.tsx +3 -3
  17. package/apps/agents-server/src/app/agents/[agentName]/ClearAgentChatFeedbackButton.tsx +63 -0
  18. package/apps/agents-server/src/app/agents/[agentName]/ClearAgentChatHistoryButton.tsx +63 -0
  19. package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +41 -0
  20. package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +74 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/ServiceWorkerRegister.tsx +24 -0
  22. package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +19 -0
  23. package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +67 -0
  24. package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +3 -0
  25. package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +177 -0
  26. package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +3 -0
  27. package/apps/agents-server/src/app/agents/[agentName]/book+chat/AgentBookAndChat.tsx +53 -1
  28. package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +12 -12
  29. package/apps/agents-server/src/app/agents/[agentName]/history/RestoreVersionButton.tsx +46 -0
  30. package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +12 -0
  31. package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +62 -0
  32. package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +80 -0
  33. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +92 -0
  34. package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +92 -0
  35. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +61 -0
  36. package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +102 -0
  37. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +46 -24
  38. package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +47 -0
  39. package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +19 -0
  40. package/apps/agents-server/src/app/api/agents/route.ts +22 -13
  41. package/apps/agents-server/src/app/api/auth/login/route.ts +6 -44
  42. package/apps/agents-server/src/app/api/chat-feedback/[id]/route.ts +38 -0
  43. package/apps/agents-server/src/app/api/chat-feedback/route.ts +157 -0
  44. package/apps/agents-server/src/app/api/chat-history/[id]/route.ts +37 -0
  45. package/apps/agents-server/src/app/api/chat-history/route.ts +147 -0
  46. package/apps/agents-server/src/app/api/federated-agents/route.ts +17 -0
  47. package/apps/agents-server/src/app/api/upload/route.ts +9 -1
  48. package/apps/agents-server/src/app/docs/[docId]/page.tsx +62 -0
  49. package/apps/agents-server/src/app/docs/page.tsx +33 -0
  50. package/apps/agents-server/src/app/layout.tsx +29 -3
  51. package/apps/agents-server/src/app/manifest.ts +109 -0
  52. package/apps/agents-server/src/app/page.tsx +8 -45
  53. package/apps/agents-server/src/app/recycle-bin/RestoreAgentButton.tsx +40 -0
  54. package/apps/agents-server/src/app/recycle-bin/actions.ts +27 -0
  55. package/apps/agents-server/src/app/recycle-bin/page.tsx +58 -0
  56. package/apps/agents-server/src/app/restricted/page.tsx +33 -0
  57. package/apps/agents-server/src/app/test/og-image/README.md +1 -0
  58. package/apps/agents-server/src/app/test/og-image/opengraph-image.tsx +37 -0
  59. package/apps/agents-server/src/app/test/og-image/page.tsx +22 -0
  60. package/apps/agents-server/src/components/Footer/Footer.tsx +175 -0
  61. package/apps/agents-server/src/components/Header/Header.tsx +445 -79
  62. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +46 -14
  63. package/apps/agents-server/src/components/Homepage/AgentsList.tsx +58 -0
  64. package/apps/agents-server/src/components/Homepage/Card.tsx +1 -1
  65. package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +21 -0
  66. package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +183 -0
  67. package/apps/agents-server/src/components/Homepage/ModelsSection.tsx +75 -0
  68. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +28 -3
  69. package/apps/agents-server/src/components/LoginDialog/LoginDialog.tsx +18 -17
  70. package/apps/agents-server/src/components/Portal/Portal.tsx +38 -0
  71. package/apps/agents-server/src/components/UsersList/UsersList.tsx +82 -131
  72. package/apps/agents-server/src/components/UsersList/useUsersAdmin.ts +139 -0
  73. package/apps/agents-server/src/database/metadataDefaults.ts +38 -6
  74. package/apps/agents-server/src/middleware.ts +146 -93
  75. package/apps/agents-server/src/tools/$provideServer.ts +2 -2
  76. package/apps/agents-server/src/utils/authenticateUser.ts +42 -0
  77. package/apps/agents-server/src/utils/chatFeedbackAdmin.ts +96 -0
  78. package/apps/agents-server/src/utils/chatHistoryAdmin.ts +96 -0
  79. package/apps/agents-server/src/utils/getEffectiveFederatedServers.ts +22 -0
  80. package/apps/agents-server/src/utils/getFederatedAgents.ts +31 -8
  81. package/apps/agents-server/src/utils/getFederatedServersFromMetadata.ts +10 -0
  82. package/apps/agents-server/src/utils/getVisibleCommitmentDefinitions.ts +12 -0
  83. package/apps/agents-server/src/utils/isUserAdmin.ts +2 -2
  84. package/apps/agents-server/vercel.json +7 -0
  85. package/esm/index.es.js +344 -11
  86. package/esm/index.es.js.map +1 -1
  87. package/esm/typings/servers.d.ts +8 -1
  88. package/esm/typings/src/_packages/components.index.d.ts +2 -0
  89. package/esm/typings/src/_packages/core.index.d.ts +6 -0
  90. package/esm/typings/src/_packages/types.index.d.ts +2 -0
  91. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  92. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +1 -0
  93. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +7 -0
  94. package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +2 -2
  95. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +10 -0
  96. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgent.d.ts +6 -0
  97. package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +12 -0
  98. package/esm/typings/src/book-components/icons/MicIcon.d.ts +8 -0
  99. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +17 -0
  100. package/esm/typings/src/commitments/MESSAGE/AgentMessageCommitmentDefinition.d.ts +28 -0
  101. package/esm/typings/src/commitments/MESSAGE/UserMessageCommitmentDefinition.d.ts +28 -0
  102. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +38 -0
  103. package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +2 -1
  104. package/esm/typings/src/commitments/index.d.ts +22 -1
  105. package/esm/typings/src/execution/LlmExecutionTools.d.ts +9 -0
  106. package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -0
  107. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +2 -1
  108. package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +10 -1
  109. package/esm/typings/src/utils/normalization/normalizeMessageText.d.ts +9 -0
  110. package/esm/typings/src/utils/normalization/normalizeMessageText.test.d.ts +1 -0
  111. package/esm/typings/src/version.d.ts +1 -1
  112. package/package.json +1 -1
  113. package/umd/index.umd.js +344 -11
  114. package/umd/index.umd.js.map +1 -1
@@ -1,112 +1,51 @@
1
1
  'use client';
2
2
 
3
- import { useState, useEffect } from 'react';
3
+ import { FormEvent, useState } from 'react';
4
4
  import { Card } from '../Homepage/Card';
5
5
  import { Section } from '../Homepage/Section';
6
-
7
- type User = {
8
- id: number;
9
- username: string;
10
- createdAt: string;
11
- updatedAt: string;
12
- isAdmin: boolean;
6
+ import { useUsersAdmin } from './useUsersAdmin';
7
+
8
+ type UsersListProps = {
9
+ /**
10
+ * Whether the UI should allow creating new users.
11
+ *
12
+ * On the main `/` page this should be `false` so that users
13
+ * can only be created from the `/admin/users` page.
14
+ */
15
+ allowCreate?: boolean;
13
16
  };
14
17
 
15
- export function UsersList() {
16
- const [users, setUsers] = useState<User[]>([]);
17
- const [loading, setLoading] = useState(true);
18
- const [error, setError] = useState<string | null>(null);
18
+ export function UsersList({ allowCreate = true }: UsersListProps) {
19
+ const { users, loading, error, createUser, deleteUser, toggleAdmin } = useUsersAdmin();
20
+
19
21
  const [newUsername, setNewUsername] = useState('');
20
22
  const [newPassword, setNewPassword] = useState('');
21
23
  const [newIsAdmin, setNewIsAdmin] = useState(false);
22
24
 
23
- const fetchUsers = async () => {
24
- try {
25
- setLoading(true);
26
- const response = await fetch('/api/users');
27
- if (!response.ok) {
28
- if (response.status === 401) {
29
- // Not authorized, maybe session expired
30
- return;
31
- }
32
- throw new Error('Failed to fetch users');
33
- }
34
- const data = await response.json();
35
- setUsers(data);
36
- } catch (err) {
37
- setError(err instanceof Error ? err.message : 'An error occurred');
38
- } finally {
39
- setLoading(false);
40
- }
41
- };
42
-
43
- useEffect(() => {
44
- fetchUsers();
45
- }, []);
46
-
47
- const handleCreateUser = async (e: React.FormEvent) => {
25
+ const handleCreateUser = async (e: FormEvent) => {
48
26
  e.preventDefault();
49
- setError(null);
50
27
 
51
28
  try {
52
- const response = await fetch('/api/users', {
53
- method: 'POST',
54
- headers: { 'Content-Type': 'application/json' },
55
- body: JSON.stringify({
56
- username: newUsername,
57
- password: newPassword,
58
- isAdmin: newIsAdmin,
59
- }),
29
+ await createUser({
30
+ username: newUsername,
31
+ password: newPassword,
32
+ isAdmin: newIsAdmin,
60
33
  });
61
34
 
62
- if (!response.ok) {
63
- const data = await response.json();
64
- throw new Error(data.error || 'Failed to create user');
65
- }
66
-
67
35
  setNewUsername('');
68
36
  setNewPassword('');
69
37
  setNewIsAdmin(false);
70
- fetchUsers();
71
- } catch (err) {
72
- setError(err instanceof Error ? err.message : 'An error occurred');
38
+ } catch {
39
+ // Error is already handled and exposed via `error` state from the hook
73
40
  }
74
41
  };
75
42
 
76
43
  const handleDeleteUser = async (username: string) => {
77
- if (!confirm(`Are you sure you want to delete user ${username}?`)) return;
78
-
79
- try {
80
- const response = await fetch(`/api/users/${username}`, {
81
- method: 'DELETE',
82
- });
83
-
84
- if (!response.ok) {
85
- const data = await response.json();
86
- throw new Error(data.error || 'Failed to delete user');
87
- }
88
- fetchUsers();
89
- } catch (err) {
90
- setError(err instanceof Error ? err.message : 'An error occurred');
91
- }
44
+ await deleteUser(username);
92
45
  };
93
46
 
94
47
  const handleToggleAdmin = async (username: string, currentIsAdmin: boolean) => {
95
- try {
96
- const response = await fetch(`/api/users/${username}`, {
97
- method: 'PATCH',
98
- headers: { 'Content-Type': 'application/json' },
99
- body: JSON.stringify({ isAdmin: !currentIsAdmin }),
100
- });
101
-
102
- if (!response.ok) {
103
- const data = await response.json();
104
- throw new Error(data.error || 'Failed to update user');
105
- }
106
- fetchUsers();
107
- } catch (err) {
108
- setError(err instanceof Error ? err.message : 'An error occurred');
109
- }
48
+ await toggleAdmin(username, currentIsAdmin);
110
49
  };
111
50
 
112
51
  if (loading) return <div>Loading users...</div>;
@@ -121,17 +60,23 @@ export function UsersList() {
121
60
  <div className="flex justify-between items-start">
122
61
  <div>
123
62
  <h3 className="text-xl font-semibold text-gray-900">{user.username}</h3>
124
- {user.isAdmin && <span className="inline-block bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded mt-1">Admin</span>}
125
- <p className="text-gray-500 text-sm mt-2">Created: {new Date(user.createdAt).toLocaleDateString()}</p>
63
+ {user.isAdmin && (
64
+ <span className="inline-block bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded mt-1">
65
+ Admin
66
+ </span>
67
+ )}
68
+ <p className="text-gray-500 text-sm mt-2">
69
+ Created: {new Date(user.createdAt).toLocaleDateString()}
70
+ </p>
126
71
  </div>
127
72
  <div className="space-x-2">
128
- <button
73
+ <button
129
74
  onClick={() => handleToggleAdmin(user.username, user.isAdmin)}
130
75
  className="text-sm text-blue-600 hover:text-blue-800"
131
76
  >
132
77
  {user.isAdmin ? 'Remove Admin' : 'Make Admin'}
133
78
  </button>
134
- <button
79
+ <button
135
80
  onClick={() => handleDeleteUser(user.username)}
136
81
  className="text-sm text-red-600 hover:text-red-800"
137
82
  >
@@ -141,49 +86,55 @@ export function UsersList() {
141
86
  </div>
142
87
  </Card>
143
88
  ))}
144
-
145
- {/* Create User Form */}
146
- <div className="block p-6 bg-gray-50 rounded-lg border border-dashed border-gray-300">
147
- <h3 className="text-lg font-semibold text-gray-700 mb-4">Add New User</h3>
148
- <form onSubmit={handleCreateUser} className="space-y-3">
149
- <div>
150
- <input
151
- type="text"
152
- placeholder="Username"
153
- value={newUsername}
154
- onChange={(e) => setNewUsername(e.target.value)}
155
- className="w-full p-2 border border-gray-300 rounded"
156
- required
157
- />
158
- </div>
159
- <div>
160
- <input
161
- type="password"
162
- placeholder="Password"
163
- value={newPassword}
164
- onChange={(e) => setNewPassword(e.target.value)}
165
- className="w-full p-2 border border-gray-300 rounded"
166
- required
167
- />
168
- </div>
169
- <div className="flex items-center">
170
- <input
171
- type="checkbox"
172
- id="newIsAdmin"
173
- checked={newIsAdmin}
174
- onChange={(e) => setNewIsAdmin(e.target.checked)}
175
- className="mr-2"
176
- />
177
- <label htmlFor="newIsAdmin" className="text-gray-700">Is Admin</label>
178
- </div>
179
- <button
180
- type="submit"
181
- className="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700 transition-colors"
182
- >
183
- Create User
184
- </button>
185
- </form>
186
- </div>
89
+
90
+ {allowCreate && (
91
+ <div
92
+ id="create-user"
93
+ className="block p-6 bg-gray-50 rounded-lg border border-dashed border-gray-300"
94
+ >
95
+ <h3 className="text-lg font-semibold text-gray-700 mb-4">Add New User</h3>
96
+ <form onSubmit={handleCreateUser} className="space-y-3">
97
+ <div>
98
+ <input
99
+ type="text"
100
+ placeholder="Username"
101
+ value={newUsername}
102
+ onChange={(e) => setNewUsername(e.target.value)}
103
+ className="w-full p-2 border border-gray-300 rounded"
104
+ required
105
+ />
106
+ </div>
107
+ <div>
108
+ <input
109
+ type="password"
110
+ placeholder="Password"
111
+ value={newPassword}
112
+ onChange={(e) => setNewPassword(e.target.value)}
113
+ className="w-full p-2 border border-gray-300 rounded"
114
+ required
115
+ />
116
+ </div>
117
+ <div className="flex items-center">
118
+ <input
119
+ type="checkbox"
120
+ id="newIsAdmin"
121
+ checked={newIsAdmin}
122
+ onChange={(e) => setNewIsAdmin(e.target.checked)}
123
+ className="mr-2"
124
+ />
125
+ <label htmlFor="newIsAdmin" className="text-gray-700">
126
+ Is Admin
127
+ </label>
128
+ </div>
129
+ <button
130
+ type="submit"
131
+ className="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700 transition-colors"
132
+ >
133
+ Create User
134
+ </button>
135
+ </form>
136
+ </div>
137
+ )}
187
138
  </Section>
188
139
  </div>
189
140
  );
@@ -0,0 +1,139 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+
3
+ export type AdminUser = {
4
+ id: number;
5
+ username: string;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ isAdmin: boolean;
9
+ };
10
+
11
+ type CreateUserPayload = {
12
+ username: string;
13
+ password: string;
14
+ isAdmin: boolean;
15
+ };
16
+
17
+ /**
18
+ * Admin users management hook
19
+ *
20
+ * Centralizes fetching and mutating users so it can be reused
21
+ * from multiple places (homepage, admin pages, header menu, etc.).
22
+ */
23
+ export function useUsersAdmin() {
24
+ const [users, setUsers] = useState<AdminUser[]>([]);
25
+ const [loading, setLoading] = useState(true);
26
+ const [error, setError] = useState<string | null>(null);
27
+
28
+ const fetchUsers = useCallback(async () => {
29
+ try {
30
+ setLoading(true);
31
+ setError(null);
32
+
33
+ const response = await fetch('/api/users');
34
+ if (!response.ok) {
35
+ if (response.status === 401) {
36
+ // Not authorized, maybe session expired or non-admin user
37
+ return;
38
+ }
39
+ throw new Error('Failed to fetch users');
40
+ }
41
+
42
+ const data = await response.json();
43
+ setUsers(data);
44
+ } catch (err) {
45
+ setError(err instanceof Error ? err.message : 'An error occurred');
46
+ } finally {
47
+ setLoading(false);
48
+ }
49
+ }, []);
50
+
51
+ useEffect(() => {
52
+ fetchUsers();
53
+ }, [fetchUsers]);
54
+
55
+ const createUser = useCallback(
56
+ async ({ username, password, isAdmin }: CreateUserPayload) => {
57
+ setError(null);
58
+
59
+ try {
60
+ const response = await fetch('/api/users', {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({
64
+ username,
65
+ password,
66
+ isAdmin,
67
+ }),
68
+ });
69
+
70
+ if (!response.ok) {
71
+ const data = await response.json().catch(() => ({}));
72
+ throw new Error(data.error || 'Failed to create user');
73
+ }
74
+
75
+ await fetchUsers();
76
+ } catch (err) {
77
+ setError(err instanceof Error ? err.message : 'An error occurred');
78
+ throw err;
79
+ }
80
+ },
81
+ [fetchUsers],
82
+ );
83
+
84
+ const deleteUser = useCallback(
85
+ async (username: string) => {
86
+ if (!confirm(`Are you sure you want to delete user ${username}?`)) return;
87
+
88
+ try {
89
+ const response = await fetch(`/api/users/${username}`, {
90
+ method: 'DELETE',
91
+ });
92
+
93
+ if (!response.ok) {
94
+ const data = await response.json().catch(() => ({}));
95
+ throw new Error(data.error || 'Failed to delete user');
96
+ }
97
+
98
+ await fetchUsers();
99
+ } catch (err) {
100
+ setError(err instanceof Error ? err.message : 'An error occurred');
101
+ throw err;
102
+ }
103
+ },
104
+ [fetchUsers],
105
+ );
106
+
107
+ const toggleAdmin = useCallback(
108
+ async (username: string, currentIsAdmin: boolean) => {
109
+ try {
110
+ const response = await fetch(`/api/users/${username}`, {
111
+ method: 'PATCH',
112
+ headers: { 'Content-Type': 'application/json' },
113
+ body: JSON.stringify({ isAdmin: !currentIsAdmin }),
114
+ });
115
+
116
+ if (!response.ok) {
117
+ const data = await response.json().catch(() => ({}));
118
+ throw new Error(data.error || 'Failed to update user');
119
+ }
120
+
121
+ await fetchUsers();
122
+ } catch (err) {
123
+ setError(err instanceof Error ? err.message : 'An error occurred');
124
+ throw err;
125
+ }
126
+ },
127
+ [fetchUsers],
128
+ );
129
+
130
+ return {
131
+ users,
132
+ loading,
133
+ error,
134
+ fetchUsers,
135
+ createUser,
136
+ deleteUser,
137
+ toggleAdmin,
138
+ };
139
+ }
@@ -1,37 +1,69 @@
1
+ export type MetadataType = 'TEXT_SINGLE_LINE' | 'TEXT' | 'NUMBER' | 'BOOLEAN' | 'IMAGE_URL' | 'IP_RANGE';
2
+
1
3
  export const metadataDefaults = [
2
4
  {
3
5
  key: 'SERVER_NAME',
4
6
  value: 'Promptbook Agents Server',
5
7
  note: 'The name of the server displayed in the heading bar',
8
+ type: 'TEXT_SINGLE_LINE',
6
9
  },
7
10
  {
8
11
  key: 'SERVER_DESCRIPTION',
9
12
  value: 'Agents server powered by Promptbook',
10
13
  note: 'The description of the server displayed in the search engine results',
11
- },
12
- {
13
- key: 'SERVER_URL',
14
- value: 'https://ptbk.io',
15
- note: 'The URL of the server',
14
+ type: 'TEXT',
16
15
  },
17
16
  {
18
17
  key: 'SERVER_LOGO_URL',
19
18
  value: '',
20
19
  note: 'The URL of the logo displayed in the heading bar',
20
+ type: 'IMAGE_URL',
21
21
  },
22
22
  {
23
23
  key: 'SERVER_FAVICON_URL',
24
24
  value: '',
25
25
  note: 'The URL of the favicon',
26
+ type: 'IMAGE_URL',
26
27
  },
27
28
  {
28
29
  key: 'RESTRICT_IP',
29
30
  value: '',
30
31
  note: 'Comma separated list of allowed IPs or CIDR ranges. If set, only clients from these IPs are allowed to access the server.',
32
+ type: 'IP_RANGE',
31
33
  },
32
34
  {
33
35
  key: 'FEDERATED_SERVERS',
34
36
  value: '',
35
37
  note: 'Comma separated list of federated servers URLs. The server will look to all federated servers and list their agents.',
38
+ type: 'TEXT',
39
+ },
40
+ {
41
+ key: 'IS_VOICE_CALLING_ENABLED',
42
+ value: 'false',
43
+ note: 'Enable or disable voice calling features for agents. When disabled, voice API endpoints will return 403 Forbidden.',
44
+ type: 'BOOLEAN',
45
+ },
46
+ {
47
+ key: 'IS_FOOTER_SHOWN',
48
+ value: 'true',
49
+ note: 'Show or hide the footer.',
50
+ type: 'BOOLEAN',
51
+ },
52
+ {
53
+ key: 'FOOTER_LINKS',
54
+ value: '[]',
55
+ note: 'Extra links to display in the footer, as a JSON array of objects with title and url properties.',
56
+ type: 'TEXT',
57
+ },
58
+ {
59
+ key: 'MAX_FILE_UPLOAD_SIZE_MB',
60
+ value: '50', // <- TODO: [🌲] To /config.ts
61
+ note: 'Maximum size of file that can be uploaded in MB.',
62
+ type: 'NUMBER',
36
63
  },
37
- ] as const;
64
+ ] as const satisfies ReadonlyArray<{
65
+ key: string;
66
+ value: string;
67
+ note: string;
68
+ type: MetadataType;
69
+ }>;