@webhouse/cms-ai 0.1.1
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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.cjs +770 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +272 -0
- package/dist/index.d.ts +272 -0
- package/dist/index.js +731 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/anthropic.ts","../src/providers/openai.ts","../src/providers/registry.ts","../src/agents/content.ts","../src/agents/seo.ts","../src/index.ts","../src/orchestrator/engine.ts","../src/orchestrator/queue.ts","../src/orchestrator/runner.ts","../src/orchestrator/scheduler.ts","../src/budget/tracker.ts","../src/agents/defaults.ts"],"sourcesContent":["import Anthropic from '@anthropic-ai/sdk';\nimport type { AiProvider, TextGenerationOptions, TextGenerationResult } from './types.js';\n\n// Pricing per 1M tokens (USD) — as of early 2026\nconst PRICING: Record<string, { input: number; output: number }> = {\n 'claude-sonnet-4-6': { input: 3.0, output: 15.0 },\n 'claude-haiku-4-5': { input: 0.8, output: 4.0 },\n 'claude-opus-4-6': { input: 15.0, output: 75.0 },\n};\n\nexport class AnthropicProvider implements AiProvider {\n name = 'anthropic';\n defaultModel = 'claude-sonnet-4-6';\n private client: Anthropic;\n\n constructor(apiKey?: string) {\n this.client = new Anthropic({ apiKey: apiKey ?? process.env['ANTHROPIC_API_KEY'] });\n }\n\n estimateCost(inputTokens: number, outputTokens: number, model?: string): number {\n const m = model ?? this.defaultModel;\n const pricing = PRICING[m] ?? PRICING['claude-sonnet-4-6']!;\n return (inputTokens / 1_000_000) * pricing.input + (outputTokens / 1_000_000) * pricing.output;\n }\n\n async generate(prompt: string, options: TextGenerationOptions = {}): Promise<TextGenerationResult> {\n const model = options.model ?? this.defaultModel;\n const response = await this.client.messages.create({\n model,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.7,\n system: options.systemPrompt ?? 'You are a helpful content writer.',\n messages: [{ role: 'user', content: prompt }],\n });\n\n const text = response.content\n .filter(b => b.type === 'text')\n .map(b => (b as { type: 'text'; text: string }).text)\n .join('');\n\n const inputTokens = response.usage.input_tokens;\n const outputTokens = response.usage.output_tokens;\n\n return {\n text,\n inputTokens,\n outputTokens,\n model,\n provider: 'anthropic',\n estimatedCostUsd: this.estimateCost(inputTokens, outputTokens, model),\n };\n }\n}\n","import OpenAI from 'openai';\nimport type { AiProvider, TextGenerationOptions, TextGenerationResult } from './types.js';\n\nconst PRICING: Record<string, { input: number; output: number }> = {\n 'gpt-4o': { input: 2.5, output: 10.0 },\n 'gpt-4o-mini': { input: 0.15, output: 0.6 },\n};\n\nexport class OpenAiProvider implements AiProvider {\n name = 'openai';\n defaultModel = 'gpt-4o';\n private client: OpenAI;\n\n constructor(apiKey?: string) {\n this.client = new OpenAI({ apiKey: apiKey ?? process.env['OPENAI_API_KEY'] });\n }\n\n estimateCost(inputTokens: number, outputTokens: number, model?: string): number {\n const m = model ?? this.defaultModel;\n const pricing = PRICING[m] ?? PRICING['gpt-4o']!;\n return (inputTokens / 1_000_000) * pricing.input + (outputTokens / 1_000_000) * pricing.output;\n }\n\n async generate(prompt: string, options: TextGenerationOptions = {}): Promise<TextGenerationResult> {\n const model = options.model ?? this.defaultModel;\n const response = await this.client.chat.completions.create({\n model,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.7,\n messages: [\n ...(options.systemPrompt ? [{ role: 'system' as const, content: options.systemPrompt }] : []),\n { role: 'user' as const, content: prompt },\n ],\n });\n\n const text = response.choices[0]?.message.content ?? '';\n const inputTokens = response.usage?.prompt_tokens ?? 0;\n const outputTokens = response.usage?.completion_tokens ?? 0;\n\n return {\n text,\n inputTokens,\n outputTokens,\n model,\n provider: 'openai',\n estimatedCostUsd: this.estimateCost(inputTokens, outputTokens, model),\n };\n }\n}\n","import type { AiProvider } from './types.js';\nimport { AnthropicProvider } from './anthropic.js';\nimport { OpenAiProvider } from './openai.js';\n\nexport interface ProviderConfig {\n anthropic?: { apiKey?: string; defaultModel?: string };\n openai?: { apiKey?: string; defaultModel?: string };\n defaultProvider?: 'anthropic' | 'openai';\n}\n\nexport class ProviderRegistry {\n private providers = new Map<string, AiProvider>();\n private defaultProviderName: string;\n\n constructor(config: ProviderConfig = {}) {\n if (config.anthropic !== undefined || process.env['ANTHROPIC_API_KEY']) {\n this.providers.set('anthropic', new AnthropicProvider(config.anthropic?.apiKey));\n }\n if (config.openai !== undefined || process.env['OPENAI_API_KEY']) {\n this.providers.set('openai', new OpenAiProvider(config.openai?.apiKey));\n }\n this.defaultProviderName =\n config.defaultProvider ??\n (this.providers.has('anthropic') ? 'anthropic' : 'openai');\n }\n\n get(name?: string): AiProvider {\n const providerName = name ?? this.defaultProviderName;\n const provider = this.providers.get(providerName);\n if (!provider) {\n throw new Error(\n `AI provider \"${providerName}\" not configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable.`,\n );\n }\n return provider;\n }\n\n list(): string[] {\n return [...this.providers.keys()];\n }\n}\n","import type { AiProvider, TextGenerationOptions } from '../providers/types.js';\nimport type { CollectionConfig } from '@webhouse/cms';\n\nexport interface GenerateOptions extends TextGenerationOptions {\n collection: CollectionConfig;\n locale?: string;\n tone?: string;\n targetAudience?: string;\n}\n\nexport interface GenerateResult {\n fields: Record<string, string>;\n slug: string;\n usage: { inputTokens: number; outputTokens: number; estimatedCostUsd: number };\n}\n\nexport interface RewriteOptions extends TextGenerationOptions {\n instruction: string;\n collection: CollectionConfig;\n}\n\nexport class ContentAgent {\n constructor(private provider: AiProvider) {}\n\n async generate(prompt: string, options: GenerateOptions): Promise<GenerateResult> {\n const { collection, locale = 'en', tone, targetAudience } = options;\n\n const fieldDescriptions = collection.fields\n .map(f => {\n const hint = f.ai?.hint ? ` (${f.ai.hint})` : '';\n const maxLen = f.ai?.maxLength ?? f.maxLength;\n const lenHint = maxLen ? ` (max ${maxLen} characters)` : '';\n return `- \"${f.name}\" (${f.type})${hint}${lenHint}${f.required === true ? ' [required]' : ''}`;\n })\n .join('\\n');\n\n const systemPrompt = [\n `You are a professional content writer creating content for a CMS.`,\n `Collection: ${collection.label ?? collection.name}`,\n tone ? `Tone: ${tone}` : null,\n targetAudience ? `Target audience: ${targetAudience}` : null,\n locale !== 'en' ? `Language: ${locale}` : null,\n ]\n .filter(Boolean)\n .join('\\n');\n\n const userPrompt = `Create content for the following request: \"${prompt}\"\n\nReturn a JSON object with these fields:\n${fieldDescriptions}\n\nFor \"richtext\" fields, use Markdown formatting.\nFor \"date\" fields, use ISO 8601 format (e.g. \"${new Date().toISOString()}\").\nFor \"slug\", generate a URL-friendly slug from the title (lowercase, hyphens).\n\nReturn ONLY valid JSON, no explanation, no markdown code blocks.`;\n\n const result = await this.provider.generate(userPrompt, { ...options, systemPrompt });\n\n let fields: Record<string, string>;\n try {\n const cleaned = result.text\n .replace(/^```(?:json)?\\n?/m, '')\n .replace(/\\n?```$/m, '')\n .trim();\n fields = JSON.parse(cleaned) as Record<string, string>;\n } catch {\n throw new Error(`AI returned invalid JSON: ${result.text.slice(0, 200)}`);\n }\n\n const slug = String(fields['slug'] ?? fields['title'] ?? 'untitled')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n return {\n fields,\n slug,\n usage: {\n inputTokens: result.inputTokens,\n outputTokens: result.outputTokens,\n estimatedCostUsd: result.estimatedCostUsd,\n },\n };\n }\n\n async rewrite(\n currentData: Record<string, unknown>,\n options: RewriteOptions,\n ): Promise<GenerateResult> {\n const { instruction } = options;\n\n const systemPrompt = `You are a professional content editor. Rewrite the provided content according to the instruction.`;\n\n const userPrompt = `Current content:\n${JSON.stringify(currentData, null, 2)}\n\nInstruction: \"${instruction}\"\n\nReturn a JSON object with the same field names but updated content. Only update fields that are relevant to the instruction. Return ONLY valid JSON.`;\n\n const result = await this.provider.generate(userPrompt, { ...options, systemPrompt });\n\n let fields: Record<string, string>;\n try {\n const cleaned = result.text\n .replace(/^```(?:json)?\\n?/m, '')\n .replace(/\\n?```$/m, '')\n .trim();\n fields = JSON.parse(cleaned) as Record<string, string>;\n } catch {\n throw new Error(`AI returned invalid JSON: ${result.text.slice(0, 200)}`);\n }\n\n const slug = String(fields['slug'] ?? currentData['slug'] ?? 'untitled')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n return {\n fields,\n slug,\n usage: {\n inputTokens: result.inputTokens,\n outputTokens: result.outputTokens,\n estimatedCostUsd: result.estimatedCostUsd,\n },\n };\n }\n\n async translate(\n currentData: Record<string, unknown>,\n targetLocale: string,\n options: Partial<TextGenerationOptions> & { collection: CollectionConfig },\n ): Promise<GenerateResult> {\n return this.rewrite(currentData, {\n instruction: `Translate all text content to ${targetLocale}. Keep field names in English. Keep dates, numbers, and URLs unchanged.`,\n ...options,\n });\n }\n}\n","import type { AiProvider } from '../providers/types.js';\nimport type { Document } from '@webhouse/cms';\n\nexport interface SeoResult {\n metaTitle: string;\n metaDescription: string;\n jsonLd: Record<string, unknown>;\n usage: { inputTokens: number; outputTokens: number; estimatedCostUsd: number };\n}\n\nexport class SeoAgent {\n constructor(private provider: AiProvider) {}\n\n async optimize(doc: Document, siteTitle: string, baseUrl: string): Promise<SeoResult> {\n const title = String(doc.data['title'] ?? doc.slug);\n const content = String(doc.data['content'] ?? doc.data['body'] ?? '').slice(0, 2000);\n const excerpt = String(doc.data['excerpt'] ?? '');\n\n const systemPrompt = `You are an SEO expert. Generate optimized meta tags and structured data.`;\n\n const userPrompt = `Document:\nTitle: ${title}\nExcerpt: ${excerpt}\nContent preview: ${content}\nSite: ${siteTitle}\nURL: ${baseUrl}/${doc.collection}/${doc.slug}/\n\nGenerate:\n1. metaTitle: SEO-optimized title (50-60 chars)\n2. metaDescription: Compelling description (150-160 chars)\n3. jsonLd: JSON-LD structured data object (Article schema)\n\nReturn ONLY valid JSON like:\n{\n \"metaTitle\": \"...\",\n \"metaDescription\": \"...\",\n \"jsonLd\": { \"@context\": \"https://schema.org\", \"@type\": \"Article\", ... }\n}`;\n\n const result = await this.provider.generate(userPrompt, {\n systemPrompt,\n maxTokens: 1024,\n temperature: 0.3,\n });\n\n let parsed: { metaTitle: string; metaDescription: string; jsonLd: Record<string, unknown> };\n try {\n const cleaned = result.text\n .replace(/^```(?:json)?\\n?/m, '')\n .replace(/\\n?```$/m, '')\n .trim();\n parsed = JSON.parse(cleaned) as typeof parsed;\n } catch {\n // Fallback\n parsed = {\n metaTitle: title.slice(0, 60),\n metaDescription: (excerpt || content).slice(0, 160),\n jsonLd: {\n '@context': 'https://schema.org',\n '@type': 'Article',\n headline: title,\n description: excerpt || content.slice(0, 160),\n },\n };\n }\n\n return {\n ...parsed,\n usage: {\n inputTokens: result.inputTokens,\n outputTokens: result.outputTokens,\n estimatedCostUsd: result.estimatedCostUsd,\n },\n };\n }\n}\n","export { AnthropicProvider } from './providers/anthropic.js';\nexport { OpenAiProvider } from './providers/openai.js';\nexport { ProviderRegistry } from './providers/registry.js';\nexport type { AiProvider, TextGenerationOptions, TextGenerationResult } from './providers/types.js';\nexport type { ProviderConfig } from './providers/registry.js';\n\nexport { ContentAgent } from './agents/content.js';\nexport type { GenerateOptions, GenerateResult, RewriteOptions } from './agents/content.js';\n\nexport { SeoAgent } from './agents/seo.js';\nexport type { SeoResult } from './agents/seo.js';\n\n// Orchestrator\nexport { OrchestratorEngine } from './orchestrator/engine.js';\nexport { CurationQueue } from './orchestrator/queue.js';\nexport { AgentRunner } from './orchestrator/runner.js';\nexport { AgentScheduler } from './orchestrator/scheduler.js';\nexport type {\n AgentConfig,\n QueueItem,\n CockpitParams,\n OrchestratorResult,\n} from './orchestrator/types.js';\n\n// Budget\nexport { TokenBudgetTracker } from './budget/tracker.js';\nexport type { BudgetData, BudgetEntry } from './budget/tracker.js';\n\n// Default agents\nexport { DEFAULT_AGENTS } from './agents/defaults.js';\n\nexport async function createAi(config: import('./providers/registry.js').ProviderConfig = {}) {\n const { ProviderRegistry } = await import('./providers/registry.js');\n const { ContentAgent } = await import('./agents/content.js');\n const { SeoAgent } = await import('./agents/seo.js');\n\n const registry = new ProviderRegistry(config);\n const provider = registry.get();\n\n return {\n registry,\n content: new ContentAgent(provider),\n seo: new SeoAgent(provider),\n };\n}\n","import type { AiProvider } from '../providers/types.js';\nimport type { AgentConfig, CockpitParams } from './types.js';\nimport type { CollectionConfig } from '@webhouse/cms';\n\nconst FAST_MODEL = 'claude-haiku-4-5-20251001';\n\nfunction buildFieldDescriptions(collection: CollectionConfig): string {\n return collection.fields\n .map(f => {\n const hint = f.ai?.hint ? ` (${f.ai.hint})` : '';\n const maxLen = f.ai?.maxLength ?? f.maxLength;\n const lenHint = maxLen ? ` (max ${maxLen} characters)` : '';\n return `- \"${f.name}\" (${f.type})${hint}${lenHint}${f.required === true ? ' [required]' : ''}`;\n })\n .join('\\n');\n}\n\nfunction resolveModel(agent: AgentConfig, cockpit: CockpitParams): string {\n if (cockpit.speedQuality === 'fast') {\n // Use haiku unless the user explicitly chose an openai model\n if (cockpit.primaryModel.startsWith('gpt') || cockpit.primaryModel.startsWith('o1')) {\n return cockpit.primaryModel;\n }\n return FAST_MODEL;\n }\n return cockpit.primaryModel;\n}\n\nfunction buildSystemPrompt(\n agent: AgentConfig,\n collection: CollectionConfig,\n cockpit: CockpitParams,\n feedbackExamples?: { original: string; corrected: string }[],\n): string {\n const parts: string[] = [];\n\n // Agent's own system prompt\n parts.push(agent.systemPrompt);\n\n // Formality / verbosity guidance\n if (agent.behavior.formality > 70) {\n parts.push('Use formal, professional language.');\n } else if (agent.behavior.formality < 30) {\n parts.push('Use casual, conversational language.');\n }\n if (agent.behavior.verbosity > 70) {\n parts.push('Be thorough and detailed in your writing.');\n } else if (agent.behavior.verbosity < 30) {\n parts.push('Be concise and to the point.');\n }\n\n if (cockpit.promptDepth === 'minimal') {\n // Brief instructions only — no extras\n }\n\n if (cockpit.promptDepth === 'medium' || cockpit.promptDepth === 'deep') {\n parts.push(`Collection: ${collection.label ?? collection.name}`);\n parts.push(`Fields:\\n${buildFieldDescriptions(collection)}`);\n }\n\n if (cockpit.promptDepth === 'deep') {\n if (cockpit.seoWeight > 50) {\n parts.push(\n `SEO priority: ${cockpit.seoWeight}%. Optimize for search engines: use target keywords naturally in title, headings, and first paragraph. Write a compelling meta description under 160 characters.`,\n );\n }\n\n if (feedbackExamples && feedbackExamples.length > 0) {\n const examples = feedbackExamples.slice(-3);\n parts.push('Learn from these past corrections:');\n for (const ex of examples) {\n parts.push(`Original: ${ex.original}\\nCorrected: ${ex.corrected}`);\n }\n }\n } else if (cockpit.seoWeight > 50) {\n // Even in medium depth, mention SEO if weight is high\n parts.push(`Optimize content for SEO (weight: ${cockpit.seoWeight}%).`);\n }\n\n if (cockpit.speedQuality === 'thorough') {\n parts.push(\n 'After generating the content, review it yourself for accuracy, tone, grammar, and completeness. Fix any issues before returning the final version.',\n );\n }\n\n return parts.join('\\n\\n');\n}\n\nexport class OrchestratorEngine {\n constructor(private provider: AiProvider) {}\n\n async run(\n prompt: string,\n agent: AgentConfig,\n collection: CollectionConfig,\n cockpit: CockpitParams,\n feedbackExamples?: { original: string; corrected: string }[],\n ): Promise<{ contentData: Record<string, unknown>; slug: string; costUsd: number }> {\n const systemPrompt = buildSystemPrompt(agent, collection, cockpit, feedbackExamples);\n const model = resolveModel(agent, cockpit);\n\n const fieldDesc = buildFieldDescriptions(collection);\n const userPrompt = `Create content for: \"${prompt}\"\n\nReturn a JSON object with these fields:\n${fieldDesc}\n\nFor \"richtext\" fields, use Markdown formatting.\nFor \"date\" fields, use ISO 8601 format (e.g. \"${new Date().toISOString()}\").\nFor \"slug\", generate a URL-friendly slug from the title (lowercase, hyphens).\n\nReturn ONLY valid JSON, no explanation, no markdown code blocks.`;\n\n const temperature = agent.behavior.temperature / 100;\n const result = await this.provider.generate(userPrompt, {\n systemPrompt,\n model,\n temperature,\n });\n\n let contentData: Record<string, unknown>;\n try {\n const cleaned = result.text\n .replace(/^```(?:json)?\\n?/m, '')\n .replace(/\\n?```$/m, '')\n .trim();\n contentData = JSON.parse(cleaned) as Record<string, unknown>;\n } catch {\n throw new Error(`AI returned invalid JSON: ${result.text.slice(0, 200)}`);\n }\n\n const slug = String(contentData['slug'] ?? contentData['title'] ?? 'untitled')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\n return {\n contentData,\n slug,\n costUsd: result.estimatedCostUsd,\n };\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { randomUUID } from 'crypto';\nimport type { QueueItem } from './types.js';\n\ninterface CmsInstance {\n content: {\n create: (collection: string, data: Record<string, unknown>) => Promise<unknown>;\n };\n}\n\nexport class CurationQueue {\n private filePath: string;\n\n constructor(private dataDir: string) {\n this.filePath = path.join(dataDir, 'curation-queue.json');\n }\n\n async list(status?: QueueItem['status']): Promise<QueueItem[]> {\n const items = await this.read();\n if (status === undefined) return items;\n return items.filter(i => i.status === status);\n }\n\n async get(id: string): Promise<QueueItem | null> {\n const items = await this.read();\n return items.find(i => i.id === id) ?? null;\n }\n\n async add(item: Omit<QueueItem, 'id' | 'generatedAt'>): Promise<QueueItem> {\n const items = await this.read();\n const newItem: QueueItem = {\n ...item,\n id: randomUUID(),\n generatedAt: new Date().toISOString(),\n };\n items.push(newItem);\n await this.write(items);\n return newItem;\n }\n\n async updateStatus(id: string, status: QueueItem['status'], feedback?: string): Promise<QueueItem> {\n const items = await this.read();\n const idx = items.findIndex(i => i.id === id);\n if (idx === -1) throw new Error(`Queue item not found: ${id}`);\n const item = items[idx]!;\n item.status = status;\n if (feedback !== undefined) {\n item.rejectionFeedback = feedback;\n }\n await this.write(items);\n return item;\n }\n\n async approve(id: string, cmsInstance: CmsInstance): Promise<QueueItem> {\n const item = await this.updateStatus(id, 'approved');\n await cmsInstance.content.create(item.collection, { ...item.contentData, status: 'published' });\n return await this.updateStatus(id, 'published');\n }\n\n async reject(id: string, feedback: string): Promise<QueueItem> {\n return this.updateStatus(id, 'rejected', feedback);\n }\n\n async getStats(): Promise<{ ready: number; in_review: number; approved: number; rejected: number; published: number }> {\n const items = await this.read();\n return {\n ready: items.filter(i => i.status === 'ready').length,\n in_review: items.filter(i => i.status === 'in_review').length,\n approved: items.filter(i => i.status === 'approved').length,\n rejected: items.filter(i => i.status === 'rejected').length,\n published: items.filter(i => i.status === 'published').length,\n };\n }\n\n private async read(): Promise<QueueItem[]> {\n try {\n const raw = await fs.readFile(this.filePath, 'utf-8');\n return JSON.parse(raw) as QueueItem[];\n } catch {\n return [];\n }\n }\n\n private async write(items: QueueItem[]): Promise<void> {\n await fs.mkdir(path.dirname(this.filePath), { recursive: true });\n await fs.writeFile(this.filePath, JSON.stringify(items, null, 2));\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport type { CollectionConfig } from '@webhouse/cms';\nimport type { AgentConfig, CockpitParams, OrchestratorResult } from './types.js';\nimport type { OrchestratorEngine } from './engine.js';\nimport type { CurationQueue } from './queue.js';\n\ninterface FeedbackExample {\n original: string;\n corrected: string;\n}\n\nexport class AgentRunner {\n constructor(\n private engine: OrchestratorEngine,\n private queue: CurationQueue,\n private dataDir: string,\n ) {}\n\n async run(\n agent: AgentConfig,\n collection: CollectionConfig,\n cockpit: CockpitParams,\n prompt: string,\n ): Promise<OrchestratorResult> {\n // 1. Load feedback examples for this agent\n const feedbackExamples = await this.loadFeedback(agent.id);\n\n // 2. Call engine\n const result = await this.engine.run(prompt, agent, collection, cockpit, feedbackExamples);\n\n // 3. Determine autonomy → queue status\n const shouldAutoPublish =\n agent.autonomy === 'full' &&\n agent.stats.totalGenerated >= 20 &&\n (agent.stats.approved + agent.stats.rejected) > 0 &&\n agent.stats.approved / (agent.stats.approved + agent.stats.rejected) > 0.95;\n\n const status = shouldAutoPublish ? 'approved' as const : 'ready' as const;\n const title = typeof result.contentData['title'] === 'string'\n ? result.contentData['title']\n : result.slug;\n\n const queueItem = await this.queue.add({\n agentId: agent.id,\n agentName: agent.name,\n collection: collection.name,\n slug: result.slug,\n title,\n status,\n contentData: result.contentData,\n costUsd: result.costUsd,\n });\n\n return {\n queueItemId: queueItem.id,\n agentId: agent.id,\n collection: collection.name,\n slug: result.slug,\n title,\n contentData: result.contentData,\n costUsd: result.costUsd,\n publishedDirectly: shouldAutoPublish,\n };\n }\n\n private async loadFeedback(agentId: string): Promise<FeedbackExample[]> {\n const feedbackPath = path.join(this.dataDir, 'agents', agentId, 'feedback.json');\n try {\n const raw = await fs.readFile(feedbackPath, 'utf-8');\n return JSON.parse(raw) as FeedbackExample[];\n } catch {\n return [];\n }\n }\n}\n","import type { AgentConfig } from './types.js';\n\nconst WINDOW_MINUTES = 5;\n\nexport class AgentScheduler {\n shouldRun(agent: AgentConfig, now: Date): boolean {\n if (!agent.active || !agent.schedule.enabled) return false;\n if (agent.schedule.frequency === 'manual') return false;\n\n if (agent.schedule.frequency === 'weekly' && now.getDay() !== 1) {\n return false; // Only Mondays\n }\n\n const { hours, minutes } = this.parseTime(agent.schedule.time);\n const nowMinutes = now.getHours() * 60 + now.getMinutes();\n const scheduleMinutes = hours * 60 + minutes;\n const diff = Math.abs(nowMinutes - scheduleMinutes);\n\n return diff <= WINDOW_MINUTES || diff >= 1440 - WINDOW_MINUTES;\n }\n\n getDueAgents(agents: AgentConfig[], now?: Date): AgentConfig[] {\n const timestamp = now ?? new Date();\n return agents.filter(a => this.shouldRun(a, timestamp));\n }\n\n private parseTime(timeStr: string): { hours: number; minutes: number } {\n const [h, m] = timeStr.split(':');\n return {\n hours: parseInt(h ?? '0', 10),\n minutes: parseInt(m ?? '0', 10),\n };\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\ninterface BudgetEntry {\n date: string;\n agentId: string;\n collection: string;\n costUsd: number;\n inputTokens: number;\n outputTokens: number;\n}\n\ninterface BudgetData {\n monthlyBudgetUsd: number;\n entries: BudgetEntry[];\n}\n\nexport type { BudgetData, BudgetEntry };\n\nexport class TokenBudgetTracker {\n private filePath: string;\n\n constructor(private dataDir: string) {\n this.filePath = path.join(dataDir, 'ai-budget.json');\n }\n\n async record(entry: Omit<BudgetEntry, 'date'>): Promise<void> {\n const data = await this.read();\n data.entries.push({\n ...entry,\n date: new Date().toISOString(),\n });\n await this.write(data);\n }\n\n async getCurrentMonthSpent(): Promise<number> {\n const data = await this.read();\n const now = new Date();\n const year = now.getFullYear();\n const month = now.getMonth();\n\n return data.entries\n .filter(e => {\n const d = new Date(e.date);\n return d.getFullYear() === year && d.getMonth() === month;\n })\n .reduce((sum, e) => sum + e.costUsd, 0);\n }\n\n async isOverBudget(monthlyLimitUsd: number): Promise<boolean> {\n const spent = await this.getCurrentMonthSpent();\n return spent >= monthlyLimitUsd;\n }\n\n async getSummary(): Promise<{\n currentMonthUsd: number;\n totalUsd: number;\n byAgent: Record<string, number>;\n }> {\n const data = await this.read();\n const currentMonthUsd = await this.getCurrentMonthSpent();\n const totalUsd = data.entries.reduce((sum, e) => sum + e.costUsd, 0);\n\n const byAgent: Record<string, number> = {};\n for (const entry of data.entries) {\n byAgent[entry.agentId] = (byAgent[entry.agentId] ?? 0) + entry.costUsd;\n }\n\n return { currentMonthUsd, totalUsd, byAgent };\n }\n\n private async read(): Promise<BudgetData> {\n try {\n const raw = await fs.readFile(this.filePath, 'utf-8');\n return JSON.parse(raw) as BudgetData;\n } catch {\n return { monthlyBudgetUsd: 0, entries: [] };\n }\n }\n\n private async write(data: BudgetData): Promise<void> {\n await fs.mkdir(path.dirname(this.filePath), { recursive: true });\n await fs.writeFile(this.filePath, JSON.stringify(data, null, 2));\n }\n}\n","import type { AgentConfig } from '../orchestrator/types.js';\n\nconst now = new Date().toISOString();\n\nconst baseStats: AgentConfig['stats'] = {\n totalGenerated: 0,\n approved: 0,\n rejected: 0,\n edited: 0,\n};\n\nconst baseSchedule: AgentConfig['schedule'] = {\n enabled: false,\n frequency: 'manual',\n time: '09:00',\n maxPerRun: 5,\n};\n\nexport const DEFAULT_AGENTS: AgentConfig[] = [\n {\n id: 'content-writer',\n name: 'Content Writer',\n role: 'copywriter',\n systemPrompt:\n 'You are a professional content writer. Write engaging, well-structured content that speaks to the target audience. Use clear headings, short paragraphs, and a natural tone.',\n behavior: { temperature: 65, formality: 50, verbosity: 60 },\n tools: { webSearch: false, internalDatabase: true },\n autonomy: 'draft',\n targetCollections: [],\n schedule: { ...baseSchedule },\n stats: { ...baseStats },\n createdAt: now,\n updatedAt: now,\n active: true,\n },\n {\n id: 'seo-optimizer',\n name: 'SEO Optimizer',\n role: 'seo',\n systemPrompt:\n 'You are an SEO specialist. Optimize existing content for search engines without compromising readability. Focus on keywords, meta descriptions, heading structure, and internal linking.',\n behavior: { temperature: 30, formality: 60, verbosity: 40 },\n tools: { webSearch: true, internalDatabase: true },\n autonomy: 'draft',\n targetCollections: [],\n schedule: { ...baseSchedule, frequency: 'weekly' },\n stats: { ...baseStats },\n createdAt: now,\n updatedAt: now,\n active: true,\n },\n {\n id: 'translator',\n name: 'Translator',\n role: 'translator',\n systemPrompt:\n 'You are a professional translator. Translate content naturally and idiomatically into the target language. Preserve meaning, tone, and formatting. Adapt cultural references where relevant.',\n behavior: { temperature: 20, formality: 50, verbosity: 50 },\n tools: { webSearch: false, internalDatabase: true },\n autonomy: 'draft',\n targetCollections: [],\n schedule: { ...baseSchedule },\n stats: { ...baseStats },\n createdAt: now,\n updatedAt: now,\n active: true,\n },\n {\n id: 'content-refresher',\n name: 'Content Refresher',\n role: 'refresher',\n systemPrompt:\n 'You are a specialist in updating and refreshing existing content. Find outdated information, update statistics and facts, improve phrasing, and add relevant new content. Preserve the original tone and structure.',\n behavior: { temperature: 40, formality: 50, verbosity: 50 },\n tools: { webSearch: true, internalDatabase: true },\n autonomy: 'draft',\n targetCollections: [],\n schedule: { ...baseSchedule, frequency: 'weekly', time: '06:00' },\n stats: { ...baseStats },\n createdAt: now,\n updatedAt: now,\n active: true,\n },\n];\n"],"mappings":"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","names":["Anthropic","PRICING","OpenAI","path","fs","import_promises","import_path","path","fs","now","import_promises","import_path","path","now","fs","ProviderRegistry","ContentAgent","SeoAgent"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { CollectionConfig, Document } from '@webhouse/cms';
|
|
2
|
+
|
|
3
|
+
interface TextGenerationOptions {
|
|
4
|
+
model?: string;
|
|
5
|
+
maxTokens?: number;
|
|
6
|
+
temperature?: number;
|
|
7
|
+
systemPrompt?: string;
|
|
8
|
+
}
|
|
9
|
+
interface TextGenerationResult {
|
|
10
|
+
text: string;
|
|
11
|
+
inputTokens: number;
|
|
12
|
+
outputTokens: number;
|
|
13
|
+
model: string;
|
|
14
|
+
provider: string;
|
|
15
|
+
estimatedCostUsd: number;
|
|
16
|
+
}
|
|
17
|
+
interface AiProvider {
|
|
18
|
+
name: string;
|
|
19
|
+
defaultModel: string;
|
|
20
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
21
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ProviderConfig {
|
|
25
|
+
anthropic?: {
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
defaultModel?: string;
|
|
28
|
+
};
|
|
29
|
+
openai?: {
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
defaultModel?: string;
|
|
32
|
+
};
|
|
33
|
+
defaultProvider?: 'anthropic' | 'openai';
|
|
34
|
+
}
|
|
35
|
+
declare class ProviderRegistry {
|
|
36
|
+
private providers;
|
|
37
|
+
private defaultProviderName;
|
|
38
|
+
constructor(config?: ProviderConfig);
|
|
39
|
+
get(name?: string): AiProvider;
|
|
40
|
+
list(): string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare class AnthropicProvider implements AiProvider {
|
|
44
|
+
name: string;
|
|
45
|
+
defaultModel: string;
|
|
46
|
+
private client;
|
|
47
|
+
constructor(apiKey?: string);
|
|
48
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
49
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare class OpenAiProvider implements AiProvider {
|
|
53
|
+
name: string;
|
|
54
|
+
defaultModel: string;
|
|
55
|
+
private client;
|
|
56
|
+
constructor(apiKey?: string);
|
|
57
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
58
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface GenerateOptions extends TextGenerationOptions {
|
|
62
|
+
collection: CollectionConfig;
|
|
63
|
+
locale?: string;
|
|
64
|
+
tone?: string;
|
|
65
|
+
targetAudience?: string;
|
|
66
|
+
}
|
|
67
|
+
interface GenerateResult {
|
|
68
|
+
fields: Record<string, string>;
|
|
69
|
+
slug: string;
|
|
70
|
+
usage: {
|
|
71
|
+
inputTokens: number;
|
|
72
|
+
outputTokens: number;
|
|
73
|
+
estimatedCostUsd: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
interface RewriteOptions extends TextGenerationOptions {
|
|
77
|
+
instruction: string;
|
|
78
|
+
collection: CollectionConfig;
|
|
79
|
+
}
|
|
80
|
+
declare class ContentAgent {
|
|
81
|
+
private provider;
|
|
82
|
+
constructor(provider: AiProvider);
|
|
83
|
+
generate(prompt: string, options: GenerateOptions): Promise<GenerateResult>;
|
|
84
|
+
rewrite(currentData: Record<string, unknown>, options: RewriteOptions): Promise<GenerateResult>;
|
|
85
|
+
translate(currentData: Record<string, unknown>, targetLocale: string, options: Partial<TextGenerationOptions> & {
|
|
86
|
+
collection: CollectionConfig;
|
|
87
|
+
}): Promise<GenerateResult>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface SeoResult {
|
|
91
|
+
metaTitle: string;
|
|
92
|
+
metaDescription: string;
|
|
93
|
+
jsonLd: Record<string, unknown>;
|
|
94
|
+
usage: {
|
|
95
|
+
inputTokens: number;
|
|
96
|
+
outputTokens: number;
|
|
97
|
+
estimatedCostUsd: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
declare class SeoAgent {
|
|
101
|
+
private provider;
|
|
102
|
+
constructor(provider: AiProvider);
|
|
103
|
+
optimize(doc: Document, siteTitle: string, baseUrl: string): Promise<SeoResult>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface AgentConfig {
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
role: 'copywriter' | 'seo' | 'translator' | 'refresher' | 'custom';
|
|
110
|
+
systemPrompt: string;
|
|
111
|
+
behavior: {
|
|
112
|
+
temperature: number;
|
|
113
|
+
formality: number;
|
|
114
|
+
verbosity: number;
|
|
115
|
+
};
|
|
116
|
+
tools: {
|
|
117
|
+
webSearch: boolean;
|
|
118
|
+
internalDatabase: boolean;
|
|
119
|
+
};
|
|
120
|
+
autonomy: 'draft' | 'full';
|
|
121
|
+
targetCollections: string[];
|
|
122
|
+
schedule: {
|
|
123
|
+
enabled: boolean;
|
|
124
|
+
frequency: 'daily' | 'weekly' | 'manual';
|
|
125
|
+
time: string;
|
|
126
|
+
maxPerRun: number;
|
|
127
|
+
};
|
|
128
|
+
stats: {
|
|
129
|
+
totalGenerated: number;
|
|
130
|
+
approved: number;
|
|
131
|
+
rejected: number;
|
|
132
|
+
edited: number;
|
|
133
|
+
};
|
|
134
|
+
createdAt: string;
|
|
135
|
+
updatedAt: string;
|
|
136
|
+
active: boolean;
|
|
137
|
+
}
|
|
138
|
+
interface QueueItem {
|
|
139
|
+
id: string;
|
|
140
|
+
agentId: string;
|
|
141
|
+
agentName: string;
|
|
142
|
+
collection: string;
|
|
143
|
+
slug: string;
|
|
144
|
+
title: string;
|
|
145
|
+
status: 'ready' | 'in_review' | 'approved' | 'rejected' | 'published';
|
|
146
|
+
generatedAt: string;
|
|
147
|
+
contentData: Record<string, unknown>;
|
|
148
|
+
alternatives?: {
|
|
149
|
+
model: string;
|
|
150
|
+
contentData: Record<string, unknown>;
|
|
151
|
+
score?: number;
|
|
152
|
+
}[];
|
|
153
|
+
seoScore?: number;
|
|
154
|
+
readabilityScore?: number;
|
|
155
|
+
estimatedReadTime?: number;
|
|
156
|
+
costUsd: number;
|
|
157
|
+
rejectionFeedback?: string;
|
|
158
|
+
}
|
|
159
|
+
interface CockpitParams {
|
|
160
|
+
temperature: number;
|
|
161
|
+
promptDepth: 'minimal' | 'medium' | 'deep';
|
|
162
|
+
seoWeight: number;
|
|
163
|
+
speedQuality: 'fast' | 'balanced' | 'thorough';
|
|
164
|
+
primaryModel: string;
|
|
165
|
+
multiModelEnabled: boolean;
|
|
166
|
+
compareModels: string[];
|
|
167
|
+
monthlyBudgetUsd: number;
|
|
168
|
+
currentMonthSpentUsd: number;
|
|
169
|
+
}
|
|
170
|
+
interface OrchestratorResult {
|
|
171
|
+
queueItemId: string;
|
|
172
|
+
agentId: string;
|
|
173
|
+
collection: string;
|
|
174
|
+
slug: string;
|
|
175
|
+
title: string;
|
|
176
|
+
contentData: Record<string, unknown>;
|
|
177
|
+
costUsd: number;
|
|
178
|
+
publishedDirectly: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
declare class OrchestratorEngine {
|
|
182
|
+
private provider;
|
|
183
|
+
constructor(provider: AiProvider);
|
|
184
|
+
run(prompt: string, agent: AgentConfig, collection: CollectionConfig, cockpit: CockpitParams, feedbackExamples?: {
|
|
185
|
+
original: string;
|
|
186
|
+
corrected: string;
|
|
187
|
+
}[]): Promise<{
|
|
188
|
+
contentData: Record<string, unknown>;
|
|
189
|
+
slug: string;
|
|
190
|
+
costUsd: number;
|
|
191
|
+
}>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface CmsInstance {
|
|
195
|
+
content: {
|
|
196
|
+
create: (collection: string, data: Record<string, unknown>) => Promise<unknown>;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
declare class CurationQueue {
|
|
200
|
+
private dataDir;
|
|
201
|
+
private filePath;
|
|
202
|
+
constructor(dataDir: string);
|
|
203
|
+
list(status?: QueueItem['status']): Promise<QueueItem[]>;
|
|
204
|
+
get(id: string): Promise<QueueItem | null>;
|
|
205
|
+
add(item: Omit<QueueItem, 'id' | 'generatedAt'>): Promise<QueueItem>;
|
|
206
|
+
updateStatus(id: string, status: QueueItem['status'], feedback?: string): Promise<QueueItem>;
|
|
207
|
+
approve(id: string, cmsInstance: CmsInstance): Promise<QueueItem>;
|
|
208
|
+
reject(id: string, feedback: string): Promise<QueueItem>;
|
|
209
|
+
getStats(): Promise<{
|
|
210
|
+
ready: number;
|
|
211
|
+
in_review: number;
|
|
212
|
+
approved: number;
|
|
213
|
+
rejected: number;
|
|
214
|
+
published: number;
|
|
215
|
+
}>;
|
|
216
|
+
private read;
|
|
217
|
+
private write;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
declare class AgentRunner {
|
|
221
|
+
private engine;
|
|
222
|
+
private queue;
|
|
223
|
+
private dataDir;
|
|
224
|
+
constructor(engine: OrchestratorEngine, queue: CurationQueue, dataDir: string);
|
|
225
|
+
run(agent: AgentConfig, collection: CollectionConfig, cockpit: CockpitParams, prompt: string): Promise<OrchestratorResult>;
|
|
226
|
+
private loadFeedback;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
declare class AgentScheduler {
|
|
230
|
+
shouldRun(agent: AgentConfig, now: Date): boolean;
|
|
231
|
+
getDueAgents(agents: AgentConfig[], now?: Date): AgentConfig[];
|
|
232
|
+
private parseTime;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface BudgetEntry {
|
|
236
|
+
date: string;
|
|
237
|
+
agentId: string;
|
|
238
|
+
collection: string;
|
|
239
|
+
costUsd: number;
|
|
240
|
+
inputTokens: number;
|
|
241
|
+
outputTokens: number;
|
|
242
|
+
}
|
|
243
|
+
interface BudgetData {
|
|
244
|
+
monthlyBudgetUsd: number;
|
|
245
|
+
entries: BudgetEntry[];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
declare class TokenBudgetTracker {
|
|
249
|
+
private dataDir;
|
|
250
|
+
private filePath;
|
|
251
|
+
constructor(dataDir: string);
|
|
252
|
+
record(entry: Omit<BudgetEntry, 'date'>): Promise<void>;
|
|
253
|
+
getCurrentMonthSpent(): Promise<number>;
|
|
254
|
+
isOverBudget(monthlyLimitUsd: number): Promise<boolean>;
|
|
255
|
+
getSummary(): Promise<{
|
|
256
|
+
currentMonthUsd: number;
|
|
257
|
+
totalUsd: number;
|
|
258
|
+
byAgent: Record<string, number>;
|
|
259
|
+
}>;
|
|
260
|
+
private read;
|
|
261
|
+
private write;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
declare const DEFAULT_AGENTS: AgentConfig[];
|
|
265
|
+
|
|
266
|
+
declare function createAi(config?: ProviderConfig): Promise<{
|
|
267
|
+
registry: ProviderRegistry;
|
|
268
|
+
content: ContentAgent;
|
|
269
|
+
seo: SeoAgent;
|
|
270
|
+
}>;
|
|
271
|
+
|
|
272
|
+
export { type AgentConfig, AgentRunner, AgentScheduler, type AiProvider, AnthropicProvider, type BudgetData, type BudgetEntry, type CockpitParams, ContentAgent, CurationQueue, DEFAULT_AGENTS, type GenerateOptions, type GenerateResult, OpenAiProvider, OrchestratorEngine, type OrchestratorResult, type ProviderConfig, ProviderRegistry, type QueueItem, type RewriteOptions, SeoAgent, type SeoResult, type TextGenerationOptions, type TextGenerationResult, TokenBudgetTracker, createAi };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { CollectionConfig, Document } from '@webhouse/cms';
|
|
2
|
+
|
|
3
|
+
interface TextGenerationOptions {
|
|
4
|
+
model?: string;
|
|
5
|
+
maxTokens?: number;
|
|
6
|
+
temperature?: number;
|
|
7
|
+
systemPrompt?: string;
|
|
8
|
+
}
|
|
9
|
+
interface TextGenerationResult {
|
|
10
|
+
text: string;
|
|
11
|
+
inputTokens: number;
|
|
12
|
+
outputTokens: number;
|
|
13
|
+
model: string;
|
|
14
|
+
provider: string;
|
|
15
|
+
estimatedCostUsd: number;
|
|
16
|
+
}
|
|
17
|
+
interface AiProvider {
|
|
18
|
+
name: string;
|
|
19
|
+
defaultModel: string;
|
|
20
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
21
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ProviderConfig {
|
|
25
|
+
anthropic?: {
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
defaultModel?: string;
|
|
28
|
+
};
|
|
29
|
+
openai?: {
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
defaultModel?: string;
|
|
32
|
+
};
|
|
33
|
+
defaultProvider?: 'anthropic' | 'openai';
|
|
34
|
+
}
|
|
35
|
+
declare class ProviderRegistry {
|
|
36
|
+
private providers;
|
|
37
|
+
private defaultProviderName;
|
|
38
|
+
constructor(config?: ProviderConfig);
|
|
39
|
+
get(name?: string): AiProvider;
|
|
40
|
+
list(): string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare class AnthropicProvider implements AiProvider {
|
|
44
|
+
name: string;
|
|
45
|
+
defaultModel: string;
|
|
46
|
+
private client;
|
|
47
|
+
constructor(apiKey?: string);
|
|
48
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
49
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare class OpenAiProvider implements AiProvider {
|
|
53
|
+
name: string;
|
|
54
|
+
defaultModel: string;
|
|
55
|
+
private client;
|
|
56
|
+
constructor(apiKey?: string);
|
|
57
|
+
estimateCost(inputTokens: number, outputTokens: number, model?: string): number;
|
|
58
|
+
generate(prompt: string, options?: TextGenerationOptions): Promise<TextGenerationResult>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface GenerateOptions extends TextGenerationOptions {
|
|
62
|
+
collection: CollectionConfig;
|
|
63
|
+
locale?: string;
|
|
64
|
+
tone?: string;
|
|
65
|
+
targetAudience?: string;
|
|
66
|
+
}
|
|
67
|
+
interface GenerateResult {
|
|
68
|
+
fields: Record<string, string>;
|
|
69
|
+
slug: string;
|
|
70
|
+
usage: {
|
|
71
|
+
inputTokens: number;
|
|
72
|
+
outputTokens: number;
|
|
73
|
+
estimatedCostUsd: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
interface RewriteOptions extends TextGenerationOptions {
|
|
77
|
+
instruction: string;
|
|
78
|
+
collection: CollectionConfig;
|
|
79
|
+
}
|
|
80
|
+
declare class ContentAgent {
|
|
81
|
+
private provider;
|
|
82
|
+
constructor(provider: AiProvider);
|
|
83
|
+
generate(prompt: string, options: GenerateOptions): Promise<GenerateResult>;
|
|
84
|
+
rewrite(currentData: Record<string, unknown>, options: RewriteOptions): Promise<GenerateResult>;
|
|
85
|
+
translate(currentData: Record<string, unknown>, targetLocale: string, options: Partial<TextGenerationOptions> & {
|
|
86
|
+
collection: CollectionConfig;
|
|
87
|
+
}): Promise<GenerateResult>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface SeoResult {
|
|
91
|
+
metaTitle: string;
|
|
92
|
+
metaDescription: string;
|
|
93
|
+
jsonLd: Record<string, unknown>;
|
|
94
|
+
usage: {
|
|
95
|
+
inputTokens: number;
|
|
96
|
+
outputTokens: number;
|
|
97
|
+
estimatedCostUsd: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
declare class SeoAgent {
|
|
101
|
+
private provider;
|
|
102
|
+
constructor(provider: AiProvider);
|
|
103
|
+
optimize(doc: Document, siteTitle: string, baseUrl: string): Promise<SeoResult>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface AgentConfig {
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
role: 'copywriter' | 'seo' | 'translator' | 'refresher' | 'custom';
|
|
110
|
+
systemPrompt: string;
|
|
111
|
+
behavior: {
|
|
112
|
+
temperature: number;
|
|
113
|
+
formality: number;
|
|
114
|
+
verbosity: number;
|
|
115
|
+
};
|
|
116
|
+
tools: {
|
|
117
|
+
webSearch: boolean;
|
|
118
|
+
internalDatabase: boolean;
|
|
119
|
+
};
|
|
120
|
+
autonomy: 'draft' | 'full';
|
|
121
|
+
targetCollections: string[];
|
|
122
|
+
schedule: {
|
|
123
|
+
enabled: boolean;
|
|
124
|
+
frequency: 'daily' | 'weekly' | 'manual';
|
|
125
|
+
time: string;
|
|
126
|
+
maxPerRun: number;
|
|
127
|
+
};
|
|
128
|
+
stats: {
|
|
129
|
+
totalGenerated: number;
|
|
130
|
+
approved: number;
|
|
131
|
+
rejected: number;
|
|
132
|
+
edited: number;
|
|
133
|
+
};
|
|
134
|
+
createdAt: string;
|
|
135
|
+
updatedAt: string;
|
|
136
|
+
active: boolean;
|
|
137
|
+
}
|
|
138
|
+
interface QueueItem {
|
|
139
|
+
id: string;
|
|
140
|
+
agentId: string;
|
|
141
|
+
agentName: string;
|
|
142
|
+
collection: string;
|
|
143
|
+
slug: string;
|
|
144
|
+
title: string;
|
|
145
|
+
status: 'ready' | 'in_review' | 'approved' | 'rejected' | 'published';
|
|
146
|
+
generatedAt: string;
|
|
147
|
+
contentData: Record<string, unknown>;
|
|
148
|
+
alternatives?: {
|
|
149
|
+
model: string;
|
|
150
|
+
contentData: Record<string, unknown>;
|
|
151
|
+
score?: number;
|
|
152
|
+
}[];
|
|
153
|
+
seoScore?: number;
|
|
154
|
+
readabilityScore?: number;
|
|
155
|
+
estimatedReadTime?: number;
|
|
156
|
+
costUsd: number;
|
|
157
|
+
rejectionFeedback?: string;
|
|
158
|
+
}
|
|
159
|
+
interface CockpitParams {
|
|
160
|
+
temperature: number;
|
|
161
|
+
promptDepth: 'minimal' | 'medium' | 'deep';
|
|
162
|
+
seoWeight: number;
|
|
163
|
+
speedQuality: 'fast' | 'balanced' | 'thorough';
|
|
164
|
+
primaryModel: string;
|
|
165
|
+
multiModelEnabled: boolean;
|
|
166
|
+
compareModels: string[];
|
|
167
|
+
monthlyBudgetUsd: number;
|
|
168
|
+
currentMonthSpentUsd: number;
|
|
169
|
+
}
|
|
170
|
+
interface OrchestratorResult {
|
|
171
|
+
queueItemId: string;
|
|
172
|
+
agentId: string;
|
|
173
|
+
collection: string;
|
|
174
|
+
slug: string;
|
|
175
|
+
title: string;
|
|
176
|
+
contentData: Record<string, unknown>;
|
|
177
|
+
costUsd: number;
|
|
178
|
+
publishedDirectly: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
declare class OrchestratorEngine {
|
|
182
|
+
private provider;
|
|
183
|
+
constructor(provider: AiProvider);
|
|
184
|
+
run(prompt: string, agent: AgentConfig, collection: CollectionConfig, cockpit: CockpitParams, feedbackExamples?: {
|
|
185
|
+
original: string;
|
|
186
|
+
corrected: string;
|
|
187
|
+
}[]): Promise<{
|
|
188
|
+
contentData: Record<string, unknown>;
|
|
189
|
+
slug: string;
|
|
190
|
+
costUsd: number;
|
|
191
|
+
}>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface CmsInstance {
|
|
195
|
+
content: {
|
|
196
|
+
create: (collection: string, data: Record<string, unknown>) => Promise<unknown>;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
declare class CurationQueue {
|
|
200
|
+
private dataDir;
|
|
201
|
+
private filePath;
|
|
202
|
+
constructor(dataDir: string);
|
|
203
|
+
list(status?: QueueItem['status']): Promise<QueueItem[]>;
|
|
204
|
+
get(id: string): Promise<QueueItem | null>;
|
|
205
|
+
add(item: Omit<QueueItem, 'id' | 'generatedAt'>): Promise<QueueItem>;
|
|
206
|
+
updateStatus(id: string, status: QueueItem['status'], feedback?: string): Promise<QueueItem>;
|
|
207
|
+
approve(id: string, cmsInstance: CmsInstance): Promise<QueueItem>;
|
|
208
|
+
reject(id: string, feedback: string): Promise<QueueItem>;
|
|
209
|
+
getStats(): Promise<{
|
|
210
|
+
ready: number;
|
|
211
|
+
in_review: number;
|
|
212
|
+
approved: number;
|
|
213
|
+
rejected: number;
|
|
214
|
+
published: number;
|
|
215
|
+
}>;
|
|
216
|
+
private read;
|
|
217
|
+
private write;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
declare class AgentRunner {
|
|
221
|
+
private engine;
|
|
222
|
+
private queue;
|
|
223
|
+
private dataDir;
|
|
224
|
+
constructor(engine: OrchestratorEngine, queue: CurationQueue, dataDir: string);
|
|
225
|
+
run(agent: AgentConfig, collection: CollectionConfig, cockpit: CockpitParams, prompt: string): Promise<OrchestratorResult>;
|
|
226
|
+
private loadFeedback;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
declare class AgentScheduler {
|
|
230
|
+
shouldRun(agent: AgentConfig, now: Date): boolean;
|
|
231
|
+
getDueAgents(agents: AgentConfig[], now?: Date): AgentConfig[];
|
|
232
|
+
private parseTime;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface BudgetEntry {
|
|
236
|
+
date: string;
|
|
237
|
+
agentId: string;
|
|
238
|
+
collection: string;
|
|
239
|
+
costUsd: number;
|
|
240
|
+
inputTokens: number;
|
|
241
|
+
outputTokens: number;
|
|
242
|
+
}
|
|
243
|
+
interface BudgetData {
|
|
244
|
+
monthlyBudgetUsd: number;
|
|
245
|
+
entries: BudgetEntry[];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
declare class TokenBudgetTracker {
|
|
249
|
+
private dataDir;
|
|
250
|
+
private filePath;
|
|
251
|
+
constructor(dataDir: string);
|
|
252
|
+
record(entry: Omit<BudgetEntry, 'date'>): Promise<void>;
|
|
253
|
+
getCurrentMonthSpent(): Promise<number>;
|
|
254
|
+
isOverBudget(monthlyLimitUsd: number): Promise<boolean>;
|
|
255
|
+
getSummary(): Promise<{
|
|
256
|
+
currentMonthUsd: number;
|
|
257
|
+
totalUsd: number;
|
|
258
|
+
byAgent: Record<string, number>;
|
|
259
|
+
}>;
|
|
260
|
+
private read;
|
|
261
|
+
private write;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
declare const DEFAULT_AGENTS: AgentConfig[];
|
|
265
|
+
|
|
266
|
+
declare function createAi(config?: ProviderConfig): Promise<{
|
|
267
|
+
registry: ProviderRegistry;
|
|
268
|
+
content: ContentAgent;
|
|
269
|
+
seo: SeoAgent;
|
|
270
|
+
}>;
|
|
271
|
+
|
|
272
|
+
export { type AgentConfig, AgentRunner, AgentScheduler, type AiProvider, AnthropicProvider, type BudgetData, type BudgetEntry, type CockpitParams, ContentAgent, CurationQueue, DEFAULT_AGENTS, type GenerateOptions, type GenerateResult, OpenAiProvider, OrchestratorEngine, type OrchestratorResult, type ProviderConfig, ProviderRegistry, type QueueItem, type RewriteOptions, SeoAgent, type SeoResult, type TextGenerationOptions, type TextGenerationResult, TokenBudgetTracker, createAi };
|