Add versioned telemetry events

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-03 07:32:54 -05:00
parent 2ac40aba56
commit 37b6ad42ea
16 changed files with 577 additions and 0 deletions

View file

@ -27,6 +27,7 @@ import {
readPaperclipSkillSyncPreference,
writePaperclipSkillSyncPreference,
} from "@paperclipai/adapter-utils/server-utils";
import { trackAgentCreated } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import {
agentService,
@ -62,6 +63,7 @@ import {
loadDefaultAgentInstructionsBundle,
resolveDefaultAgentInstructionsBundleRole,
} from "../services/default-agent-instructions.js";
import { getTelemetryClient } from "../telemetry.js";
export function agentRoutes(db: Db) {
const DEFAULT_INSTRUCTIONS_PATH_KEYS: Record<string, string> = {
@ -1387,6 +1389,10 @@ export function agentRoutes(db: Db) {
desiredSkills: desiredSkillAssignment.desiredSkills,
},
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
trackAgentCreated(telemetryClient, { agentRole: agent.role });
}
await applyDefaultAgentTaskAssignGrant(
companyId,
@ -1469,6 +1475,10 @@ export function agentRoutes(db: Db) {
desiredSkills: desiredSkillAssignment.desiredSkills,
},
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
trackAgentCreated(telemetryClient, { agentRole: agent.role });
}
await applyDefaultAgentTaskAssignGrant(
companyId,

View file

@ -6,10 +6,20 @@ import {
companySkillImportSchema,
companySkillProjectScanRequestSchema,
} from "@paperclipai/shared";
import { trackSkillImported } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { accessService, agentService, companySkillService, logActivity } from "../services/index.js";
import { forbidden } from "../errors.js";
import { assertCompanyAccess, getActorInfo } from "./authz.js";
import { getTelemetryClient } from "../telemetry.js";
type SkillTelemetryInput = {
key: string;
slug: string;
sourceType: string;
sourceLocator: string | null;
metadata: Record<string, unknown> | null;
};
export function companySkillRoutes(db: Db) {
const router = Router();
@ -22,6 +32,26 @@ export function companySkillRoutes(db: Db) {
return Boolean((agent.permissions as Record<string, unknown>).canCreateAgents);
}
function asString(value: unknown): string | null {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
function deriveTrackedSkillRef(skill: SkillTelemetryInput): string | null {
if (skill.sourceType === "skills_sh") {
return skill.key;
}
if (skill.sourceType !== "github") {
return null;
}
const hostname = asString(skill.metadata?.hostname) ?? "github.com";
if (hostname !== "github.com") {
return null;
}
return skill.key;
}
async function assertCanMutateCompanySkills(req: Request, companyId: string) {
assertCompanyAccess(req, companyId);
@ -183,6 +213,15 @@ export function companySkillRoutes(db: Db) {
warningCount: result.warnings.length,
},
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
for (const skill of result.imported) {
trackSkillImported(telemetryClient, {
sourceType: skill.sourceType,
skillRef: deriveTrackedSkillRef(skill),
});
}
}
res.status(201).json(result);
},

View file

@ -1,9 +1,11 @@
import { Router } from "express";
import type { Db } from "@paperclipai/db";
import { createGoalSchema, updateGoalSchema } from "@paperclipai/shared";
import { trackGoalCreated } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { goalService, logActivity } from "../services/index.js";
import { assertCompanyAccess, getActorInfo } from "./authz.js";
import { getTelemetryClient } from "../telemetry.js";
export function goalRoutes(db: Db) {
const router = Router();
@ -42,6 +44,10 @@ export function goalRoutes(db: Db) {
entityId: goal.id,
details: { title: goal.title },
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
trackGoalCreated(telemetryClient, { goalLevel: goal.level });
}
res.status(201).json(goal);
});

View file

@ -7,11 +7,13 @@ import {
updateProjectSchema,
updateProjectWorkspaceSchema,
} from "@paperclipai/shared";
import { trackProjectCreated } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { projectService, logActivity, workspaceOperationService } from "../services/index.js";
import { conflict } from "../errors.js";
import { assertCompanyAccess, getActorInfo } from "./authz.js";
import { startRuntimeServicesForWorkspaceControl, stopRuntimeServicesForProjectWorkspace } from "../services/workspace-runtime.js";
import { getTelemetryClient } from "../telemetry.js";
export function projectRoutes(db: Db) {
const router = Router();
@ -107,6 +109,10 @@ export function projectRoutes(db: Db) {
workspaceId: createdWorkspaceId,
},
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
trackProjectCreated(telemetryClient);
}
res.status(201).json(hydratedProject ?? project);
});

View file

@ -8,10 +8,12 @@ import {
updateRoutineSchema,
updateRoutineTriggerSchema,
} from "@paperclipai/shared";
import { trackRoutineCreated } from "@paperclipai/shared/telemetry";
import { validate } from "../middleware/validate.js";
import { accessService, logActivity, routineService } from "../services/index.js";
import { assertCompanyAccess, getActorInfo } from "./authz.js";
import { forbidden, unauthorized } from "../errors.js";
import { getTelemetryClient } from "../telemetry.js";
export function routineRoutes(db: Db) {
const router = Router();
@ -76,6 +78,10 @@ export function routineRoutes(db: Db) {
entityId: created.id,
details: { title: created.title, assigneeAgentId: created.assigneeAgentId },
});
const telemetryClient = getTelemetryClient();
if (telemetryClient) {
trackRoutineCreated(telemetryClient);
}
res.status(201).json(created);
});