diff --git a/apps/code/snapshots.yml b/apps/code/snapshots.yml index 94a33aa7ea..4aa05de400 100644 --- a/apps/code/snapshots.yml +++ b/apps/code/snapshots.yml @@ -672,34 +672,6 @@ snapshots: hash: v1.k4693efd2.e01a8a548c694761b9f2a575268f420f653ad7eb9d26c2e33dc245ab03415fcf.Z5Ut_gF62xXnxkDgBXxE3yk6UDIAEVX5Sw_rKBPsqps settings-personalizationsettings--synced-truncated--light: hash: v1.k4693efd2.3c9f0dfa759b8c174abd8754593f0db9fd1518ff5225cccdcf0c3e83d4cdbe77.BqdmyuIiYJuGmHCQiRVAaBMk-xgycYOgVfwuMqma4LY - skill-buttons-skillbuttonactionmessage--add-analytics--dark: - hash: v1.k4693efd2.6d4ce4fac8e23a50efbbfaf24c2e11f8981f6778af2bfb2ca559749d7bda0eca.OnypKY5jyJSbQUZtTVcUy-eXC2euU-xQ2wFBYJOsKwI - skill-buttons-skillbuttonactionmessage--add-analytics--light: - hash: v1.k4693efd2.f9611d356ec29fdbeaa559fd1fad74ef5240edf099ca6b0c98bb000c8ecebb99.kLrb06q55BNiaXt5IiOa5GMJnSBLEE2XpPlzFclgkyc - skill-buttons-skillbuttonactionmessage--add-error-tracking--dark: - hash: v1.k4693efd2.4d3fb8903585f88035fe7f11bd131fb5469b1bcfa56e850fc872a90965b9a9a8.8wlRUb95tyzSof7imJ7zs_y03dvbRmH4WFjX541w5HE - skill-buttons-skillbuttonactionmessage--add-error-tracking--light: - hash: v1.k4693efd2.cfebda50da261d92f05d65771b89733969966491eae709a7ad0985af7d92b2af.cJib8NTQeUDwiCFGyKZZrzOkYB6wZpzj2lQTKoCoX2M - skill-buttons-skillbuttonactionmessage--add-logging--dark: - hash: v1.k4693efd2.0683c4cb4d3758ccfb3070a73e3f388624949cf359ff5e236e7f644bf8149ebd.nbHO3MGaY0eezUGvbSffJ2mWnwYGcv_Ls5Ftd7TamFc - skill-buttons-skillbuttonactionmessage--add-logging--light: - hash: v1.k4693efd2.089572e8d90c2ce17d03eb0d1f4028f28b0b106c262ffb5aa176efc67aac6961.aE-7mciin1bJeXhS3NO9MIdbA7p1V2yv7I9_av5qiuk - skill-buttons-skillbuttonactionmessage--create-feature-flag--dark: - hash: v1.k4693efd2.9e76cce0670827af38126d82091a1ddbff6fa46851eb5282307562828f33fffe.dLGLJgQ0h7Qbea4TkB_10bM1S7YhP7MtLWly5a8w8pI - skill-buttons-skillbuttonactionmessage--create-feature-flag--light: - hash: v1.k4693efd2.1816aed1a5153e40d66db8ded2823492fb2c6a2119e9dafc2e3e28b78efc0cd3.pWhUy7sCTfgQ-9SOY7Otzb21YPkdPalRmF1LpFaCE7o - skill-buttons-skillbuttonactionmessage--instrument-llm-calls--dark: - hash: v1.k4693efd2.45cd285f3dde88ec3a42d6124267f8b4927d6241ec5e6a32531d6c4d25f62fe4.6KVWQAustG4YSrWUwC8fT6PTTf8s6cRLqOicWuSD61g - skill-buttons-skillbuttonactionmessage--instrument-llm-calls--light: - hash: v1.k4693efd2.7c401e13f085e5fda6fe8b175bea7aba836e35d72ace33fa425893ad703ba874.uKLTlUu1eQrQQ_AroVKlbzvm7W10tJ1O_RqyxSg1aTQ - skill-buttons-skillbuttonactionmessage--run-experiment--dark: - hash: v1.k4693efd2.e747a3b5d0983a7a125335f1d95cc7735dafda73abdb3f63ccfadde0482c5ce9.tjc4lMKeaOJjLLxd9tivmgKLshzHZwuSAa_MbqwN_20 - skill-buttons-skillbuttonactionmessage--run-experiment--light: - hash: v1.k4693efd2.c18264887c67224ea1196646ff27f31ef9d79add87b5e9dfead377fcaf0dc941.MwzR7Yyd4le31Qm7RB2yk-qLk5ujgLkN-cMAB2WQ9_k - skill-buttons-skillbuttonsmenu--default--dark: - hash: v1.k4693efd2.cfff4c6bbb0acef1c9941b21d2f69c24b234c2c206282acf6fcada0cb2bd2386.xILjVPp8ecQmGbPjGDdhbRyi9KFPpA_1nfYF3bfjwuc - skill-buttons-skillbuttonsmenu--default--light: - hash: v1.k4693efd2.eb9bd49b9700641f6f3c90653447c9767c52e997afec9843e8649b90752faad3.VdxEtBwtkU3ioy2evcNbrEKxPjQ1GDUpZAQzFe-Uho4 spaces-taskfeedrow--agent-origin--dark: hash: v1.k4693efd2.82f8c70a399c9ea768201933e202fcc2fde74332c5153aeabf6835ace79beee6.yEZq_qnKxItv5u0Ydcqa1B4VCwv8lwXUvcaFScE2XO0 spaces-taskfeedrow--agent-origin--light: diff --git a/packages/core/src/sessions/sessionService.ts b/packages/core/src/sessions/sessionService.ts index cd001a33e5..0583cfc52c 100644 --- a/packages/core/src/sessions/sessionService.ts +++ b/packages/core/src/sessions/sessionService.ts @@ -293,7 +293,6 @@ export interface ISessionStore { } export interface SessionServiceHelpers { - extractSkillButtonId: (...args: any[]) => any; combineQueuedCloudPrompts: (...args: any[]) => any; getCloudPromptTransport: (...args: any[]) => any; resolveLocalSkillCommandPrompt?: (prompt: string) => Promise; @@ -3555,7 +3554,7 @@ export class SessionService { }); // Show the user's message in the chat immediately, before any respawn - this.applyOptimisticPrompt(session.taskRunId, blocks, promptText); + this.applyOptimisticPrompt(session.taskRunId, promptText); if (promptReferencesAbsoluteFolder(prompt)) { const repoPath = this.localRepoPaths.get(taskId); @@ -3681,30 +3680,18 @@ export class SessionService { } } - private applyOptimisticPrompt( - taskRunId: string, - blocks: ContentBlock[], - promptText: string, - ): void { + private applyOptimisticPrompt(taskRunId: string, promptText: string): void { this.d.store.updateSession(taskRunId, { isPromptPending: true, promptStartedAt: Date.now(), pausedDurationMs: 0, }); - const skillButtonId = this.d.h.extractSkillButtonId(blocks); - if (skillButtonId) { - this.d.store.appendOptimisticItem(taskRunId, { - type: "skill_button_action", - buttonId: skillButtonId, - }); - } else { - this.d.store.appendOptimisticItem(taskRunId, { - type: "user_message", - content: promptText, - timestamp: Date.now(), - }); - } + this.d.store.appendOptimisticItem(taskRunId, { + type: "user_message", + content: promptText, + timestamp: Date.now(), + }); } private async sendLocalPrompt( @@ -3714,7 +3701,7 @@ export class SessionService { options: { optimisticApplied?: boolean; isRecoveryResend?: boolean } = {}, ): Promise<{ stopReason: string }> { if (!options.optimisticApplied) { - this.applyOptimisticPrompt(session.taskRunId, blocks, promptText); + this.applyOptimisticPrompt(session.taskRunId, promptText); } try { diff --git a/packages/core/src/sessions/sessionServicePromptRecovery.test.ts b/packages/core/src/sessions/sessionServicePromptRecovery.test.ts index 927dbe61df..6a0e0253ca 100644 --- a/packages/core/src/sessions/sessionServicePromptRecovery.test.ts +++ b/packages/core/src/sessions/sessionServicePromptRecovery.test.ts @@ -46,7 +46,7 @@ function createHarness() { const usageLimitShow = vi.fn(); const deps = { store, - h: { extractSkillButtonId: () => undefined }, + h: {}, log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }, toast: { error: vi.fn(), info: vi.fn() }, track: vi.fn(), diff --git a/packages/core/src/setup/buildDiscoveredTaskPrompt.ts b/packages/core/src/setup/buildDiscoveredTaskPrompt.ts index 8f00cd592b..89c6939e20 100644 --- a/packages/core/src/setup/buildDiscoveredTaskPrompt.ts +++ b/packages/core/src/setup/buildDiscoveredTaskPrompt.ts @@ -1,9 +1,11 @@ import type { DiscoveredTask } from "@posthog/core/setup/types"; -import { SKILL_BUTTON_CATALOG } from "@posthog/core/skill-buttons/catalog"; + +const EXPERIMENT_TASK_PROMPT = + "Set up a PostHog experiment for the feature in this task. Use the PostHog MCP to create the feature flag with control and test variants, then create the experiment in draft with a clear hypothesis and primary metric tied to the feature's success. Wire the variant into the code via posthog.getFeatureFlag. Only launch the experiment if the feature is already live in production — otherwise leave it in draft and tell me to launch it after this is merged and deployed."; function buildExperimentTaskPrompt(task: DiscoveredTask): string { const sections: string[] = [ - SKILL_BUTTON_CATALOG["run-experiment"].prompt, + EXPERIMENT_TASK_PROMPT, "", "Use the analysis below as the starting point.", "", diff --git a/packages/core/src/skill-buttons/catalog.ts b/packages/core/src/skill-buttons/catalog.ts deleted file mode 100644 index 9079077a02..0000000000 --- a/packages/core/src/skill-buttons/catalog.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { SkillButtonId } from "@posthog/shared/analytics-events"; - -export type { SkillButtonId }; - -export interface SkillButtonCatalogEntry { - id: SkillButtonId; - label: string; - prompt: string; - color: string; - actionTitle: string; - actionDescription: string; - tooltip: string; -} - -export const SKILL_BUTTON_CATALOG: Record< - SkillButtonId, - SkillButtonCatalogEntry -> = { - "add-analytics": { - id: "add-analytics", - label: "Track events", - prompt: "/instrument-product-analytics", - color: "#2F80FA", - actionTitle: "Adding analytics", - actionDescription: "to measure how this change performs in production.", - tooltip: - "Instrument PostHog events so you can measure this change in production", - }, - "create-feature-flags": { - id: "create-feature-flags", - label: "Add feature flag", - prompt: "/instrument-feature-flags", - color: "#30ABC6", - actionTitle: "Creating a feature flag", - actionDescription: - "to roll this out safely and toggle it without a redeploy.", - tooltip: - "Gate this change behind a PostHog feature flag for a safe rollout", - }, - "run-experiment": { - id: "run-experiment", - label: "Run experiment", - prompt: - "Set up a PostHog experiment for the feature in this task. Use the PostHog MCP to create the feature flag with control and test variants, then create the experiment in draft with a clear hypothesis and primary metric tied to the feature's success. Wire the variant into the code via posthog.getFeatureFlag. Only launch the experiment if the feature is already live in production — otherwise leave it in draft and tell me to launch it after this is merged and deployed.", - color: "#B62AD9", - actionTitle: "Setting up an experiment", - actionDescription: - "with control and test variants tied to a primary metric, ready to launch once this ships.", - tooltip: - "Scaffold a PostHog A/B experiment with control and test variants tied to a primary metric", - }, - "add-error-tracking": { - id: "add-error-tracking", - label: "Track errors", - prompt: "/instrument-error-tracking", - color: "#BF8113", - actionTitle: "Adding error tracking", - actionDescription: - "so exceptions surface in PostHog with stack traces and source maps.", - tooltip: - "Capture exceptions in PostHog with stack traces so issues surface quickly in production", - }, - "instrument-llm-calls": { - id: "instrument-llm-calls", - label: "Trace LLM calls", - prompt: "/instrument-llm-analytics", - color: "#B029D2", - actionTitle: "Instrumenting LLM calls", - actionDescription: - "for visibility into prompts, tokens, latency, and costs.", - tooltip: - "Inspect traces, spans, latency, usage, and per-user costs for AI-powered features", - }, - "add-logging": { - id: "add-logging", - label: "Capture logs", - prompt: "/instrument-logs", - color: "#C92474", - actionTitle: "Adding logging", - actionDescription: - "so structured log events flow into PostHog for inspection and debugging.", - tooltip: - "Capture structured application logs in PostHog for inspection and debugging", - }, -}; - -export const SKILL_BUTTON_ORDER: SkillButtonId[] = [ - "add-analytics", - "add-logging", - "add-error-tracking", - "instrument-llm-calls", - "create-feature-flags", - "run-experiment", -]; - -export const SKILL_BUTTON_IDS: ReadonlySet = new Set( - Object.keys(SKILL_BUTTON_CATALOG) as SkillButtonId[], -); - -export function isSkillButtonId(value: unknown): value is SkillButtonId { - return ( - typeof value === "string" && SKILL_BUTTON_IDS.has(value as SkillButtonId) - ); -} diff --git a/packages/core/src/skill-buttons/prompts.test.ts b/packages/core/src/skill-buttons/prompts.test.ts deleted file mode 100644 index 63b5dff366..0000000000 --- a/packages/core/src/skill-buttons/prompts.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { ContentBlock } from "@agentclientprotocol/sdk"; -import { describe, expect, it } from "vitest"; -import { SKILL_BUTTON_CATALOG } from "./catalog"; -import { buildSkillButtonPromptBlocks, extractSkillButtonId } from "./prompts"; - -describe("buildSkillButtonPromptBlocks", () => { - it("produces a text block carrying the button id under posthogCode meta", () => { - const [block] = buildSkillButtonPromptBlocks("add-analytics"); - expect(block.type).toBe("text"); - expect((block as { text: string }).text).toBe( - SKILL_BUTTON_CATALOG["add-analytics"].prompt, - ); - expect((block as { _meta?: unknown })._meta).toEqual({ - posthogCode: { skillButtonId: "add-analytics" }, - }); - }); -}); - -describe("extractSkillButtonId", () => { - it("round-trips through buildSkillButtonPromptBlocks", () => { - for (const id of Object.keys(SKILL_BUTTON_CATALOG)) { - const blocks = buildSkillButtonPromptBlocks( - id as keyof typeof SKILL_BUTTON_CATALOG, - ); - expect(extractSkillButtonId(blocks)).toBe(id); - } - }); - - it("returns null for blocks with no meta", () => { - const blocks: ContentBlock[] = [{ type: "text", text: "hello" }]; - expect(extractSkillButtonId(blocks)).toBeNull(); - }); - - it("returns null when meta carries an unknown id", () => { - const blocks: ContentBlock[] = [ - { - type: "text", - text: "hi", - _meta: { posthogCode: { skillButtonId: "unknown" } }, - }, - ]; - expect(extractSkillButtonId(blocks)).toBeNull(); - }); - - it("ignores plain text that happens to match a prompt string", () => { - const blocks: ContentBlock[] = [ - { type: "text", text: SKILL_BUTTON_CATALOG["add-analytics"].prompt }, - ]; - expect(extractSkillButtonId(blocks)).toBeNull(); - }); - - it("handles undefined blocks", () => { - expect(extractSkillButtonId(undefined)).toBeNull(); - expect(extractSkillButtonId([])).toBeNull(); - }); -}); diff --git a/packages/core/src/skill-buttons/prompts.ts b/packages/core/src/skill-buttons/prompts.ts deleted file mode 100644 index ded135a0ad..0000000000 --- a/packages/core/src/skill-buttons/prompts.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { ContentBlock } from "@agentclientprotocol/sdk"; -import { - isSkillButtonId, - SKILL_BUTTON_CATALOG, - type SkillButtonId, -} from "./catalog"; - -export const SKILL_BUTTON_META_NAMESPACE = "posthogCode"; -export const SKILL_BUTTON_META_FIELD = "skillButtonId"; - -export function buildSkillButtonPromptBlocks( - buttonId: SkillButtonId, -): ContentBlock[] { - return [ - { - type: "text", - text: SKILL_BUTTON_CATALOG[buttonId].prompt, - _meta: { - [SKILL_BUTTON_META_NAMESPACE]: { - [SKILL_BUTTON_META_FIELD]: buttonId, - }, - }, - }, - ]; -} - -export function extractSkillButtonId( - blocks: ContentBlock[] | undefined, -): SkillButtonId | null { - if (!blocks?.length) return null; - for (const block of blocks) { - const meta = (block as { _meta?: Record })._meta; - const namespace = meta?.[SKILL_BUTTON_META_NAMESPACE] as - | Record - | undefined; - const id = namespace?.[SKILL_BUTTON_META_FIELD]; - if (isSkillButtonId(id)) { - return id; - } - } - return null; -} diff --git a/packages/shared/src/analytics-events.ts b/packages/shared/src/analytics-events.ts index 2da7a31ed6..402fd46c0d 100644 --- a/packages/shared/src/analytics-events.ts +++ b/packages/shared/src/analytics-events.ts @@ -34,14 +34,6 @@ export type FeedbackType = "good" | "bad" | "general"; type FileOpenSource = "sidebar" | "agent-suggestion" | "search" | "diff"; export type FileChangeType = "added" | "modified" | "deleted"; type StopReason = "user_cancelled" | "completed" | "error" | "timeout"; -export type SkillButtonId = - | "add-analytics" - | "create-feature-flags" - | "run-experiment" - | "add-error-tracking" - | "instrument-llm-calls" - | "add-logging"; -type SkillButtonSource = "primary" | "dropdown"; export type CommandMenuAction = | "home" | "new-task" @@ -288,12 +280,6 @@ export interface BrainrotActivatedProperties { filled_cells: number; } -export interface SkillButtonTriggeredProperties { - task_id: string; - button_id: SkillButtonId; - source: SkillButtonSource; -} - // Settings events export interface SettingChangedProperties { setting_name: string; @@ -1272,7 +1258,6 @@ export const ANALYTICS_EVENTS = { COMMAND_MENU_ACTION: "Command menu action", COMMAND_CENTER_VIEWED: "Command center viewed", BRAINROT_ACTIVATED: "Brainrot activated", - SKILL_BUTTON_TRIGGERED: "Skill button triggered", POSTHOG_WEB_OPENED: "PostHog web opened", SIDEBAR_NAV_ITEM_CLICKED: "Sidebar nav item clicked", SIDEBAR_CUSTOMIZED: "Sidebar customized", @@ -1449,7 +1434,6 @@ export type EventPropertyMap = { [ANALYTICS_EVENTS.COMMAND_MENU_ACTION]: CommandMenuActionProperties; [ANALYTICS_EVENTS.COMMAND_CENTER_VIEWED]: never; [ANALYTICS_EVENTS.BRAINROT_ACTIVATED]: BrainrotActivatedProperties; - [ANALYTICS_EVENTS.SKILL_BUTTON_TRIGGERED]: SkillButtonTriggeredProperties; [ANALYTICS_EVENTS.POSTHOG_WEB_OPENED]: never; [ANALYTICS_EVENTS.SIDEBAR_NAV_ITEM_CLICKED]: SidebarNavItemClickedProperties; [ANALYTICS_EVENTS.SIDEBAR_CUSTOMIZED]: SidebarCustomizedProperties; diff --git a/packages/shared/src/sessions.ts b/packages/shared/src/sessions.ts index 181ff36c20..81a2bc1cb3 100644 --- a/packages/shared/src/sessions.ts +++ b/packages/shared/src/sessions.ts @@ -7,7 +7,6 @@ import type { SessionConfigSelectOptions, } from "@agentclientprotocol/sdk"; import type { Adapter } from "./adapter"; -import type { SkillButtonId } from "./analytics-events"; import type { TaskRunArtifact, TaskRunStatus } from "./domain-types"; import type { ExecutionMode } from "./exec-types"; import type { AcpMessage } from "./session-events"; @@ -26,19 +25,13 @@ export interface QueuedMessage { queuedAt: number; } -export type OptimisticItem = - | { - type: "user_message"; - id: string; - content: string; - timestamp: number; - pinToTop?: boolean; - } - | { - type: "skill_button_action"; - id: string; - buttonId: SkillButtonId; - }; +export type OptimisticItem = { + type: "user_message"; + id: string; + content: string; + timestamp: number; + pinToTop?: boolean; +}; export type SessionStatus = | "connecting" diff --git a/packages/ui/src/features/sessions/components/ConversationView.tsx b/packages/ui/src/features/sessions/components/ConversationView.tsx index 6adcfcf522..cfef7ad0a6 100644 --- a/packages/ui/src/features/sessions/components/ConversationView.tsx +++ b/packages/ui/src/features/sessions/components/ConversationView.tsx @@ -67,7 +67,6 @@ import { import { useThreadScrollRequest } from "@posthog/ui/features/sessions/threadNavigationStore"; import { SessionTaskIdProvider } from "@posthog/ui/features/sessions/useSessionTaskId"; import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore"; -import { SkillButtonActionMessage } from "@posthog/ui/features/skill-buttons/components/SkillButtonActionMessage"; import { DIFF_WORKER_FACTORY, type DiffWorkerFactory, @@ -402,8 +401,6 @@ export function ConversationView({ ); case "git_action": return ; - case "skill_button_action": - return ; case "session_update": return ( { ]); }); + it("renders legacy skill-button prompts as ordinary user messages", () => { + const events: AcpMessage[] = [ + { + type: "acp_message", + ts: 1, + message: { + jsonrpc: "2.0", + id: 1, + method: "session/prompt", + params: { + prompt: [ + { + type: "text", + text: "/instrument-product-analytics", + _meta: { + posthogCode: { + skillButtonId: "add-analytics", + }, + }, + }, + ], + }, + }, + }, + ]; + + const result = buildConversationItems(events, null); + + expect(result.items).toEqual([ + { + type: "user_message", + id: "turn-1-1-user", + content: "/instrument-product-analytics", + timestamp: 1, + attachments: [], + }, + ]); + }); + it("clears the compacting spinner on a successful completion status, without duplicating the row", () => { // A successful compaction sends a terminal `status: compacting, isComplete: // true`. It must flip the existing status row, not append a second one. diff --git a/packages/ui/src/features/sessions/components/buildConversationItems.ts b/packages/ui/src/features/sessions/components/buildConversationItems.ts index 44042029b4..bed913e3aa 100644 --- a/packages/ui/src/features/sessions/components/buildConversationItems.ts +++ b/packages/ui/src/features/sessions/components/buildConversationItems.ts @@ -27,10 +27,6 @@ import type { ToolCall, } from "@posthog/ui/features/sessions/types"; import type { UserMessageAttachment } from "@posthog/ui/features/sessions/userMessageTypes"; -import { - extractSkillButtonId, - type SkillButtonId, -} from "@posthog/ui/features/skill-buttons/prompts"; import type { Step, StepStatus } from "@posthog/ui/primitives/StepList"; import type { RenderItem } from "./session-update/SessionUpdateView"; @@ -51,7 +47,6 @@ export type ConversationItem = pinToTop?: boolean; } | { type: "git_action"; id: string; actionType: GitActionType } - | { type: "skill_button_action"; id: string; buttonId: SkillButtonId } | { type: "session_update"; id: string; @@ -474,7 +469,6 @@ function handlePromptRequest( const turnId = `turn-${ts}-${msg.id}`; const toolCalls = new Map(); const gitAction = parseGitActionMessage(userContent); - const skillButtonId = extractSkillButtonId(userPrompt.blocks); const childItems = new Map(); const context: TurnContext = { @@ -531,12 +525,6 @@ function handlePromptRequest( id: `${turnId}-git-action`, actionType: gitAction.actionType, }); - } else if (skillButtonId) { - b.items.splice(insertIndex, 0, { - type: "skill_button_action", - id: `${turnId}-skill-action`, - buttonId: skillButtonId, - }); } else { b.items.splice(insertIndex, 0, { type: "user_message", diff --git a/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx b/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx index dbacd99334..764e7fd251 100644 --- a/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx +++ b/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx @@ -116,7 +116,6 @@ import { useSessionTaskId, } from "@posthog/ui/features/sessions/useSessionTaskId"; import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore"; -import { SkillButtonActionMessage } from "@posthog/ui/features/skill-buttons/components/SkillButtonActionMessage"; import { toast } from "@posthog/ui/primitives/toast"; import { useCopy } from "@posthog/ui/primitives/useCopy"; import { @@ -233,10 +232,9 @@ function groupIntoTurns(rows: ThreadItem[]): TurnRow[] { } }; for (const row of rows) { - // git_action and skill_button_action stand in for the user's message when the prompt was a - // git operation or a skill button click (see handlePromptRequest) — they open a turn just - // like a user message, so they break the agent card too rather than render inside it as if - // they were agent output. Same boundary set as the legacy view's buildThreadGroups. + // git_action stands in for the user's message when the prompt was a git + // operation, so it opens a turn and breaks the agent card rather than + // rendering inside it as if it were agent output. if (isUserInitiatedConversationItem(row)) { flush(); out.push(row); @@ -1177,8 +1175,6 @@ function ChatThreadRenderer({ return null; case "git_action": return ; - case "skill_button_action": - return ; case "session_update": { const update = item.update; // Assistant prose → start-aligned ghost bubble. Everything else (tool calls, thoughts, diff --git a/packages/ui/src/features/sessions/components/groupConversationTurns.test.ts b/packages/ui/src/features/sessions/components/groupConversationTurns.test.ts index 2ffba91891..af59a3a966 100644 --- a/packages/ui/src/features/sessions/components/groupConversationTurns.test.ts +++ b/packages/ui/src/features/sessions/components/groupConversationTurns.test.ts @@ -15,11 +15,8 @@ function cancelled(id: string): ConversationItem { return { type: "turn_cancelled", id } as ConversationItem; } -function userAction( - id: string, - type: "git_action" | "skill_button_action", -): ConversationItem { - return { type, id } as ConversationItem; +function gitAction(id: string): ConversationItem { + return { type: "git_action", id, actionType: "commit-push" }; } describe("groupRowsIntoTurns", () => { @@ -49,22 +46,19 @@ describe("groupRowsIntoTurns", () => { expect(result.rowToTurnIndex).toEqual([0, 0, 1]); }); - it.each(["git_action", "skill_button_action"] as const)( - "starts a turn for %s", - (type) => { - const result = groupRowsIntoTurns([ - row(userMessage("user-1")), - row(cancelled("reply-1")), - row(userAction("action-1", type)), - row(cancelled("reply-2")), - ]); + it("starts a turn for a git action", () => { + const result = groupRowsIntoTurns([ + row(userMessage("user-1")), + row(cancelled("reply-1")), + row(gitAction("action-1")), + row(cancelled("reply-2")), + ]); - expect( - result.turns.map((turn) => turn.rows.map((item) => item.id)), - ).toEqual([ - ["user-1", "reply-1"], - ["action-1", "reply-2"], - ]); - }, - ); + expect( + result.turns.map((turn) => turn.rows.map((item) => item.id)), + ).toEqual([ + ["user-1", "reply-1"], + ["action-1", "reply-2"], + ]); + }); }); diff --git a/packages/ui/src/features/sessions/components/isUserInitiatedConversationItem.ts b/packages/ui/src/features/sessions/components/isUserInitiatedConversationItem.ts index cf4a7d9ae8..833ba547aa 100644 --- a/packages/ui/src/features/sessions/components/isUserInitiatedConversationItem.ts +++ b/packages/ui/src/features/sessions/components/isUserInitiatedConversationItem.ts @@ -1,9 +1,5 @@ export function isUserInitiatedConversationItem(item: { type: string; }): boolean { - return ( - item.type === "user_message" || - item.type === "git_action" || - item.type === "skill_button_action" - ); + return item.type === "user_message" || item.type === "git_action"; } diff --git a/packages/ui/src/features/sessions/sessionServiceHost.ts b/packages/ui/src/features/sessions/sessionServiceHost.ts index 9811a82430..7fb33979e2 100644 --- a/packages/ui/src/features/sessions/sessionServiceHost.ts +++ b/packages/ui/src/features/sessions/sessionServiceHost.ts @@ -9,7 +9,6 @@ import { SessionService, type SessionServiceDeps, } from "@posthog/core/sessions/sessionService"; -import { extractSkillButtonId } from "@posthog/core/skill-buttons/prompts"; import { resolveService } from "@posthog/di/container"; import { HOST_TRPC_CLIENT, @@ -152,7 +151,6 @@ function buildSessionServiceDeps(): SessionServiceDeps { DEFAULT_GATEWAY_MODEL, WORKSPACE_QUERY_KEY, h: { - extractSkillButtonId, combineQueuedCloudPrompts, getCloudPromptTransport, resolveLocalSkillCommandPrompt: (prompt) => diff --git a/packages/ui/src/features/sessions/utils/extractSearchableText.test.ts b/packages/ui/src/features/sessions/utils/extractSearchableText.test.ts index 18d7a5a71c..83e0982fee 100644 --- a/packages/ui/src/features/sessions/utils/extractSearchableText.test.ts +++ b/packages/ui/src/features/sessions/utils/extractSearchableText.test.ts @@ -205,7 +205,7 @@ describe("extractSearchableText", () => { expect(extractSearchableText(item)).toBe("moving_to_worktree"); }); - it.each(["git_action", "skill_button_action", "git_action_result"] as const)( + it.each(["git_action", "git_action_result"] as const)( "returns empty string for %s items", (type) => { const item = { diff --git a/packages/ui/src/features/sessions/utils/extractSearchableText.ts b/packages/ui/src/features/sessions/utils/extractSearchableText.ts index 78ba59cadb..4871e2e558 100644 --- a/packages/ui/src/features/sessions/utils/extractSearchableText.ts +++ b/packages/ui/src/features/sessions/utils/extractSearchableText.ts @@ -41,7 +41,6 @@ export function extractSearchableText(item: ConversationItem): string { case "turn_cancelled": return item.interruptReason ?? "Interrupted by user"; case "git_action": - case "skill_button_action": case "git_action_result": return ""; } diff --git a/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.stories.tsx b/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.stories.tsx deleted file mode 100644 index 7890bb842c..0000000000 --- a/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.stories.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { SkillButtonActionMessage } from "@posthog/ui/features/skill-buttons/components/SkillButtonActionMessage"; -import type { Meta, StoryObj } from "@storybook/react-vite"; - -const meta: Meta = { - title: "Skill Buttons/SkillButtonActionMessage", - component: SkillButtonActionMessage, - parameters: { - layout: "centered", - }, -}; - -export default meta; -type Story = StoryObj; - -export const AddAnalytics: Story = { - args: { - buttonId: "add-analytics", - }, -}; - -export const CreateFeatureFlag: Story = { - args: { - buttonId: "create-feature-flags", - }, -}; - -export const RunExperiment: Story = { - args: { - buttonId: "run-experiment", - }, -}; - -export const AddErrorTracking: Story = { - args: { - buttonId: "add-error-tracking", - }, -}; - -export const InstrumentLlmCalls: Story = { - args: { - buttonId: "instrument-llm-calls", - }, -}; - -export const AddLogging: Story = { - args: { - buttonId: "add-logging", - }, -}; diff --git a/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.tsx b/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.tsx deleted file mode 100644 index 43adc7a605..0000000000 --- a/packages/ui/src/features/skill-buttons/components/SkillButtonActionMessage.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { SKILL_BUTTONS, type SkillButtonId } from "../prompts"; - -interface SkillButtonActionMessageProps { - buttonId: SkillButtonId; -} - -export function SkillButtonActionMessage({ - buttonId, -}: SkillButtonActionMessageProps) { - const { Icon, color, actionTitle, actionDescription } = - SKILL_BUTTONS[buttonId]; - - return ( -
- -

