Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
92d0cb3
feat: adopt evlog across services and remove shared pino logger
izadoesdev Mar 21, 2026
eb37e77
refactor(basket): drop OpenTelemetry and drain evlog wide events to A…
izadoesdev Mar 21, 2026
0a0c22a
refactor(api): drop OpenTelemetry and drain evlog wide events to Axiom
izadoesdev Mar 21, 2026
406e0aa
feat(basket): unify errors on evlog EvlogError and shared JSON
izadoesdev Mar 21, 2026
ce3ea48
feat(evlog): batched Axiom, sampling, enrichers, and dev FS drains
izadoesdev Mar 21, 2026
9de39ef
fix(rpc): align funnel analytics ORPC output with FunnelAnalytics shapes
izadoesdev Mar 21, 2026
72135e4
refactor(api,rpc): evlog-only RPC context and wider API logging
izadoesdev Mar 21, 2026
ffd8e15
refactor(api,rpc): consolidate auth context into single global wide e…
izadoesdev Mar 21, 2026
9951cf7
refactor(api): improve AI insights with prefetched data and generateT…
izadoesdev Mar 21, 2026
883a5d7
chore(api): use Claude Opus 4.6 for AI insights
izadoesdev Mar 21, 2026
738a695
feat(dashboard): link home Pulse card to monitors page
izadoesdev Mar 21, 2026
0730440
lint
izadoesdev Mar 21, 2026
99b50cd
Merge branch 'main' into staging
izadoesdev Mar 22, 2026
36e361f
feat: alarms, uptime email alerts on status transitions
izadoesdev Mar 22, 2026
34bd7d6
refactor(uptime): drop OpenTelemetry, align evlog with API/basket
izadoesdev Mar 22, 2026
e9cf85c
feat(uptime): merge error context into wide events via error_step
izadoesdev Mar 22, 2026
b329e88
feat(uptime): simplify JSON health extraction and add service health …
izadoesdev Mar 22, 2026
97c52a4
fix(health): split liveness /health and dependency /health/status acr…
izadoesdev Mar 22, 2026
695fd60
Add shared brand assets and Branding component for docs and dashboard
izadoesdev Mar 22, 2026
cbc9a7e
feat(docs): add brand asset context menu on logo right-click
izadoesdev Mar 23, 2026
3beaf2f
feat(docs): add branding page, custom fonts, and fix dark mode accent…
izadoesdev Mar 23, 2026
2b6c553
feat(dashboard): branding pass — LT Superior fonts, hex palette, char…
izadoesdev Mar 23, 2026
fa23fd9
fix(dashboard): update components to use brand colors and chart tokens
izadoesdev Mar 23, 2026
ad7cc8b
feat(docs,dashboard): install RealFaviconGenerator icons and web mani…
izadoesdev Mar 23, 2026
16caf5a
fix(dashboard): fix border colors, sidebar row heights, and sticky to…
izadoesdev Mar 23, 2026
afad2ae
fix(dashboard): improve button contrast, clean up sheet/dialog UI acr…
izadoesdev Mar 23, 2026
2010ac4
refactor(links): redesign link rows with favicons, inline copy, and t…
izadoesdev Mar 23, 2026
26f5778
feat(tracker): Navigation API SPA tracking, batch filter/sampling, E2…
izadoesdev Mar 23, 2026
2b352ac
fix(docs): unify SEO metadata, add FAQ + Article + TechArticle JSON-L…
izadoesdev Mar 23, 2026
3879ba3
feat(docs): use staging app demo iframe when docs run on preview.data…
izadoesdev Mar 23, 2026
45af898
feat(api): add tcc instrumentation (#362)
armans-code Mar 24, 2026
af366c2
fix: funnels output validation
izadoesdev Mar 24, 2026
6093a69
feat(funnels): analytics, link picker, and RPC funnel support
izadoesdev Mar 24, 2026
4ac1696
docs: replace early-access copy with GA-ready CTAs
izadoesdev Mar 24, 2026
e06c673
refactor(rpc): funnel errors via ClickHouse subqueries
izadoesdev Mar 24, 2026
bc82960
feat(ingest): dual-write ClickHouse via Vector replica sinks
izadoesdev Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 10 additions & 6 deletions .github/workflows/health-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,14 @@ jobs:
sleep 1
done

# Check health endpoint response structure
# Dependency probe (optional in CI — may 503 without Postgres/ClickHouse)
STATUS_BODY=$(curl -sS http://localhost:3001/health/status || echo '{}')
echo "API /health/status: $STATUS_BODY"

RESPONSE=$(curl -sf http://localhost:3001/health || echo '{}')
echo "API Health Response: $RESPONSE"
echo "API /health: $RESPONSE"

# Verify response has expected fields
# Verify simple liveness shape
if echo "$RESPONSE" | grep -q '"status"'; then
echo "API health endpoint structure is valid"
else
Expand Down Expand Up @@ -174,11 +177,12 @@ jobs:
sleep 1
done

# Check health endpoint response structure
STATUS_BODY=$(curl -sS http://localhost:4000/health/status || echo '{}')
echo "Basket /health/status: $STATUS_BODY"

RESPONSE=$(curl -sf http://localhost:4000/health || echo '{}')
echo "Basket Health Response: $RESPONSE"
echo "Basket /health: $RESPONSE"

# Verify response has expected fields
if echo "$RESPONSE" | grep -q '"status"'; then
echo "Basket health endpoint structure is valid"
else
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,9 @@ yarn-error.log*
*.tsbuildinfo
*.buildinfo
tmp

# Local evlog file-system drain (dev NDJSON under .evlog/logs)
**/.evlog/

# next-agents-md
.next-docs/
16 changes: 7 additions & 9 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"private": true,
"scripts": {
"dev": "dotenv -- bun --hot src/index.ts --port 3001",
"dev": "NODE_ENV=development dotenv -- bun --hot src/index.ts --port 3001",
"test": "bun test",
"test:watch": "bun test --watch"
},
Expand All @@ -19,6 +19,10 @@
"@ai-sdk/groq": "^3.0.15",
"@ai-sdk/openai": "^3.0.0",
"@ai-sdk/provider": "^3.0.5",
"@contextcompany/otel": "^1.0.13",
"@opentelemetry/resources": "^2.4.0",
"@opentelemetry/sdk-node": "^0.210.0",
"@opentelemetry/semantic-conventions": "^1.29.0",
"@databuddy/ai": "workspace:*",
"@databuddy/api-keys": "workspace:*",
"@databuddy/auth": "workspace:*",
Expand All @@ -31,14 +35,6 @@
"@elysiajs/cors": "^1.4.1",
"@json-render/core": "^0.2.0",
"@modelcontextprotocol/sdk": "^1.26.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.208.0",
"@opentelemetry/instrumentation-http": "^0.55.0",
"@opentelemetry/instrumentation-pg": "^0.48.0",
"@opentelemetry/resources": "^2.3.0",
"@opentelemetry/sdk-node": "^0.208.0",
"@opentelemetry/sdk-trace-node": "^2.3.0",
"@opentelemetry/semantic-conventions": "^1.38.0",
"@orpc/openapi": "^1.13.4",
"@orpc/server": "^1.13.4",
"@orpc/zod": "^1.13.4",
Expand All @@ -47,9 +43,11 @@
"bullmq": "^5.66.5",
"dayjs": "^1.11.19",
"elysia": "^1.4.22",
"evlog": "^2.8.0",
"jszip": "^3.10.1",
"keypal": "^0.1.11",
"resend": "^4.0.1",
"supermemory": "^4.17.0",
"svix": "^1.84.1",
"zod": "catalog:",
"zod-to-json-schema": "^3.25.1"
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/ai/agents/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getDataTool } from "../tools/get-data";
import { getTopPagesTool } from "../tools/get-top-pages";
import { createGoalTools } from "../tools/goals";
import { createLinksTools } from "../tools/links";
import { createMemoryTools } from "../tools/memory";
import { createProfileTools } from "../tools/profiles";
import { webSearchTool } from "../tools/web-search";
import type { AgentConfig, AgentContext } from "./types";
Expand All @@ -21,6 +22,7 @@ function createTools() {
execute_query_builder: executeQueryBuilderTool,
execute_sql_query: executeSqlQueryTool,
web_search: webSearchTool,
...createMemoryTools(),
...createProfileTools(),
...createFunnelTools(),
...createGoalTools(),
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/ai/agents/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function createMcpAgentConfig(
apiKey: unknown;
userId: string | null;
timezone?: string;
chatId?: string;
}
) {
const timezone = context.timezone ?? "UTC";
Expand All @@ -26,7 +27,7 @@ export function createMcpAgentConfig(
websiteDomain: "",
timezone,
currentDateTime: new Date().toISOString(),
chatId: crypto.randomUUID(),
chatId: context.chatId ?? crypto.randomUUID(),
requestHeaders: context.requestHeaders,
apiKey: context.apiKey,
};
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/ai/agents/reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { createFunnelTools } from "../tools/funnels";
import { getTopPagesTool } from "../tools/get-top-pages";
import { createGoalTools } from "../tools/goals";
import { createLinksTools } from "../tools/links";
import { createMemoryTools } from "../tools/memory";
import type { AgentConfig, AgentContext } from "./types";

function createTools() {
return {
get_top_pages: getTopPagesTool,
execute_query_builder: executeQueryBuilderTool,
execute_sql_query: executeSqlQueryTool,
...createMemoryTools(),
...createFunnelTools(),
...createGoalTools(),
...createAnnotationTools(),
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/ai/mcp/agent-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { createAnnotationTools } from "../tools/annotations";
import { createFunnelTools } from "../tools/funnels";
import { createGoalTools } from "../tools/goals";
import { createLinksTools } from "../tools/links";
import { createMemoryTools } from "../tools/memory";
import { createProfileTools } from "../tools/profiles";
import {
executeTimedQuery,
Expand Down Expand Up @@ -280,6 +281,7 @@ export function createMcpAgentTools() {
},
}),
web_search: webSearchTool,
...createMemoryTools(),
...createProfileTools(),
...createFunnelTools(),
...createGoalTools(),
Expand Down
77 changes: 69 additions & 8 deletions apps/api/src/ai/mcp/run-agent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ToolLoopAgent } from "ai";
import {
formatMemoryForPrompt,
getMemoryContext,
isMemoryEnabled,
storeConversation,
} from "../../lib/supermemory";
import { createMcpAgentConfig } from "../agents/mcp";
import { models } from "../config/models";

Expand All @@ -12,26 +18,69 @@ export interface RunMcpAgentOptions {
>;
userId: string | null;
timezone?: string;
conversationId?: string;
priorMessages?: Array<{ role: "user" | "assistant"; content: string }>;
}

export async function runMcpAgent(
options: RunMcpAgentOptions
): Promise<string> {
const config = createMcpAgentConfig(models.analyticsMcp, {
requestHeaders: options.requestHeaders,
apiKey: options.apiKey,
userId: options.userId,
timezone: options.timezone,
});
const sessionId = options.conversationId ?? crypto.randomUUID();

const apiKeyId =
options.apiKey &&
typeof options.apiKey === "object" &&
"id" in options.apiKey
? (options.apiKey as { id: string }).id
: null;

const [config, memoryCtx] = await Promise.all([
Promise.resolve(
createMcpAgentConfig(models.analyticsMcp, {
requestHeaders: options.requestHeaders,
apiKey: options.apiKey,
userId: options.userId,
timezone: options.timezone,
chatId: sessionId,
})
),
isMemoryEnabled()
? getMemoryContext(options.question, options.userId, apiKeyId)
: Promise.resolve(null),
]);

const memoryBlock = memoryCtx ? formatMemoryForPrompt(memoryCtx) : "";
const instructions = memoryBlock
? `${config.system}\n\n${memoryBlock}`
: config.system;

const mcpUserId = options.userId ?? options.apiKey?.userId;
const mcpTelemetryMetadata: Record<string, string> = {
source: "mcp",
authType: options.apiKey ? "api_key" : "session",
timezone: options.timezone ?? "UTC",
"tcc.conversational": "true",
};
if (mcpUserId) {
mcpTelemetryMetadata.userId = mcpUserId;
}
if (options.apiKey?.organizationId) {
mcpTelemetryMetadata.organizationId = options.apiKey.organizationId;
}
mcpTelemetryMetadata["tcc.sessionId"] = sessionId;

const agent = new ToolLoopAgent({
model: config.model,
instructions: config.system,
instructions,
tools: config.tools,
stopWhen: config.stopWhen,
temperature: config.temperature,
experimental_context: config.experimental_context,
experimental_telemetry: {
isEnabled: true,
functionId: "databuddy.mcp.ask",
metadata: mcpTelemetryMetadata,
},
});

const messages =
Expand All @@ -54,7 +103,19 @@ export async function runMcpAgent(
abortSignal: abortController.signal,
});

return result.text ?? "No response generated.";
const answer = result.text ?? "No response generated.";

storeConversation(
[
{ role: "user", content: options.question },
{ role: "assistant", content: answer },
],
options.userId,
apiKeyId,
{ source: "mcp" }
);

return answer;
} finally {
clearTimeout(timeout);
}
Expand Down
Loading
Loading