@promptbook/cli 0.112.0-135 → 0.112.0-136
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/README.md +0 -1
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +246 -15
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +237 -4
- package/apps/agents-server/src/app/api/admin/update/log/route.ts +42 -0
- package/apps/agents-server/src/app/api/agents/export/route.ts +41 -0
- package/apps/agents-server/src/app/api/agents/import/route.ts +168 -0
- package/apps/agents-server/src/app/api/federated-agents/route.ts +1 -1
- package/apps/agents-server/src/app/api/metadata/export/route.ts +34 -0
- package/apps/agents-server/src/app/api/metadata/import/route.ts +46 -0
- package/apps/agents-server/src/app/layout.tsx +1 -1
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +31 -1
- package/apps/agents-server/src/components/Homepage/AgentsListHeader.tsx +60 -1
- package/apps/agents-server/src/components/Homepage/useAgentsListImportExportState.ts +523 -0
- package/apps/agents-server/src/components/Homepage/useAgentsListState.ts +16 -0
- package/apps/agents-server/src/database/metadataDefaults.ts +0 -21
- package/apps/agents-server/src/database/seedCoreAgents.ts +235 -0
- package/apps/agents-server/src/database/seedDefaultAgents.ts +32 -1
- package/apps/agents-server/src/search/createDefaultServerSearchProviders/createFederatedAgentsSearchProvider.ts +1 -1
- package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +2 -9
- package/apps/agents-server/src/utils/agentsTransfer/createAgentsExportZipStream.ts +68 -0
- package/apps/agents-server/src/utils/agentsTransfer/importAgentsFromFiles.ts +852 -0
- package/apps/agents-server/src/utils/backup/createBooksBackupZipStream.ts +15 -2
- package/apps/agents-server/src/utils/defaultAgents/loadDefaultAgentBooks.ts +46 -4
- package/apps/agents-server/src/utils/getFederatedServers.ts +3 -74
- package/apps/agents-server/src/utils/getWellKnownAgentUrl.ts +10 -4
- package/apps/agents-server/src/utils/metadataConfigurationTransfer.ts +426 -0
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/bootstrapManagedServer.ts +2 -5
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +162 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +110 -0
- package/esm/index.es.js +1 -1
- package/esm/src/_packages/core.index.d.ts +0 -2
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/servers.ts +1 -16
- package/src/_packages/core.index.ts +0 -2
- package/src/other/templates/getTemplatesPipelineCollection.ts +770 -721
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +1 -1
- package/umd/src/_packages/core.index.d.ts +0 -2
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/utils/defaultFederatedAgents/DefaultFederatedAgentsSyncOptions.ts +0 -9
- package/apps/agents-server/src/utils/defaultFederatedAgents/ensureDefaultFederatedAgentExists.ts +0 -277
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchCoreOrganizationPayload.ts +0 -39
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchFederatedAgentBook.ts +0 -43
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchWithDefaultFederatedAgentTimeout.ts +0 -28
- package/apps/agents-server/src/utils/defaultFederatedAgents/getDefaultFederatedAgentSyncPool.ts +0 -38
- package/apps/agents-server/src/utils/defaultFederatedAgents/loadActiveLocalAgentIdsByNormalizedName.ts +0 -41
- package/apps/agents-server/src/utils/defaultFederatedAgents/loadDefaultFederatedAgentSyncMetadata.ts +0 -76
- package/apps/agents-server/src/utils/defaultFederatedAgents/quoteIdentifier.ts +0 -11
- package/apps/agents-server/src/utils/defaultFederatedAgents/scheduleDefaultFederatedAgentsSync.ts +0 -88
- package/apps/agents-server/src/utils/defaultFederatedAgents/selectDefaultFederatedAgentsFromOrganizationPayload.ts +0 -181
- package/apps/agents-server/src/utils/defaultFederatedAgents/synchronizeDefaultFederatedAgents.ts +0 -77
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from './useAgentsListDragState';
|
|
16
16
|
import { useAgentsListFolderPathRecovery } from './useAgentsListFolderPathRecovery';
|
|
17
17
|
import { useAgentsListFolderState } from './useAgentsListFolderState';
|
|
18
|
+
import { useAgentsListImportExportState } from './useAgentsListImportExportState';
|
|
18
19
|
import { useAgentsListNavigationState } from './useAgentsListNavigationState';
|
|
19
20
|
import { useAgentsListOrganizationActions } from './useAgentsListOrganizationActions';
|
|
20
21
|
import { useAgentsListOverlayDetailsState } from './useAgentsListOverlayDetailsState';
|
|
@@ -166,6 +167,10 @@ export function useAgentsListState(props: UseAgentsListStateProps) {
|
|
|
166
167
|
setFolders,
|
|
167
168
|
synchronizeAfterMutation,
|
|
168
169
|
});
|
|
170
|
+
const importExportState = useAgentsListImportExportState({
|
|
171
|
+
currentFolderId,
|
|
172
|
+
synchronizeAfterMutation,
|
|
173
|
+
});
|
|
169
174
|
const agentState = useAgentsListAgentState({
|
|
170
175
|
agents,
|
|
171
176
|
formatText,
|
|
@@ -255,6 +260,13 @@ export function useAgentsListState(props: UseAgentsListStateProps) {
|
|
|
255
260
|
handleDragEnd: dragState.handleDragEnd,
|
|
256
261
|
handleDragOver: dragState.handleDragOver,
|
|
257
262
|
handleDragStart: dragState.handleDragStart,
|
|
263
|
+
handleAgentsExport: importExportState.handleAgentsExport,
|
|
264
|
+
handleAgentsFileDragEnter: importExportState.handleAgentsFileDragEnter,
|
|
265
|
+
handleAgentsFileDragLeave: importExportState.handleAgentsFileDragLeave,
|
|
266
|
+
handleAgentsFileDragOver: importExportState.handleAgentsFileDragOver,
|
|
267
|
+
handleAgentsFileDrop: importExportState.handleAgentsFileDrop,
|
|
268
|
+
handleAgentsImportClick: importExportState.handleAgentsImportClick,
|
|
269
|
+
handleAgentsImportFileChange: importExportState.handleAgentsImportFileChange,
|
|
258
270
|
handleFolderContextMenu: overlayState.handleFolderContextMenu,
|
|
259
271
|
handleRenameFolder: folderState.handleRenameFolder,
|
|
260
272
|
handleRequestAgentVisibilityChange: agentState.handleRequestAgentVisibilityChange,
|
|
@@ -262,6 +274,10 @@ export function useAgentsListState(props: UseAgentsListStateProps) {
|
|
|
262
274
|
handleShowQrCode: overlayState.handleShowQrCode,
|
|
263
275
|
handleSubmitFolderEdit: folderState.handleSubmitFolderEdit,
|
|
264
276
|
headingTitle,
|
|
277
|
+
importFileInputRef: importExportState.importFileInputRef,
|
|
278
|
+
isAgentsExporting: importExportState.isAgentsExporting,
|
|
279
|
+
isAgentsImportDragActive: importExportState.isAgentsImportDragActive,
|
|
280
|
+
isAgentsImporting: importExportState.isAgentsImporting,
|
|
265
281
|
isFolderEditSubmitting: folderState.isFolderEditSubmitting,
|
|
266
282
|
navigateToFolder,
|
|
267
283
|
mazeAgents,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { spaceTrim } from 'spacetrim';
|
|
2
|
-
import { CORE_AGENTS_SERVER } from '../../../../servers';
|
|
3
1
|
import { DEFAULT_THINKING_MESSAGES } from '../../../../src/utils/DEFAULT_THINKING_MESSAGES';
|
|
4
2
|
import { ANALYTICS_METADATA_KEYS, getAnalyticsMetadataDefinition } from '../constants/analyticsMetadata';
|
|
5
3
|
import {
|
|
@@ -263,25 +261,6 @@ export const metadataDefaults: ReadonlyArray<MetadataDefinition> = [
|
|
|
263
261
|
note: 'Comma separated list of allowed IPs or CIDR ranges. If set, only clients from these IPs are allowed to access the server.',
|
|
264
262
|
type: 'IP_RANGE',
|
|
265
263
|
},
|
|
266
|
-
{
|
|
267
|
-
key: 'CORE_SERVER',
|
|
268
|
-
value: CORE_AGENTS_SERVER.url,
|
|
269
|
-
note: spaceTrim(`
|
|
270
|
-
Core Promptbook server URL used for agents that are used for common tasks, these agents are called well known agents:
|
|
271
|
-
|
|
272
|
-
On the core server, the following well known agents should be hosted:
|
|
273
|
-
- \`adam\`: The default ancestor agent for new agents
|
|
274
|
-
- \`teacher\`: Agent that knows book syntax and can help with self-learning
|
|
275
|
-
|
|
276
|
-
`),
|
|
277
|
-
type: 'TEXT',
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
key: 'IS_CORE_SERVER_HIDDEN',
|
|
281
|
-
value: 'false',
|
|
282
|
-
note: 'Hide the core federated server from homepage, navbar, search, and footer links while keeping it available for references when true.',
|
|
283
|
-
type: 'BOOLEAN',
|
|
284
|
-
},
|
|
285
264
|
// <- TODO: [🆎] Allow to set well-known agent names via Metadata
|
|
286
265
|
|
|
287
266
|
{
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { spaceTrim } from 'spacetrim';
|
|
3
|
+
import { AgentCollectionInSupabase } from '../../../../src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase';
|
|
4
|
+
import type { AgentsDatabaseSchema } from '../../../../src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema';
|
|
5
|
+
import { parseAgentSource } from '../../../../src/book-2.0/agent-source/parseAgentSource';
|
|
6
|
+
import type { string_book } from '../../../../src/book-2.0/agent-source/string_book';
|
|
7
|
+
import { DatabaseError } from '../../../../src/errors/DatabaseError';
|
|
8
|
+
import { CORE_AGENT_DIRECTORY_NAME, loadCoreAgentBooks } from '../utils/defaultAgents/loadDefaultAgentBooks';
|
|
9
|
+
import { DEFAULT_AGENT_VISIBILITY } from '../utils/agentVisibility';
|
|
10
|
+
import { $getTableName } from './$getTableName';
|
|
11
|
+
import { $provideSupabaseForServer } from './$provideSupabaseForServer';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Logger surface used by the core-agent seeder.
|
|
15
|
+
*
|
|
16
|
+
* @private utility of `.core` folder seeding
|
|
17
|
+
*/
|
|
18
|
+
type SeedCoreAgentsLogger = Pick<Console, 'error' | 'info' | 'warn'>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for ensuring the bundled `.core` folder and core agents exist.
|
|
22
|
+
*
|
|
23
|
+
* @private utility of `.core` folder seeding
|
|
24
|
+
*/
|
|
25
|
+
export type SeedCoreAgentsOptions = {
|
|
26
|
+
/**
|
|
27
|
+
* Optional explicit directory containing default `*.book` files.
|
|
28
|
+
*/
|
|
29
|
+
readonly defaultAgentDirectory?: string | null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Optional table prefix for the server namespace being seeded.
|
|
33
|
+
*/
|
|
34
|
+
readonly tablePrefix?: string | null;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Optional logger for installer output.
|
|
38
|
+
*/
|
|
39
|
+
readonly logger?: SeedCoreAgentsLogger;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Result of one `.core` agents seed attempt.
|
|
44
|
+
*
|
|
45
|
+
* @private utility of `.core` folder seeding
|
|
46
|
+
*/
|
|
47
|
+
export type SeedCoreAgentsResult = {
|
|
48
|
+
/**
|
|
49
|
+
* Identifier of the `.core` folder, or `null` when no books were available and the folder was not created.
|
|
50
|
+
*/
|
|
51
|
+
readonly coreFolderId: number | null;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Names of agents that were created during this run.
|
|
55
|
+
*/
|
|
56
|
+
readonly createdAgentNames: ReadonlyArray<string>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Ensures the `.core` folder and well-known core agents are present in the current server database.
|
|
61
|
+
*
|
|
62
|
+
* - Creates the `.core` folder when it is missing.
|
|
63
|
+
* - Creates each bundled `.core/*.book` agent when it is missing from the database.
|
|
64
|
+
* - Reuses the same persistence mechanism used by the default agent seeder.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Optional seed controls.
|
|
67
|
+
* @returns Seed summary including the resolved `.core` folder id.
|
|
68
|
+
*
|
|
69
|
+
* @private utility of `.core` folder seeding
|
|
70
|
+
*/
|
|
71
|
+
export async function seedCoreAgents(options: SeedCoreAgentsOptions = {}): Promise<SeedCoreAgentsResult> {
|
|
72
|
+
const logger = options.logger ?? console;
|
|
73
|
+
const tablePrefix = options.tablePrefix ?? process.env.SUPABASE_TABLE_PREFIX ?? '';
|
|
74
|
+
const collection = new AgentCollectionInSupabase(resolveAgentsDatabaseSupabaseClient(), { tablePrefix });
|
|
75
|
+
|
|
76
|
+
const coreAgentBooks = await loadCoreAgentBooks({
|
|
77
|
+
defaultAgentDirectory: options.defaultAgentDirectory,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (coreAgentBooks.length === 0) {
|
|
81
|
+
logger.warn(
|
|
82
|
+
spaceTrim(`
|
|
83
|
+
Skipping \`.core\` agents because no bundled \`.core/*.book\` files were found.
|
|
84
|
+
`),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return { coreFolderId: null, createdAgentNames: [] };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const coreFolderId = await ensureCoreFolderExists();
|
|
91
|
+
const existingAgentNames = await loadExistingActiveAgentNames();
|
|
92
|
+
const createdAgentNames: Array<string> = [];
|
|
93
|
+
|
|
94
|
+
for (const [index, coreAgentBook] of coreAgentBooks.entries()) {
|
|
95
|
+
const agentName = parseCoreAgentName(coreAgentBook);
|
|
96
|
+
|
|
97
|
+
if (existingAgentNames.has(agentName)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const createdAgent = await collection.createAgent(coreAgentBook, {
|
|
102
|
+
folderId: coreFolderId,
|
|
103
|
+
sortOrder: index,
|
|
104
|
+
visibility: DEFAULT_AGENT_VISIBILITY,
|
|
105
|
+
});
|
|
106
|
+
createdAgentNames.push(createdAgent.agentName);
|
|
107
|
+
logger.info(`Created \`.core\` agent: ${createdAgent.agentName}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { coreFolderId, createdAgentNames };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Reads the agent name from one bundled `.core` book source.
|
|
115
|
+
*
|
|
116
|
+
* @param coreAgentBook - Raw `.core` agent book source.
|
|
117
|
+
* @returns Persisted agent name parsed from the book.
|
|
118
|
+
*
|
|
119
|
+
* @private utility of `.core` folder seeding
|
|
120
|
+
*/
|
|
121
|
+
function parseCoreAgentName(coreAgentBook: string_book): string {
|
|
122
|
+
return parseAgentSource(coreAgentBook).agentName;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Reads the set of active agent names already persisted on the current server.
|
|
127
|
+
*
|
|
128
|
+
* @returns Set of active agent names indexed for quick lookups.
|
|
129
|
+
*
|
|
130
|
+
* @private utility of `.core` folder seeding
|
|
131
|
+
*/
|
|
132
|
+
async function loadExistingActiveAgentNames(): Promise<Set<string>> {
|
|
133
|
+
const supabase = $provideSupabaseForServer();
|
|
134
|
+
const agentTableName = await $getTableName('Agent');
|
|
135
|
+
const selectResult = await supabase
|
|
136
|
+
.from(agentTableName)
|
|
137
|
+
.select('agentName')
|
|
138
|
+
.is('deletedAt', null);
|
|
139
|
+
|
|
140
|
+
if (selectResult.error) {
|
|
141
|
+
throw new DatabaseError(
|
|
142
|
+
spaceTrim(
|
|
143
|
+
(block) => `
|
|
144
|
+
Failed to read active agents before seeding \`.core\` agents:
|
|
145
|
+
|
|
146
|
+
${block(selectResult.error.message)}
|
|
147
|
+
`,
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const existingAgentNames = new Set<string>();
|
|
153
|
+
for (const row of (selectResult.data || []) as Array<{ agentName: string }>) {
|
|
154
|
+
existingAgentNames.add(row.agentName);
|
|
155
|
+
}
|
|
156
|
+
return existingAgentNames;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Ensures the `.core` folder exists at the root and returns its identifier.
|
|
161
|
+
*
|
|
162
|
+
* @returns Persisted `.core` folder identifier.
|
|
163
|
+
*
|
|
164
|
+
* @private utility of `.core` folder seeding
|
|
165
|
+
*/
|
|
166
|
+
async function ensureCoreFolderExists(): Promise<number> {
|
|
167
|
+
const supabase = $provideSupabaseForServer();
|
|
168
|
+
const folderTableName = await $getTableName('AgentFolder');
|
|
169
|
+
|
|
170
|
+
const existingFolderResult = await supabase
|
|
171
|
+
.from(folderTableName)
|
|
172
|
+
.select('id')
|
|
173
|
+
.eq('name', CORE_AGENT_DIRECTORY_NAME)
|
|
174
|
+
.is('parentId', null)
|
|
175
|
+
.is('deletedAt', null)
|
|
176
|
+
.maybeSingle();
|
|
177
|
+
|
|
178
|
+
if (existingFolderResult.error) {
|
|
179
|
+
throw new DatabaseError(
|
|
180
|
+
spaceTrim(
|
|
181
|
+
(block) => `
|
|
182
|
+
Failed to read the \`${CORE_AGENT_DIRECTORY_NAME}\` folder before seeding core agents:
|
|
183
|
+
|
|
184
|
+
${block(existingFolderResult.error.message)}
|
|
185
|
+
`,
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (existingFolderResult.data) {
|
|
191
|
+
return (existingFolderResult.data as { id: number }).id;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const insertFolderResult = await supabase
|
|
195
|
+
.from(folderTableName)
|
|
196
|
+
.insert({
|
|
197
|
+
name: CORE_AGENT_DIRECTORY_NAME,
|
|
198
|
+
parentId: null,
|
|
199
|
+
sortOrder: 0,
|
|
200
|
+
icon: null,
|
|
201
|
+
color: null,
|
|
202
|
+
createdAt: new Date().toISOString(),
|
|
203
|
+
updatedAt: null,
|
|
204
|
+
} as never)
|
|
205
|
+
.select('id')
|
|
206
|
+
.maybeSingle();
|
|
207
|
+
|
|
208
|
+
if (insertFolderResult.error || !insertFolderResult.data) {
|
|
209
|
+
throw new DatabaseError(
|
|
210
|
+
spaceTrim(
|
|
211
|
+
(block) => `
|
|
212
|
+
Failed to create the \`${CORE_AGENT_DIRECTORY_NAME}\` folder while seeding core agents:
|
|
213
|
+
|
|
214
|
+
${block(
|
|
215
|
+
insertFolderResult.error?.message ||
|
|
216
|
+
`The database did not return the created \`${CORE_AGENT_DIRECTORY_NAME}\` folder.`,
|
|
217
|
+
)}
|
|
218
|
+
`,
|
|
219
|
+
),
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return (insertFolderResult.data as { id: number }).id;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Resolves the Supabase-shaped client for the Agent collection subset.
|
|
228
|
+
*
|
|
229
|
+
* @returns Supabase client typed for agent collection persistence.
|
|
230
|
+
*
|
|
231
|
+
* @private utility of `.core` folder seeding
|
|
232
|
+
*/
|
|
233
|
+
function resolveAgentsDatabaseSupabaseClient(): SupabaseClient<AgentsDatabaseSchema> {
|
|
234
|
+
return $provideSupabaseForServer() as unknown as SupabaseClient<AgentsDatabaseSchema>;
|
|
235
|
+
}
|
|
@@ -5,6 +5,7 @@ import { $provideSupabaseForServer } from './$provideSupabaseForServer';
|
|
|
5
5
|
import { DEFAULT_AGENT_VISIBILITY } from '../utils/agentVisibility';
|
|
6
6
|
import { loadDefaultAgentBooks } from '../utils/defaultAgents/loadDefaultAgentBooks';
|
|
7
7
|
import { loadAgentsServerEnvFile } from './loadAgentsServerEnvFile';
|
|
8
|
+
import { seedCoreAgents } from './seedCoreAgents';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Environment variable with an explicit default-agent source directory.
|
|
@@ -93,6 +94,36 @@ export async function seedDefaultAgents(options: SeedDefaultAgentsOptions = {}):
|
|
|
93
94
|
const logger = options.logger ?? console;
|
|
94
95
|
const tablePrefix = options.tablePrefix ?? process.env[SUPABASE_TABLE_PREFIX_ENV_NAME] ?? '';
|
|
95
96
|
const collection = new AgentCollectionInSupabase(resolveAgentsDatabaseSupabaseClient(), { tablePrefix });
|
|
97
|
+
const defaultAgentDirectory = options.defaultAgentDirectory ?? process.env[DEFAULT_AGENTS_DIRECTORY_ENV_NAME];
|
|
98
|
+
|
|
99
|
+
const result = await seedDefaultAgentBooks(collection, { defaultAgentDirectory, logger });
|
|
100
|
+
|
|
101
|
+
await seedCoreAgents({
|
|
102
|
+
defaultAgentDirectory,
|
|
103
|
+
tablePrefix,
|
|
104
|
+
logger,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Inserts the bundled top-level default agent books when the server is empty.
|
|
112
|
+
*
|
|
113
|
+
* @param collection - Agent collection bound to the current table prefix.
|
|
114
|
+
* @param options - Seeding context shared with `seedDefaultAgents`.
|
|
115
|
+
* @returns Seed summary for default agents only (core agents are tracked separately).
|
|
116
|
+
*
|
|
117
|
+
* @private utility of standalone default-agent seeding
|
|
118
|
+
*/
|
|
119
|
+
async function seedDefaultAgentBooks(
|
|
120
|
+
collection: AgentCollectionInSupabase,
|
|
121
|
+
options: {
|
|
122
|
+
readonly defaultAgentDirectory: string | undefined;
|
|
123
|
+
readonly logger: SeedDefaultAgentsLogger;
|
|
124
|
+
},
|
|
125
|
+
): Promise<SeedDefaultAgentsResult> {
|
|
126
|
+
const { defaultAgentDirectory, logger } = options;
|
|
96
127
|
const existingAgentCount = await countExistingAgents(collection);
|
|
97
128
|
|
|
98
129
|
if (existingAgentCount > 0) {
|
|
@@ -111,7 +142,7 @@ export async function seedDefaultAgents(options: SeedDefaultAgentsOptions = {}):
|
|
|
111
142
|
}
|
|
112
143
|
|
|
113
144
|
const defaultAgentBooks = await loadDefaultAgentBooks({
|
|
114
|
-
defaultAgentDirectory
|
|
145
|
+
defaultAgentDirectory,
|
|
115
146
|
});
|
|
116
147
|
|
|
117
148
|
if (defaultAgentBooks.length === 0) {
|
|
@@ -30,7 +30,7 @@ export function createFederatedAgentsSearchProvider(): ServerSearchProvider {
|
|
|
30
30
|
|
|
31
31
|
let federatedServers: string[] = [];
|
|
32
32
|
try {
|
|
33
|
-
federatedServers = await getFederatedServers(
|
|
33
|
+
federatedServers = await getFederatedServers();
|
|
34
34
|
} catch (error) {
|
|
35
35
|
console.error('[search] Failed to load federated servers:', error);
|
|
36
36
|
return [];
|
|
@@ -36,7 +36,7 @@ export async function $provideAgentCollectionForServer(): Promise<AgentCollectio
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
const supabase = $provideSupabaseForServer();
|
|
39
|
-
const {
|
|
39
|
+
const { tablePrefix } = await $provideServer();
|
|
40
40
|
const cachedAgentCollection = agentCollectionsByTablePrefix.get(tablePrefix);
|
|
41
41
|
|
|
42
42
|
if (cachedAgentCollection) {
|
|
@@ -50,16 +50,9 @@ export async function $provideAgentCollectionForServer(): Promise<AgentCollectio
|
|
|
50
50
|
|
|
51
51
|
agentCollectionsByTablePrefix.set(tablePrefix, providedCollection);
|
|
52
52
|
|
|
53
|
-
const
|
|
54
|
-
import('../utils/attachAgentPreparationScheduling'),
|
|
55
|
-
import('../utils/defaultFederatedAgents/scheduleDefaultFederatedAgentsSync'),
|
|
56
|
-
]);
|
|
53
|
+
const { attachAgentPreparationScheduling } = await import('../utils/attachAgentPreparationScheduling');
|
|
57
54
|
|
|
58
55
|
attachAgentPreparationScheduling(providedCollection, { tablePrefix });
|
|
59
|
-
scheduleDefaultFederatedAgentsSync({
|
|
60
|
-
tablePrefix,
|
|
61
|
-
localServerUrl: publicUrl.href,
|
|
62
|
-
});
|
|
63
56
|
|
|
64
57
|
return providedCollection;
|
|
65
58
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
import { getMetadata } from '../../database/getMetadata';
|
|
3
|
+
import { appendBooksBackupEntriesToZip, type BooksBackupZipStream } from '../backup/createBooksBackupZipStream';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Metadata key used for the human-readable server name.
|
|
7
|
+
*/
|
|
8
|
+
const SERVER_NAME_METADATA_KEY = 'SERVER_NAME';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Filename suffix used for agents-only exports.
|
|
12
|
+
*/
|
|
13
|
+
const AGENTS_EXPORT_FILENAME_SUFFIX = '.agents.zip';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Fallback server filename stem when metadata does not provide a usable name.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_AGENTS_EXPORT_FILENAME_STEM = 'promptbook-agents-server';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pattern matching non-alphanumeric filename slug separators.
|
|
22
|
+
*/
|
|
23
|
+
const FILENAME_SLUG_SEPARATOR_PATTERN = /[^a-z0-9]+/g;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Pattern matching leading or trailing filename slug separators.
|
|
27
|
+
*/
|
|
28
|
+
const FILENAME_SLUG_EDGE_SEPARATOR_PATTERN = /^-+|-+$/g;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Builds a ZIP stream containing only agent books organized by folder structure.
|
|
32
|
+
*
|
|
33
|
+
* @returns Download filename and stream payload.
|
|
34
|
+
*/
|
|
35
|
+
export async function createAgentsExportZipStream(): Promise<BooksBackupZipStream> {
|
|
36
|
+
const serverName = await getMetadata(SERVER_NAME_METADATA_KEY);
|
|
37
|
+
const zip = new JSZip();
|
|
38
|
+
|
|
39
|
+
await appendBooksBackupEntriesToZip(zip, '');
|
|
40
|
+
|
|
41
|
+
const stream = zip.generateNodeStream({
|
|
42
|
+
streamFiles: true,
|
|
43
|
+
compression: 'DEFLATE',
|
|
44
|
+
compressionOptions: { level: 6 },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
filename: `${createAgentsExportFilenameStem(serverName)}${AGENTS_EXPORT_FILENAME_SUFFIX}`,
|
|
49
|
+
stream,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a safe lowercase filename stem from server metadata.
|
|
55
|
+
*
|
|
56
|
+
* @param serverName - Raw server name from metadata.
|
|
57
|
+
* @returns Filename stem for the agents export.
|
|
58
|
+
*/
|
|
59
|
+
export function createAgentsExportFilenameStem(serverName: string | null | undefined): string {
|
|
60
|
+
const normalizedServerName = typeof serverName === 'string' ? serverName.trim().toLowerCase() : '';
|
|
61
|
+
const filenameStem = normalizedServerName
|
|
62
|
+
.normalize('NFKD')
|
|
63
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
64
|
+
.replace(FILENAME_SLUG_SEPARATOR_PATTERN, '-')
|
|
65
|
+
.replace(FILENAME_SLUG_EDGE_SEPARATOR_PATTERN, '');
|
|
66
|
+
|
|
67
|
+
return filenameStem || DEFAULT_AGENTS_EXPORT_FILENAME_STEM;
|
|
68
|
+
}
|