- - {actionTitle} - - — {actionDescription} -

-
- ); -} diff --git a/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.stories.tsx b/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.stories.tsx deleted file mode 100644 index eb76ddd98f..0000000000 --- a/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { SkillButtonsMenu } from "@posthog/ui/features/skill-buttons/components/SkillButtonsMenu"; -import type { Meta, StoryObj } from "@storybook/react-vite"; - -const meta: Meta = { - title: "Skill Buttons/SkillButtonsMenu", - component: SkillButtonsMenu, - parameters: { - layout: "centered", - }, - args: { - taskId: "storybook-task", - }, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.tsx b/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.tsx deleted file mode 100644 index da5d2d3952..0000000000 --- a/packages/ui/src/features/skill-buttons/components/SkillButtonsMenu.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { CaretDown } from "@phosphor-icons/react"; -import { - Button, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@posthog/quill"; -import { ANALYTICS_EVENTS } from "@posthog/shared/analytics-events"; -import { track } from "../../../shell/analytics"; -import { sendPromptToAgent } from "../../sessions/sendPromptToAgent"; -import { - buildSkillButtonPromptBlocks, - SKILL_BUTTON_ORDER, - SKILL_BUTTONS, - type SkillButton, - type SkillButtonId, -} from "../prompts"; -import { useSkillButtonsStore } from "../skillButtonsStore"; - -interface SkillButtonsMenuProps { - taskId: string; -} - -function SkillButtonIcon({ button }: { button: SkillButton }) { - const { Icon, color } = button; - return ; -} - -export function SkillButtonsMenu({ taskId }: SkillButtonsMenuProps) { - const lastSelectedId = useSkillButtonsStore((s) => s.lastSelectedId); - const setLastSelectedId = useSkillButtonsStore((s) => s.setLastSelectedId); - - const primaryButton = SKILL_BUTTONS[lastSelectedId]; - const dropdownButtons = SKILL_BUTTON_ORDER.filter( - (id) => id !== lastSelectedId, - ).map((id) => SKILL_BUTTONS[id]); - - const handleTrigger = ( - buttonId: SkillButtonId, - source: "primary" | "dropdown", - ) => { - track(ANALYTICS_EVENTS.SKILL_BUTTON_TRIGGERED, { - task_id: taskId, - button_id: buttonId, - source, - }); - setLastSelectedId(buttonId); - sendPromptToAgent(taskId, buildSkillButtonPromptBlocks(buttonId)); - }; - - return ( - -
- - handleTrigger(primaryButton.id, "primary")} - > - - {primaryButton.label} - - } - /> - {primaryButton.tooltip} - - - - - - } - /> - - {dropdownButtons.map((button) => ( - - handleTrigger(button.id, "dropdown")} - > - - {button.label} - - } - /> - {button.tooltip} - - ))} - - -
-
- ); -} diff --git a/packages/ui/src/features/skill-buttons/prompts.ts b/packages/ui/src/features/skill-buttons/prompts.ts deleted file mode 100644 index a91439f4e7..0000000000 --- a/packages/ui/src/features/skill-buttons/prompts.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - Broadcast, - ChartBar, - Flask, - type Icon, - Pulse, - ToggleRight, - Warning, -} from "@phosphor-icons/react"; -import { - SKILL_BUTTON_CATALOG, - SKILL_BUTTON_ORDER, - type SkillButtonCatalogEntry, - type SkillButtonId, -} from "@posthog/core/skill-buttons/catalog"; -import { - buildSkillButtonPromptBlocks, - extractSkillButtonId, -} from "@posthog/core/skill-buttons/prompts"; - -export { - buildSkillButtonPromptBlocks, - extractSkillButtonId, - SKILL_BUTTON_ORDER, -}; -export type { SkillButtonId }; - -export interface SkillButton extends SkillButtonCatalogEntry { - Icon: Icon; -} - -const SKILL_BUTTON_ICONS: Record = { - "add-analytics": ChartBar, - "create-feature-flags": ToggleRight, - "run-experiment": Flask, - "add-error-tracking": Warning, - "instrument-llm-calls": Broadcast, - "add-logging": Pulse, -}; - -export const SKILL_BUTTONS: Record = - Object.fromEntries( - (Object.keys(SKILL_BUTTON_CATALOG) as SkillButtonId[]).map((id) => [ - id, - { ...SKILL_BUTTON_CATALOG[id], Icon: SKILL_BUTTON_ICONS[id] }, - ]), - ) as Record; diff --git a/packages/ui/src/features/skill-buttons/skillButtonsStore.ts b/packages/ui/src/features/skill-buttons/skillButtonsStore.ts deleted file mode 100644 index 932c1f8b77..0000000000 --- a/packages/ui/src/features/skill-buttons/skillButtonsStore.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - isSkillButtonId, - SKILL_BUTTON_ORDER, - type SkillButtonId, -} from "@posthog/core/skill-buttons/catalog"; -import { create } from "zustand"; -import { persist } from "zustand/middleware"; - -interface SkillButtonsStoreState { - lastSelectedId: SkillButtonId; -} - -interface SkillButtonsStoreActions { - setLastSelectedId: (id: SkillButtonId) => void; -} - -type SkillButtonsStore = SkillButtonsStoreState & SkillButtonsStoreActions; - -const DEFAULT_PRIMARY: SkillButtonId = SKILL_BUTTON_ORDER[0]; - -export const useSkillButtonsStore = create()( - persist( - (set) => ({ - lastSelectedId: DEFAULT_PRIMARY, - setLastSelectedId: (lastSelectedId) => set({ lastSelectedId }), - }), - { - name: "skill-buttons-storage", - merge: (persisted, current) => { - const persistedState = persisted as { - lastSelectedId?: string; - }; - const restored = isSkillButtonId(persistedState.lastSelectedId) - ? persistedState.lastSelectedId - : DEFAULT_PRIMARY; - return { - ...current, - lastSelectedId: restored, - }; - }, - }, - ), -); diff --git a/packages/ui/src/features/task-detail/components/TaskHeaderActions.test.tsx b/packages/ui/src/features/task-detail/components/TaskHeaderActions.test.tsx index f80d03734d..9e438ed755 100644 --- a/packages/ui/src/features/task-detail/components/TaskHeaderActions.test.tsx +++ b/packages/ui/src/features/task-detail/components/TaskHeaderActions.test.tsx @@ -45,12 +45,6 @@ vi.mock("@posthog/ui/features/code-review/hooks/useDiffStatsToggle", () => ({ toggle: vi.fn(), }), })); -vi.mock( - "@posthog/ui/features/skill-buttons/components/SkillButtonsMenu", - () => ({ - SkillButtonsMenu: () => null, - }), -); vi.mock("@posthog/ui/features/autoresearch/AutoresearchHeaderButton", () => ({ AutoresearchHeaderButton: () => null, })); diff --git a/packages/ui/src/features/task-detail/components/TaskHeaderActions.tsx b/packages/ui/src/features/task-detail/components/TaskHeaderActions.tsx index b1b6eb4000..dc71a76c89 100644 --- a/packages/ui/src/features/task-detail/components/TaskHeaderActions.tsx +++ b/packages/ui/src/features/task-detail/components/TaskHeaderActions.tsx @@ -18,7 +18,6 @@ import { StopCloudRunButton } from "@posthog/ui/features/sessions/components/Sto import { useHandoffDialogStore } from "@posthog/ui/features/sessions/handoffDialogStore"; import { useSessionCallbacks } from "@posthog/ui/features/sessions/hooks/useSessionCallbacks"; import { useSessionForTask } from "@posthog/ui/features/sessions/useSession"; -import { SkillButtonsMenu } from "@posthog/ui/features/skill-buttons/components/SkillButtonsMenu"; import { useWorkspace, useWorkspaceLoaded, @@ -142,9 +141,6 @@ export function TaskHeaderActions({ task }: { task: Task }) { pl="1" className="h-full max-w-[50%] shrink-0 overflow-hidden" > -
- -
diff --git a/packages/ui/src/shell/ContentHeader.tsx b/packages/ui/src/shell/ContentHeader.tsx index 741a785734..1f574c9d01 100644 --- a/packages/ui/src/shell/ContentHeader.tsx +++ b/packages/ui/src/shell/ContentHeader.tsx @@ -7,7 +7,7 @@ import { Flex } from "@radix-ui/themes"; // The in-pane content header for the unified Bluebird chrome. Shows the active // view's title (pushed into the header store by each view) on the left and that // task's action row (TaskHeaderActions) on the right — the branch selector, -// review-panel toggle, cloud/local handoff, skill buttons and task actions that +// review-panel toggle, cloud/local handoff and task actions that // used to live in the Code header bar. // // This breadcrumb row is scoped to views that have somewhere to walk back to: