Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions kits/content-generation/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
AGENTIC_GENERATE_CONTENT="AGENTIC_GENERATE_CONTENT Flow ID"
LAMATIC_API_URL="LAMATIC_API_URL"
LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
LAMATIC_API_KEY="LAMATIC_API_KEY"
27 changes: 27 additions & 0 deletions kits/content-generation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules

# next.js
/.next/
/out/

# production
/build

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files
.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
106 changes: 106 additions & 0 deletions kits/content-generation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Agent Kit Generation by Lamatic.ai

<p align="center">
<a href="https://agent-kit-generation.vercel.app" target="_blank">
<img src="https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge" alt="Live Demo" />
</a>
</p>


**Agent Kit Generation** is an AI-powered content generation system built with [Lamatic.ai](https://lamatic.ai). It uses intelligent workflows to generate text, images, and JSON content through a modern Next.js interface with markdown rendering support.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits/agentic/generation&env=AGENTIC_GENERATE_CONTENT,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY&envDescription=Your%20Lamatic%20Generation%20keys%20are%20required.&envLink=https://lamatic.ai/templates/agentkits/agentic/agent-kit-generation)

---

## Lamatic Setup (Pre and Post)

Before running this project, you must build and deploy the flow in Lamatic, then wire its config into this codebase.

Pre: Build in Lamatic
1. Sign in or sign up at https://lamatic.ai
2. Create a project (if you don’t have one yet)
3. Click “+ New Flow” and select "Templates"
4. Select the 'Generation' agent kit
5. Configure providers/tools/inputs as prompted
6. Deploy the kit in Lamatic and obtain your .env keys
7. Copy the keys from your studio

Post: Wire into this repo
1. Create a .env file and set the keys
2. Install and run locally:
- npm install
- npm run dev
3. Deploy (Vercel recommended):
- Import your repo, set the project's Root Directory (if applicable)
- Add env vars in Vercel (same as your .env)
- Deploy and test your live URL

Notes
- Coming soon: single-click export and "Connect Git" in Lamatic to push config directly to your repo.

---

## 🔑 Setup
## Required Keys and Config

You’ll need these things to run this project locally:

1. **.env Keys** → get it from your [Lamatic account](https://lamatic.ai) post kit deployment.


| Item | Purpose | Where to Get It |
| ----------------- | -------------------------------------------- | ----------------------------------------------- |
| .env Key | Authentication for Lamatic AI APIs and Orchestration | [lamatic.ai](https://lamatic.ai) |

### 1. Environment Variables

Create `.env.local` with:

```bash
# Lamatic
AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID"
LAMATIC_API_URL = "LAMATIC_API_URL"
LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID"
LAMATIC_API_KEY = "LAMATIC_API_KEY"
```

### 2. Install & Run

```bash
npm install
npm run dev
# Open http://localhost:3000
```
---

## 📂 Repo Structure

```
/actions
└── orchestrate.ts # Lamatic workflow orchestration
/app
└── page.tsx # Main generation form UI
/components
├── header.tsx # Header component with navigation
└── ui # shadcn/ui components
/lib
└── lamatic-client.ts # Lamatic SDK client
/public
└── lamatic-logo.png # Lamatic branding
/flows
└── ... # Lamatic Flows
/package.json # Dependencies & scripts
```

---

## 🤝 Contributing

We welcome contributions! Open an issue or PR in this repo.

---

## 📜 License

MIT License – see [LICENSE](../../../LICENSE).
84 changes: 84 additions & 0 deletions kits/content-generation/actions/orchestrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"use server"

import { lamaticClient } from "@/lib/lamatic-client"
import {config} from "../orchestrate.js"

type InputType = "text" | "image" | "json"

export async function generateContent(
inputType: InputType,
instructions: string,
): Promise<{
success: boolean
data?: any
error?: string
}> {
try {
console.log("[v0] Generating content with:", { inputType, instructions })

// Get the first workflow from the config
const flows = config.flows
const firstFlowKey = Object.keys(flows)[0]

if (!firstFlowKey) {
throw new Error("No workflows found in configuration")
}

// Fix: Add index signature to make TypeScript happy about accessing flows[firstFlowKey]
const flow = flows[firstFlowKey as keyof typeof flows] as (typeof flows)[keyof typeof flows];
console.log("[v0] Using workflow:", flow.name, flow.workflowId);

// Prepare inputs based on the flow's input schema
const inputs: Record<string, any> = {
mode: inputType,
instructions,
}

// Map to schema if needed
for (const inputKey of Object.keys(flow.inputSchema || {})) {
if (inputKey === "inputType" || inputKey === "type") {
inputs[inputKey] = inputType
} else if (inputKey === "instructions" || inputKey === "query") {
inputs[inputKey] = instructions
}
}

console.log("[v0] Sending inputs:", inputs)

if(!flow.workflowId){
throw Error("Workflow not found in config.")
}
const resData = await lamaticClient.executeFlow(flow.workflowId, inputs)
console.log("[v0] Raw response:", resData)

// Parse the answer from resData?.output.answer
const answer = resData?.result?.answer

if (!answer) {
throw new Error("No answer found in response")
}

return {
success: true,
data: answer,
}
} catch (error) {
console.error("[v0] Generation error:", error)

let errorMessage = "Unknown error occurred"
if (error instanceof Error) {
errorMessage = error.message
if (error.message.includes("fetch failed")) {
errorMessage =
"Network error: Unable to connect to the service. Please check your internet connection and try again."
} else if (error.message.includes("API key")) {
errorMessage = "Authentication error: Please check your API configuration."
}
}

return {
success: false,
error: errorMessage,
}
}
}
125 changes: 125 additions & 0 deletions kits/content-generation/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
@import 'tailwindcss';
@import 'tw-animate-css';

@custom-variant dark (&:is(.dark *));

:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}

.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.439 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.269 0 0);
--sidebar-ring: oklch(0.439 0 0);
}

@theme inline {
--font-sans: 'Geist', 'Geist Fallback';
--font-mono: 'Geist Mono', 'Geist Mono Fallback';
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}

@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
45 changes: 45 additions & 0 deletions kits/content-generation/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Metadata } from 'next'
import { Geist, Geist_Mono } from 'next/font/google'
import { Analytics } from '@vercel/analytics/next'
import './globals.css'

const _geist = Geist({ subsets: ["latin"] });
const _geistMono = Geist_Mono({ subsets: ["latin"] });

export const metadata: Metadata = {
title: 'v0 App',
description: 'Created with v0',
generator: 'v0.app',
icons: {
icon: [
{
url: '/icon-light-32x32.png',
media: '(prefers-color-scheme: light)',
},
{
url: '/icon-dark-32x32.png',
media: '(prefers-color-scheme: dark)',
},
{
url: '/icon.svg',
type: 'image/svg+xml',
},
],
apple: '/apple-icon.png',
},
}

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body className={`font-sans antialiased`}>
{children}
<Analytics />
</body>
</html>
)
}
Loading