-
Notifications
You must be signed in to change notification settings - Fork 111
Description
Marketing Pipeline Upgrade
Current Architecture
flowchart LR
User["User: picks platform + writes prompt"] --> Context["context.ts: company name, employee count, categories, KB snippets"]
Context --> Trends["research.ts: generic trend search"]
Trends --> Generator["generator.ts: single LLM call"]
Generator --> Output["Output: platform post + media type"]
The user prompt is the primary driver. The system is a copywriter, not a strategist.
Proposed Architecture
flowchart TD
User["User: picks platform + optional topic"] --> Phase1
subgraph Phase1 ["Phase 1: Intelligence Gathering"]
CompanyDNA["Company DNA Extraction"]
CompetitorResearch["Competitor Research"]
TrendResearch["Trend Research"]
end
Phase1 --> Phase2
subgraph Phase2 ["Phase 2: Strategic Synthesis"]
Positioning["Competitive Positioning: why we win"]
end
Phase2 --> Phase3
subgraph Phase3 ["Phase 3: Content Generation"]
Generator["Humanized message with limited tech depth"]
end
Phase3 --> Output["Output: post + competitive angle + media type"]
Implementation
1. New module: Company DNA extraction (context.ts enhancement)
Currently buildCompanyKnowledgeContext() returns flat data. Enhance it to run two RAG queries:
- General context query (existing): company facts and capabilities
- Differentiator query (new): targeted search for unique strengths, open-source mentions, competitive advantages, awards, metrics, customer outcomes
Add a new function extractCompanyDNA() that uses LLM to distill the raw KB snippets into structured insights:
interface CompanyDNA {
coreMission: string;
keyDifferentiators: string[]; // e.g., "open source", "no vendor lock-in"
provenResults: string[]; // metrics, outcomes from KB
humanStory: string; // founding story, team ethos, values
technicalEdge: string; // simplified explanation of how it works
}This replaces the raw context string with a structured, LLM-distilled profile. File: context.ts.
2. New module: Competitor analysis (competitor.ts)
New file at src/lib/tools/marketing-pipeline/competitor.ts. This module:
- Uses company categories + name to build competitor search queries (via the existing trend-search web search infrastructure)
- Searches for competitors' messaging, positioning, and recent posts
- Uses LLM to synthesize a competitive landscape:
interface CompetitorAnalysis {
competitors: Array<{
name: string;
positioning: string;
weaknesses: string[];
}>;
ourAdvantages: string[]; // where we clearly win
marketGaps: string[]; // opportunities competitors miss
messagingAntiPatterns: string[]; // what competitors say that we should avoid
}Uses the existing runTrendSearch or direct web search providers from trend-search to gather raw data, then an LLM call to synthesize.
3. New module: Strategic positioning (positioning.ts)
New file at src/lib/tools/marketing-pipeline/positioning.ts. This is the "brain" that combines Company DNA + Competitor Analysis + Trends into a focused messaging angle:
interface MessagingStrategy {
angle: string; // the single tension/insight to lead with
keyProof: string; // the differentiator that backs it up
humanHook: string; // the relatable, human framing
avoidList: string[]; // competitor cliches to steer clear of
}Single LLM call that takes all three inputs and produces one focused strategy.
4. Shared model factory via LangChain (models.ts)
The project already has a getChatModel() factory in models.ts that supports OpenAI, Anthropic, and Google Gemini models through LangChain's BaseChatModel interface. The marketing pipeline currently bypasses this and hardcodes new ChatOpenAI() directly — which is both inflexible and caused the temperature bug (gpt-5-mini rejects temperature: 0.7).
Move getChatModel() to a shared location at src/lib/models.ts (or src/lib/models/index.ts) so it can be imported by both the marketing pipeline and other agents. Then use it in every LLM call within the marketing pipeline:
generator.ts— main content generation (currently broken with temperature error)context.ts— new CompanyDNA extraction callcompetitor.ts— new competitor analysis synthesis callpositioning.ts— new strategic positioning call
This gives you one place to swap models. Want to try Claude Sonnet for marketing content? Change one line. All calls go through LangChain's BaseChatModel interface, so any provider LangChain supports (OpenAI, Anthropic, Google, Mistral, Cohere, etc.) works with zero changes to the pipeline logic.
For the marketing pipeline specifically, we can define a config object:
const MARKETING_MODELS = {
dnaExtraction: "gpt-5-mini" as AIModelType,
competitorAnalysis: "gpt-5-mini" as AIModelType,
positioning: "gpt-5-mini" as AIModelType,
contentGeneration: "gpt-5.2" as AIModelType,
};This makes it trivial to experiment with different models for different pipeline stages.
5. Generator rewrite (generator.ts)
Update the system prompt and buildPrompt() in generator.ts. Replace new ChatOpenAI(...) with getChatModel(MARKETING_MODELS.contentGeneration):
- System prompt changes:
- Add explicit humanization rules: "Write as if explaining to a smart friend over coffee, not presenting at a conference"
- Add technical depth constraint: "If you mention how something works, keep it to one sentence max. Focus on what it means for the reader, not the implementation"
- Add competitor-awareness rules: "Use competitive insights to create contrast, but never name competitors directly"
- Prompt structure changes:
- Replace raw company context with structured
CompanyDNA - Add
CompetitorAnalysissummary - Add
MessagingStrategyas the primary directive - Make the user prompt an optional "topic focus" rather than the primary driver
- Replace raw company context with structured
- Output schema update: Add a
competitiveAnglefield so the UI can show why this message was crafted this way.
6. Pipeline orchestration update (run.ts)
Update run.ts to add the new steps. Run Company DNA + Competitor Research + Trend Research in parallel for speed:
1. extractCompanyDNA() ─┐
2. analyzeCompetitors() ├─ parallel
3. researchPlatformTrends() ─┘
4. buildMessagingStrategy() ← sequential (needs 1-3)
5. generateCampaignOutput() ← sequential (needs 4)
7. Types update (types.ts)
In types.ts:
- Make
promptoptional inMarketingPipelineInputSchema(with.optional()) - Add
CompanyDNA,CompetitorAnalysis,MessagingStrategyinterfaces - Extend
MarketingPipelineResultwithcompetitiveAngle: stringandstrategyUsed: MessagingStrategy - Add output schema for the new
competitiveAnglefield