Community cards and prebuilt cards (#258)

* Add community sharing feature and merge with pre-built templates

* Add warning before publishing

* [Untested] Add delete flow for community cards

* Fix bug with sorting by likes count and update design of cards

* Fix community assistant parsing errors

* Remove all as a type filter

* Remove default assistant name for publishing to community

* Update DB calls to be standardized paginated
This commit is contained in:
Akhilesh Sudhakar 2025-09-15 19:53:35 +04:00 committed by GitHub
parent 62c1230cff
commit be4e17b5a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 2144 additions and 264 deletions

View file

@ -0,0 +1,52 @@
import { db } from "@/app/lib/mongodb";
import { prebuiltTemplates } from "@/app/lib/prebuilt-cards";
// idempotent seed: creates library (prebuilt) templates in DB if missing
// Uses name+authorName match to avoid duplicates; tags include a stable prebuilt key
export async function ensureLibraryTemplatesSeeded(): Promise<void> {
try {
const collection = db.collection("assistant_templates");
const now = new Date().toISOString();
const entries = Object.entries(prebuiltTemplates);
for (const [prebuiltKey, tpl] of entries) {
// minimal guard; only ingest valid workflow-like objects
if (!(tpl as any)?.agents || !Array.isArray((tpl as any).agents)) continue;
const name = (tpl as any).name || prebuiltKey;
// check if already present (by name + authorName Rowboat and special tag)
const existing = await collection.findOne({ name, authorName: "Rowboat", tags: { $in: [ `prebuilt:${prebuiltKey}`, "__library__" ] } });
if (existing) continue;
const doc = {
name,
description: (tpl as any).description || "",
category: (tpl as any).category || "Other",
authorId: "rowboat-system",
authorName: "Rowboat",
authorEmail: undefined,
isAnonymous: false,
workflow: tpl as any,
tags: ["__library__", `prebuilt:${prebuiltKey}`].filter(Boolean),
publishedAt: now,
lastUpdatedAt: now,
downloadCount: 0,
likeCount: 0,
featured: false,
isPublic: true,
likes: [] as string[],
copilotPrompt: (tpl as any).copilotPrompt || undefined,
thumbnailUrl: undefined,
source: 'library' as const,
} as const;
await collection.insertOne(doc as any);
}
} catch (err) {
// best-effort seed; do not throw to avoid breaking requests
console.error("ensureLibraryTemplatesSeeded error:", err);
}
}

View file

@ -1,50 +1,33 @@
import { WorkflowTemplate } from "./types/workflow_types";
import { z } from 'zod';
import { prebuiltTemplates } from './prebuilt-cards';
const DEFAULT_MODEL = process.env.PROVIDER_DEFAULT_MODEL || "gpt-4.1";
// Build templates object using static imports so Vercel bundles them
function buildTemplates(): { [key: string]: z.infer<typeof WorkflowTemplate> } {
const templates: { [key: string]: z.infer<typeof WorkflowTemplate> } = {};
// Add default template
templates['default'] = {
name: 'Blank Template',
description: 'A blank canvas to build your agents.',
startAgent: "",
agents: [],
prompts: [],
tools: [
{
name: "Generate Image",
description: "Generate an image using Google Gemini given a text prompt. Returns base64-encoded image data and any text parts.",
isGeminiImage: true,
parameters: {
type: 'object',
properties: {
prompt: { type: 'string', description: 'Text prompt describing the image to generate' },
modelName: { type: 'string', description: 'Optional Gemini model override' },
},
required: ['prompt'],
additionalProperties: true,
// Provide a minimal default template to satisfy legacy code paths that
// still reference `templates.default`. Real templates are DB-backed.
const defaultTemplate: z.infer<typeof WorkflowTemplate> = {
name: 'Blank Template',
description: 'A blank canvas to build your assistant.',
startAgent: "",
agents: [],
prompts: [],
tools: [
{
name: "Generate Image",
description: "Generate an image using Google Gemini given a text prompt. Returns base64-encoded image data and any text parts.",
isGeminiImage: true,
parameters: {
type: 'object',
properties: {
prompt: { type: 'string', description: 'Text prompt describing the image to generate' },
modelName: { type: 'string', description: 'Optional Gemini model override' },
},
required: ['prompt'],
additionalProperties: true,
},
],
};
},
],
pipelines: [],
};
// Merge static prebuilt templates
Object.entries(prebuiltTemplates).forEach(([key, tpl]) => {
// Basic guard to avoid bad entries
if ((tpl as any)?.agents && Array.isArray((tpl as any).agents)) {
templates[key] = tpl as z.infer<typeof WorkflowTemplate>;
}
});
return templates;
}
export const templates: { [key: string]: z.infer<typeof WorkflowTemplate> } = buildTemplates();
// Note: Prebuilt cards are now loaded from app/lib/prebuilt-cards/ directory
// starting_copilot_prompts has been removed as it was unused
export const templates: Record<string, z.infer<typeof WorkflowTemplate>> = {
default: defaultTemplate,
};