fix(createblogpost): convert to proper AI SDK tool
- Wrap function with tool() from 'ai' package - Add jsonSchema() for input validation - Rename export from createBlogPost to createBlogPostTool - Update package.json with proper tpmjs.tools format - Bump version to 0.3.0 Fixes executor error: 'Cannot destructure property title of t'
This commit is contained in:
parent
196cbacf62
commit
db482855d3
3 changed files with 165 additions and 124 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tpmjs/createblogpost",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"description": "A tool for creating structured blog posts with AI-generated content",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs-tool", "blog", "content", "ai", "writing"],
|
||||
|
|
@ -34,63 +34,66 @@
|
|||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
|
||||
"parameters": [
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"description": "The title of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "author",
|
||||
"type": "string",
|
||||
"description": "The author of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "content",
|
||||
"type": "string",
|
||||
"description": "The main content of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"type": "string[]",
|
||||
"description": "Array of tags for categorization",
|
||||
"required": false,
|
||||
"default": []
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "'markdown' | 'mdx'",
|
||||
"description": "Output format for the blog post",
|
||||
"required": false,
|
||||
"default": "markdown"
|
||||
},
|
||||
{
|
||||
"name": "excerpt",
|
||||
"type": "string",
|
||||
"description": "Short excerpt or summary of the post",
|
||||
"required": false
|
||||
"exportName": "createBlogPostTool",
|
||||
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"description": "The title of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "author",
|
||||
"type": "string",
|
||||
"description": "The author of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "content",
|
||||
"type": "string",
|
||||
"description": "The main content of the blog post",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"type": "string[]",
|
||||
"description": "Array of tags for categorization",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "'markdown' | 'mdx'",
|
||||
"description": "Output format for the blog post",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "excerpt",
|
||||
"type": "string",
|
||||
"description": "Short excerpt or summary of the post",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "BlogPost",
|
||||
"description": "A structured blog post object with frontmatter, content, and metadata including slug, wordCount, readingTime, and formattedOutput"
|
||||
},
|
||||
"aiAgent": {
|
||||
"useCase": "Use this tool when users need to generate blog posts, articles, or structured content with proper frontmatter and metadata. Ideal for content management systems, static site generators, and documentation sites.",
|
||||
"limitations": "Does not include AI content generation - you must provide the content. Only formats and structures existing content.",
|
||||
"examples": [
|
||||
"Create a blog post about TypeScript best practices",
|
||||
"Generate a tutorial post with code examples",
|
||||
"Format an article with SEO metadata"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "BlogPost",
|
||||
"description": "A structured blog post object with frontmatter, content, and metadata including slug, wordCount, readingTime, and formattedOutput"
|
||||
},
|
||||
"frameworks": ["vercel-ai", "langchain"],
|
||||
"aiAgent": {
|
||||
"useCase": "Use this tool when users need to generate blog posts, articles, or structured content with proper frontmatter and metadata. Ideal for content management systems, static site generators, and documentation sites.",
|
||||
"limitations": "Does not include AI content generation - you must provide the content. Only formats and structures existing content.",
|
||||
"examples": [
|
||||
"Create a blog post about TypeScript best practices",
|
||||
"Generate a tutorial post with code examples",
|
||||
"Format an article with SEO metadata"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^4.1.13"
|
||||
"ai": "6.0.0-beta.124"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
/**
|
||||
* Blog Post Creation Tool for TPMJS
|
||||
* Creates structured blog posts with frontmatter and metadata
|
||||
*
|
||||
* This is a proper AI SDK v6 tool that can be used with streamText()
|
||||
* Uses jsonSchema() to avoid Zod 4 JSON Schema conversion issues with OpenAI
|
||||
*/
|
||||
|
||||
export interface BlogPostOptions {
|
||||
title: string;
|
||||
author: string;
|
||||
content: string;
|
||||
tags?: string[];
|
||||
format?: 'markdown' | 'mdx';
|
||||
excerpt?: string;
|
||||
publishDate?: Date;
|
||||
}
|
||||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface BlogPost {
|
||||
frontmatter: {
|
||||
|
|
@ -28,6 +23,18 @@ export interface BlogPost {
|
|||
formattedOutput: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type for Create Blog Post Tool
|
||||
*/
|
||||
type CreateBlogPostInput = {
|
||||
title: string;
|
||||
author: string;
|
||||
content: string;
|
||||
tags?: string[];
|
||||
format?: 'markdown' | 'mdx';
|
||||
excerpt?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a slug from a title
|
||||
*/
|
||||
|
|
@ -84,64 +91,95 @@ function formatFrontmatter(
|
|||
}
|
||||
|
||||
/**
|
||||
* Create Blog Post Tool
|
||||
* Creates a structured blog post with frontmatter and metadata
|
||||
*
|
||||
* This is a proper AI SDK v6 tool that can be used with streamText()
|
||||
*/
|
||||
export async function createBlogPost(options: BlogPostOptions): Promise<BlogPost> {
|
||||
const {
|
||||
title,
|
||||
author,
|
||||
content,
|
||||
tags = [],
|
||||
format = 'markdown',
|
||||
excerpt,
|
||||
publishDate = new Date(),
|
||||
} = options;
|
||||
export const createBlogPostTool = tool({
|
||||
description:
|
||||
'Creates a structured blog post with frontmatter, metadata, slug, word count, and reading time. Outputs in Markdown or MDX format.',
|
||||
inputSchema: jsonSchema<CreateBlogPostInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'The title of the blog post',
|
||||
},
|
||||
author: {
|
||||
type: 'string',
|
||||
description: 'The author of the blog post',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
description: 'The main content of the blog post',
|
||||
},
|
||||
tags: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
description: 'Array of tags for categorization',
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
enum: ['markdown', 'mdx'],
|
||||
description: 'Output format for the blog post (default: markdown)',
|
||||
},
|
||||
excerpt: {
|
||||
type: 'string',
|
||||
description: 'Short excerpt or summary of the post',
|
||||
},
|
||||
},
|
||||
required: ['title', 'author', 'content'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ title, author, content, tags = [], format = 'markdown', excerpt }) {
|
||||
// Validate required fields
|
||||
if (!title || title.trim().length === 0) {
|
||||
throw new Error('Title is required');
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if (!title || title.trim().length === 0) {
|
||||
throw new Error('Title is required');
|
||||
}
|
||||
if (!author || author.trim().length === 0) {
|
||||
throw new Error('Author is required');
|
||||
}
|
||||
|
||||
if (!author || author.trim().length === 0) {
|
||||
throw new Error('Author is required');
|
||||
}
|
||||
if (!content || content.trim().length === 0) {
|
||||
throw new Error('Content is required');
|
||||
}
|
||||
|
||||
if (!content || content.trim().length === 0) {
|
||||
throw new Error('Content is required');
|
||||
}
|
||||
// Calculate metadata
|
||||
const slug = createSlug(title);
|
||||
const wordCount = countWords(content);
|
||||
const readingTime = calculateReadingTime(wordCount);
|
||||
const publishDate = new Date();
|
||||
|
||||
// Calculate metadata
|
||||
const slug = createSlug(title);
|
||||
const wordCount = countWords(content);
|
||||
const readingTime = calculateReadingTime(wordCount);
|
||||
// Build frontmatter
|
||||
const frontmatter: BlogPost['frontmatter'] = {
|
||||
title,
|
||||
author,
|
||||
date: publishDate.toISOString().split('T')[0] || '',
|
||||
tags,
|
||||
slug,
|
||||
wordCount,
|
||||
readingTime,
|
||||
};
|
||||
|
||||
// Build frontmatter
|
||||
const frontmatter: BlogPost['frontmatter'] = {
|
||||
title,
|
||||
author,
|
||||
date: publishDate.toISOString().split('T')[0] || '',
|
||||
tags,
|
||||
slug,
|
||||
wordCount,
|
||||
readingTime,
|
||||
};
|
||||
if (excerpt) {
|
||||
frontmatter.excerpt = excerpt;
|
||||
}
|
||||
|
||||
if (excerpt) {
|
||||
frontmatter.excerpt = excerpt;
|
||||
}
|
||||
// Format the complete blog post
|
||||
const formattedFrontmatter = formatFrontmatter(frontmatter, format);
|
||||
const formattedOutput = `${formattedFrontmatter}\n\n${content}`;
|
||||
|
||||
// Format the complete blog post
|
||||
const formattedFrontmatter = formatFrontmatter(frontmatter, format);
|
||||
const formattedOutput = `${formattedFrontmatter}\n\n${content}`;
|
||||
|
||||
return {
|
||||
frontmatter,
|
||||
content,
|
||||
formattedOutput,
|
||||
};
|
||||
}
|
||||
return {
|
||||
frontmatter,
|
||||
content,
|
||||
formattedOutput,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Export default for convenience
|
||||
*/
|
||||
export default createBlogPost;
|
||||
export default createBlogPostTool;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue