Skip to content

Commit 0bc2a3e

Browse files
committed
sonar
1 parent 0cd9ce1 commit 0bc2a3e

File tree

5 files changed

+56
-5
lines changed

5 files changed

+56
-5
lines changed

apps/api/src/ai/agents.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { buildReflectionInstructions } from "./prompts/reflection";
1313
import { buildTriageInstructions } from "./prompts/triage";
1414
import { executeSqlQueryTool } from "./tools/execute-sql-query";
1515
import { getTopPagesTool } from "./tools/get-top-pages";
16-
import { webSearchTool } from "./tools/web-search";
16+
import { competitorAnalysisTool, webSearchTool } from "./tools/web-search";
1717

1818
/**
1919
* Tools available to analytics agents.
@@ -22,6 +22,7 @@ const analyticsTools = {
2222
get_top_pages: getTopPagesTool,
2323
execute_sql_query: executeSqlQueryTool,
2424
web_search: webSearchTool,
25+
competitor_analysis: competitorAnalysisTool,
2526
...(Object.keys(memoryTools).length > 0 ? memoryTools : {}),
2627
} as const;
2728

@@ -30,6 +31,7 @@ const analyticsTools = {
3031
*/
3132
const triageTools = {
3233
web_search: webSearchTool,
34+
competitor_analysis: competitorAnalysisTool,
3335
...(Object.keys(memoryTools).length > 0 ? memoryTools : {}),
3436
} as const;
3537

apps/api/src/ai/config/models.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,22 @@ export const openrouter = createOpenRouter({
1818
*/
1919
export const models = {
2020
/** Fast, cheap model for routing/triage decisions */
21-
triage: openrouter.chat(process.env.AI_TRIAGE_MODEL ?? "anthropic/claude-haiku-4.5"),
21+
triage: openrouter.chat(
22+
process.env.AI_TRIAGE_MODEL ?? "anthropic/claude-haiku-4.5"
23+
),
2224

2325
/** Balanced model for most analytical tasks */
24-
analytics: openrouter.chat(process.env.AI_ANALYTICS_MODEL ?? "anthropic/claude-haiku-4.5"),
26+
analytics: openrouter.chat(
27+
process.env.AI_ANALYTICS_MODEL ?? "anthropic/claude-haiku-4.5"
28+
),
2529

2630
/** High-capability model for complex reasoning and reflection */
27-
advanced: openrouter.chat(process.env.AI_ADVANCED_MODEL ?? "anthropic/claude-sonnet-4.5"),
31+
advanced: openrouter.chat(
32+
process.env.AI_ADVANCED_MODEL ?? "anthropic/claude-sonnet-4.5"
33+
),
34+
35+
/** Perplexity model for real-time web search and competitor analysis */
36+
perplexity: openrouter.chat("perplexity/sonar-pro"),
2837
} as const;
2938

3039
export type ModelKey = keyof typeof models;

apps/api/src/ai/prompts/analytics.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ const ANALYTICS_RULES = `<agent-specific-rules>
1818
**Tools Usage:**
1919
- Use get_top_pages for page analytics
2020
- Use execute_sql_query for custom analytics queries
21+
- Use competitor_analysis for real-time competitor insights, market trends, and industry analysis with citations
2122
- Use memory tools (search_memory, add_memory) to remember user preferences and past analysis patterns
2223
- CRITICAL: execute_sql_query must ONLY use SELECT/WITH and parameter placeholders (e.g., {limit:UInt32}) with values passed via params. websiteId is automatically included. Never interpolate strings.
2324
- Example: execute_sql_query({ websiteId: "<use website_id from context>", sql: "SELECT ... WHERE client_id = {websiteId:String}", params: { limit: 10 } })
25+
- Example competitor analysis: competitor_analysis({ query: "competitors to example.com in web analytics", context: "Our website tracks user behavior and performance metrics" })
2426
- Example memory: search_memory({ query: "user's preferred metrics" })
2527
2628
**Insights & Recommendations:**

apps/api/src/ai/prompts/triage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ databunny: End-to-end website analytics. Analyze traffic, visitors, page views,
1414
const ROUTING_RULES = `<routing-rules>
1515
- You are a single Databunny model. Never mention other experts or handoffs.
1616
- Always respond directly using the available tools.
17+
- For competitor analysis, use competitor_analysis tool for real-time market insights with citations.
1718
- Keep replies concise and action-oriented; avoid "I'll link you" phrasing.
1819
- Do not use emojis.
1920
</routing-rules>`;

apps/api/src/ai/tools/web-search.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import FirecrawlApp from "@mendable/firecrawl-js";
2-
import { tool } from "ai";
2+
import { generateText, tool } from "ai";
33
import { z } from "zod";
4+
import { models } from "../config/models";
45

56
/**
67
* Web search tool using Firecrawl for scraping and crawling websites.
@@ -28,3 +29,39 @@ export const webSearchTool = tool({
2829
return crawlResponse;
2930
},
3031
});
32+
33+
/**
34+
* Competitor analysis tool using Perplexity for real-time web search and analysis.
35+
* Provides grounded insights with citations about competitors and market trends.
36+
*/
37+
export const competitorAnalysisTool = tool({
38+
description:
39+
"Analyze competitors, market trends, and industry insights using real-time web search with citations",
40+
inputSchema: z.object({
41+
query: z
42+
.string()
43+
.min(1)
44+
.max(500)
45+
.describe(
46+
"The competitor analysis query (e.g., 'competitors to example.com in analytics space')"
47+
),
48+
context: z
49+
.string()
50+
.optional()
51+
.describe("Additional context about what you're analyzing"),
52+
}),
53+
execute: async ({ query, context }) => {
54+
const fullQuery = context ? `${query}. Context: ${context}` : query;
55+
56+
const result = await generateText({
57+
model: models.perplexity,
58+
prompt: fullQuery,
59+
});
60+
61+
return {
62+
analysis: result.text || "",
63+
sources: (result as any).sources || [],
64+
query: fullQuery,
65+
};
66+
},
67+
});

0 commit comments

Comments
 (0)