diff --git a/backend/src/modules/agent-actions/routes.ts b/backend/src/modules/agent-actions/routes.ts index e235642..37aa619 100644 --- a/backend/src/modules/agent-actions/routes.ts +++ b/backend/src/modules/agent-actions/routes.ts @@ -20,6 +20,12 @@ import { type AgentActionDoc, } from './types.js'; import { PRODUCT_ID } from '../../lib/product-config.js'; +import { trackEvent } from '../../lib/telemetry.js'; +import { + AGENT_INBOX_ACTION_APPROVED, + AGENT_INBOX_ACTION_REJECTED, + AGENT_INBOX_BATCH_APPROVED, +} from '../../lib/telemetry-events.js'; export async function agentActionRoutes(app: FastifyInstance) { // ── Feature flag gate ───────────────────────────────────── @@ -78,6 +84,7 @@ export async function agentActionRoutes(app: FastifyInstance) { if (!updated) throw new NotFoundError('Agent action not found'); req.log.info({ actionId: id }, 'Approved agent action'); + trackEvent(AGENT_INBOX_ACTION_APPROVED, auth.sub, { actionId: id, actorId: updated.actorId, toolName: updated.toolName }); return updated; }); @@ -96,6 +103,7 @@ export async function agentActionRoutes(app: FastifyInstance) { if (!updated) throw new NotFoundError('Agent action not found'); req.log.info({ actionId: id }, 'Rejected agent action'); + trackEvent(AGENT_INBOX_ACTION_REJECTED, auth.sub, { actionId: id, actorId: updated.actorId, toolName: updated.toolName }); return updated; }); @@ -109,6 +117,7 @@ export async function agentActionRoutes(app: FastifyInstance) { const result = await repo.batchApproveByActor(auth.sub, PRODUCT_ID, parsed.data.actorId); req.log.info({ actorId: parsed.data.actorId, count: result.approved.length }, 'Batch approved agent actions'); + trackEvent(AGENT_INBOX_BATCH_APPROVED, auth.sub, { actorId: parsed.data.actorId, count: result.approved.length }); return result; }); } diff --git a/backend/src/server.ts b/backend/src/server.ts index 28d7262..4354a7c 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -20,9 +20,10 @@ import { config } from './lib/config.js'; import { getAllFlags, isFeatureEnabled } from './lib/feature-flags.js'; import { generateContextMessage, type ContextMessageInput } from './lib/ai-context.js'; import { z } from 'zod'; -import { getBufferedEvents, flushEvents } from './lib/telemetry.js'; +import { trackEvent, getBufferedEvents, flushEvents } from './lib/telemetry.js'; import { PRODUCT_ID, productConfig } from './lib/product-config.js'; import { initWebhookSubscriber, stopWebhookSubscriber } from './lib/webhook-subscriber.js'; +import { AI_CONTEXT_ENRICHED, AI_CONTEXT_FALLBACK_USED } from './lib/telemetry-events.js'; import { jwtVerify } from 'jose'; import type { JwtPayload } from './lib/request-context.js'; @@ -78,7 +79,13 @@ app.post('/api/context-message', async (req, reply) => { reply.code(400); return { message: 'Get ready!', source: 'generic' as const }; } - return generateContextMessage(parsed.data as ContextMessageInput); + const result = await generateContextMessage(parsed.data as ContextMessageInput); + if (result.source === 'llm') { + trackEvent(AI_CONTEXT_ENRICHED, undefined, { timerLabel: parsed.data.timerLabel }); + } else { + trackEvent(AI_CONTEXT_FALLBACK_USED, undefined, { timerLabel: parsed.data.timerLabel, source: result.source }); + } + return result; }); // ── Bootstrap (no auth) ──────────────────────────────────────────