Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export function useDiscussReport({
has_branch: false,
cloud_run_source: "signal_report",
cloud_pr_authorship_mode: "user",
signal_report_id: reportId,
adapter,
});
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ async function trackTaskCreated(
: undefined,
cloud_pr_authorship_mode:
workspaceMode === "cloud" ? input.cloudPrAuthorshipMode : undefined,
signal_report_id: input.signalReportId,
uses_worktree_link: usesWorktreeLink,
uses_worktree_include: usesWorktreeInclude,
adapter: input.adapter,
Expand Down
5 changes: 4 additions & 1 deletion apps/code/src/renderer/stores/navigationStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ vi.mock("@renderer/trpc/client", () => ({
},
}));

vi.mock("@utils/analytics", () => ({ track: vi.fn() }));
vi.mock("@utils/analytics", () => ({
track: vi.fn(),
setActiveTaskAnalyticsContext: vi.fn(),
}));
Comment thread
andrewm4894 marked this conversation as resolved.
vi.mock("@utils/logger", () => ({
logger: { scope: () => ({ info: vi.fn(), error: vi.fn(), debug: vi.fn() }) },
}));
Expand Down
17 changes: 14 additions & 3 deletions apps/code/src/renderer/stores/navigationStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { workspaceApi } from "@features/workspace/hooks/useWorkspace";
import { getTaskDirectory } from "@hooks/useRepositoryDirectory";
import type { Task } from "@shared/types";
import { ANALYTICS_EVENTS } from "@shared/types/analytics";
import { track } from "@utils/analytics";
import { setActiveTaskAnalyticsContext, track } from "@utils/analytics";
import { electronStorage } from "@utils/electronStorage";
import { logger } from "@utils/logger";
import { getTaskRepository } from "@utils/repository";
Expand Down Expand Up @@ -132,6 +132,9 @@ export const useNavigationStore = create<NavigationStore>()(
history: newHistory,
historyIndex: newHistory.length - 1,
});
setActiveTaskAnalyticsContext(
newView.type === "task-detail" ? (newView.data ?? null) : null,
);
};

return {
Expand Down Expand Up @@ -306,21 +309,29 @@ export const useNavigationStore = create<NavigationStore>()(
const { history, historyIndex } = get();
if (historyIndex > 0) {
const newIndex = historyIndex - 1;
const newView = history[newIndex];
set({
view: history[newIndex],
view: newView,
historyIndex: newIndex,
});
setActiveTaskAnalyticsContext(
newView.type === "task-detail" ? (newView.data ?? null) : null,
);
}
},

goForward: () => {
const { history, historyIndex } = get();
if (historyIndex < history.length - 1) {
const newIndex = historyIndex + 1;
const newView = history[newIndex];
set({
view: history[newIndex],
view: newView,
historyIndex: newIndex,
});
setActiveTaskAnalyticsContext(
newView.type === "task-detail" ? (newView.data ?? null) : null,
);
}
},

Expand Down
1 change: 1 addition & 0 deletions apps/code/src/renderer/utils/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const mockPosthog = {
init: vi.fn(),
register: vi.fn(),
unregister: vi.fn(),
onFeatureFlags: vi.fn(),
isFeatureEnabled: vi.fn(),
startSessionRecording: vi.fn(),
Expand Down
24 changes: 24 additions & 0 deletions apps/code/src/renderer/utils/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import posthog from "posthog-js/dist/module.full.no-external";
// posthog-recorder (vs lazy-recorder) ensures recording is ready immediately
import "posthog-js/dist/posthog-recorder";
import type { PermissionRequest } from "@renderer/features/sessions/utils/parseSessionLogs";
import type { Task } from "@shared/types";
import type {
EventPropertyMap,
UserIdentifyProperties,
Expand Down Expand Up @@ -62,6 +63,9 @@ export function initializePostHog() {
},
});

// Clear stale task-scoped super-properties from the previous session.
posthog.unregister("signal_report_id");

isInitialized = true;

registerPersistentSuperProperties();
Expand Down Expand Up @@ -175,6 +179,26 @@ export function resetUser() {
registerPersistentSuperProperties();
}

/**
* Attach (or clear) task-scoped super-properties so every subsequent event
* carries the context of the currently active task. Pass `null` when no task
* is active (e.g. when navigating to a non-task view) to clear the context.
*
* Currently used to tag every event fired while the user is inside a task
* launched from an inbox report via the Discuss button.
*/
export function setActiveTaskAnalyticsContext(task: Task | null) {
Comment thread
andrewm4894 marked this conversation as resolved.
if (!isInitialized) {
return;
}
Comment thread
andrewm4894 marked this conversation as resolved.

if (task?.signal_report) {
posthog.register({ signal_report_id: task.signal_report });
Comment thread
andrewm4894 marked this conversation as resolved.
} else {
posthog.unregister("signal_report_id");
}
}
Comment thread
andrewm4894 marked this conversation as resolved.

export function track<K extends keyof EventPropertyMap>(
eventName: K,
...args: EventPropertyMap[K] extends never
Expand Down
1 change: 1 addition & 0 deletions apps/code/src/shared/types/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface TaskCreateProperties {
has_sandbox_environment?: boolean;
cloud_run_source?: "manual" | "signal_report";
cloud_pr_authorship_mode?: "user" | "bot";
signal_report_id?: string;
/** Worktree mode: repo has a non-empty .worktreelink file */
uses_worktree_link?: boolean;
/** Worktree mode: repo has a non-empty .worktreeinclude file */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ interface TestableServer {
configureEnvironment(args?: {
isInternal?: boolean;
originProduct?: string | null;
signalReportId?: string | null;
taskId?: string | null;
taskRunId?: string | null;
taskUserId?: number | null;
Expand Down Expand Up @@ -124,6 +125,7 @@ describe("AgentServer.configureEnvironment", () => {
buildServer("background").configureEnvironment({
isInternal: true,
originProduct: "signal_report",
signalReportId: "report-123",
taskId: "task-abc",
taskRunId: "run-xyz",
taskUserId: 42,
Expand All @@ -133,13 +135,25 @@ describe("AgentServer.configureEnvironment", () => {
[
"x-posthog-property-task_origin_product: signal_report",
"x-posthog-property-task_internal: true",
"x-posthog-property-signal_report_id: report-123",
"x-posthog-property-task_id: task-abc",
"x-posthog-property-task_run_id: run-xyz",
"x-posthog-property-task_user_id: 42",
].join("\n"),
);
});

it("omits signal_report_id from ANTHROPIC_CUSTOM_HEADERS for non-report tasks", () => {
buildServer("background").configureEnvironment({
isInternal: false,
taskId: "task-abc",
});

expect(process.env.ANTHROPIC_CUSTOM_HEADERS).not.toContain(
"signal_report_id",
);
});

it("omits optional task metadata from ANTHROPIC_CUSTOM_HEADERS when not provided", () => {
buildServer("background").configureEnvironment({ isInternal: false });

Expand Down
4 changes: 4 additions & 0 deletions packages/agent/src/server/agent-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ export class AgentServer {
this.configureEnvironment({
isInternal: preTask?.internal === true,
originProduct: preTask?.origin_product,
signalReportId: preTask?.signal_report,
taskId: payload.task_id,
taskRunId: payload.run_id,
taskUserId: payload.user_id,
Expand Down Expand Up @@ -1853,12 +1854,14 @@ ${signedCommitInstructions}
private configureEnvironment({
isInternal = false,
originProduct,
signalReportId,
taskId,
taskRunId,
taskUserId,
}: {
isInternal?: boolean;
originProduct?: string | null;
signalReportId?: string | null;
taskId?: string | null;
taskRunId?: string | null;
taskUserId?: number | null;
Expand All @@ -1877,6 +1880,7 @@ ${signedCommitInstructions}
const customHeaders = buildGatewayPropertyHeaders({
task_origin_product: originProduct,
task_internal: isInternal,
signal_report_id: signalReportId,
task_id: taskId,
task_run_id: taskRunId,
task_user_id: taskUserId,
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface Task {
| "support_queue"
| "session_summaries"
| "signal_report";
signal_report?: string | null; // Inbox report UUID when origin_product is "signal_report"
github_integration?: number | null;
repository: string; // Format: "organization/repository" (e.g., "posthog/posthog-js")
json_schema?: Record<string, unknown> | null; // JSON schema for task output validation
Expand Down
Loading