Skip to content
Draft
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
6 changes: 6 additions & 0 deletions packages/shared/src/analytics-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ export type ChannelActionType =
| "unstar"
| "edit_context_open"
| "new_task_open"
| "select_suggestion_category"
| "new_task_suggestion"
| "view_context"
| "view_history"
Expand All @@ -827,10 +828,15 @@ export interface ChannelActionProperties {
channel_id?: string;
/** For file/unfile/archive/open task actions. */
task_id?: string;
/** For open_artifact when the artifact is a canvas. */
dashboard_id?: string;
/** For file_task: destination channel when different from `channel_id`. */
target_channel_id?: string;
/** For nav_click: which destination ("home"|"inbox"|"canvas"|"agents"|"files"|"settings"). */
nav_target?: string;
/** For select_suggestion_category / new_task_suggestion: the suggestion
* category id (e.g. "code", "analysis", "debug", "canvas"). */
category?: string;
/** For new_task_suggestion: the starter-prompt card label. */
suggestion_label?: string;
/** Whether the underlying mutation resolved successfully. */
Expand Down
228 changes: 159 additions & 69 deletions packages/ui/src/features/canvas/channelTaskSuggestions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,182 @@ import {
Bug,
ChartBar,
ChartLine,
ChartPieSlice,
ChatCircleText,
Code,
Cube,
CurrencyDollar,
Flask,
type Icon,
SquaresFour,
TrendDown,
WarningOctagon,
Wrench,
} from "@phosphor-icons/react";
import type { SuggestedPrompt } from "@posthog/ui/features/task-detail/components/SuggestedPromptCard";

// Starter prompts shown as cards on the channels (project-bluebird) new-task
// screen. Clicking a card drops its `prompt` into the composer, ready to
// edit/send. Each prompt ends with a "User input:" block of fill-in lines the
// user completes before sending. Channels-only — the /code new-task screen
// keeps its discovery suggestions. Card styling mirrors SuggestedTaskCard
// (icon badge + title + description); the icon/color follow the same
// `var(--<color>-N)` token scheme.
export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] = [
// Starter prompts for the channels (project-bluebird) new-task surfaces. Picking
// one drops its `prompt` into the composer, ready to edit/send. Each prompt ends
// with a "User input:" block of fill-in lines the user completes before sending.
// Channels-only — the /code new-task screen keeps its discovery suggestions.
//
// On the channel home these are grouped behind the category chips below; the
// flat CHANNEL_TASK_SUGGESTIONS list (derived at the bottom) still feeds the
// new-task screen's card grid.
export interface SuggestionCategory {
id: string;
/** Chip label shown on the channel home. */
label: string;
icon: Icon;
/** Radix color token base (`var(--<color>-N)`) for the chip + row icons. */
color: string;
suggestions: SuggestedPrompt[];
}

export const CHANNEL_SUGGESTION_CATEGORIES: SuggestionCategory[] = [
{
label: "Debug a user issue",
description: "Trace a specific user's events, replays, and errors",
icon: Bug,
color: "red",
mode: "auto",
prompt:
"Help me debug an issue a specific user is hitting. Pull their recent events, session replays, and errors, then figure out what went wrong.\n\n\nUser input:\n- Describe the user issue:\n- User identifier (distinct ID, email address, etc):",
id: "code",
label: "Code",
icon: Code,
color: "orange",
suggestions: [
{
label: "Fix a bug",
description: "Track down and fix a problem in the code",
icon: Wrench,
color: "orange",
mode: "plan",
prompt:
"Help me fix a bug — track down the root cause in the code and implement a fix. Open a PR if appropriate.\n\n\nUser input:\n- Describe the bug / what's going wrong:\n- Steps to reproduce (optional):\n- Where it happens (file, page, area — optional):",
},
{
label: "Build a new feature",
description: "Design and implement something new",
icon: Cube,
color: "teal",
mode: "plan",
prompt:
"Help me build a new feature — propose an approach, then implement it. Open a PR if appropriate.\n\n\nUser input:\n- Describe the feature you want:\n- Any constraints or requirements (optional):",
},
],
},
{
label: "Run a feature analysis",
description: "Adoption, engagement, and retention of a feature",
id: "analysis",
label: "Analysis",
icon: ChartLine,
color: "blue",
mode: "auto",
prompt:
"Analyze how a feature is performing — adoption, engagement, and retention of users who use it vs. those who don't.\n\n\nUser input:\n- Feature to analyze:\n- Time period (optional):",
suggestions: [
{
label: "Run a feature analysis",
description: "Adoption, engagement, and retention of a feature",
icon: ChartLine,
color: "blue",
mode: "auto",
prompt:
"Analyze how a feature is performing — adoption, engagement, and retention of users who use it vs. those who don't.\n\n\nUser input:\n- Feature to analyze:\n- Time period (optional):",
},
{
label: "Understand revenue patterns",
description: "Trends over time, by plan, and by cohort",
icon: CurrencyDollar,
color: "green",
mode: "auto",
prompt:
"Analyze our revenue trends — break it down over time, by plan, and by cohort, and call out notable changes and likely drivers.\n\n\nUser input:\n- What revenue question are you trying to answer:\n- Time period (optional):",
},
{
label: "Summarize product usage",
description: "Top events, active users, and key funnels",
icon: ChartBar,
color: "violet",
mode: "auto",
prompt:
"Summarize how our product is being used — top events, active users, key funnels, and notable trends.\n\n\nUser input:\n- Product area or feature to focus on (optional):\n- Time period (optional):",
},
{
label: "Interpret experiment results",
description: "Significance and what to do next",
icon: Flask,
color: "purple",
mode: "auto",
prompt:
"Interpret the results of an experiment — explain what the metrics show, whether it's significant, and what to do next.\n\n\nUser input:\n- Experiment name or key:\n- What decision are you trying to make (optional):",
},
{
label: "Summarize user & agent feedback",
description: "Common themes across recent feedback",
icon: ChatCircleText,
color: "amber",
mode: "auto",
prompt:
"Summarize recent user and support/agent feedback — surface the common themes, complaints, and requests.\n\n\nUser input:\n- Feedback source or topic to focus on:\n- Time period (optional):",
},
],
},
{
label: "Understand revenue patterns",
description: "Trends over time, by plan, and by cohort",
icon: CurrencyDollar,
color: "green",
mode: "auto",
prompt:
"Analyze our revenue trends — break it down over time, by plan, and by cohort, and call out notable changes and likely drivers.\n\n\nUser input:\n- What revenue question are you trying to answer:\n- Time period (optional):",
id: "debug",
label: "Debug",
icon: Bug,
color: "red",
suggestions: [
{
label: "Debug a user issue",
description: "Trace a specific user's events, replays, and errors",
icon: Bug,
color: "red",
mode: "auto",
prompt:
"Help me debug an issue a specific user is hitting. Pull their recent events, session replays, and errors, then figure out what went wrong.\n\n\nUser input:\n- Describe the user issue:\n- User identifier (distinct ID, email address, etc):",
},
{
label: "Investigate an error",
description: "Root cause, frequency, and who it affects",
icon: WarningOctagon,
color: "red",
mode: "auto",
prompt:
"Investigate an error or exception — find the root cause, how often it happens, and which users it affects.\n\n\nUser input:\n- Error message or issue:\n- Where you're seeing it (optional):",
},
{
label: "Diagnose a metric change",
description: "Why a metric dropped or spiked",
icon: TrendDown,
color: "amber",
mode: "auto",
prompt:
"Figure out why a metric dropped or spiked — break it down by segment and surface the likely causes.\n\n\nUser input:\n- Which metric changed:\n- When you noticed it (optional):",
},
],
},
{
label: "Summarize product usage",
description: "Top events, active users, and key funnels",
icon: ChartBar,
id: "canvas",
label: "Canvas",
icon: SquaresFour,
color: "violet",
mode: "auto",
prompt:
"Summarize how our product is being used — top events, active users, key funnels, and notable trends.\n\n\nUser input:\n- Product area or feature to focus on (optional):\n- Time period (optional):",
},
{
label: "Summarize user & agent feedback",
description: "Common themes across recent feedback",
icon: ChatCircleText,
color: "amber",
mode: "auto",
prompt:
"Summarize recent user and support/agent feedback — surface the common themes, complaints, and requests.\n\n\nUser input:\n- Feedback source or topic to focus on:\n- Time period (optional):",
},
{
label: "Interpret experiment results",
description: "Significance and what to do next",
icon: Flask,
color: "purple",
mode: "auto",
prompt:
"Interpret the results of an experiment — explain what the metrics show, whether it's significant, and what to do next.\n\n\nUser input:\n- Experiment name or key:\n- What decision are you trying to make (optional):",
},
{
label: "Fix a bug",
description: "Track down and fix a problem in the code",
icon: Wrench,
color: "orange",
mode: "plan",
prompt:
"Help me fix a bug — track down the root cause in the code and implement a fix. Open a PR if appropriate.\n\n\nUser input:\n- Describe the bug / what's going wrong:\n- Steps to reproduce (optional):\n- Where it happens (file, page, area — optional):",
},
{
label: "Build a new feature",
description: "Design and implement something new",
icon: Cube,
color: "teal",
mode: "plan",
prompt:
"Help me build a new feature — propose an approach, then implement it. Open a PR if appropriate.\n\n\nUser input:\n- Describe the feature you want:\n- Any constraints or requirements (optional):",
suggestions: [
{
label: "Build a dashboard",
description: "Lay out the key metrics on a canvas",
icon: SquaresFour,
color: "violet",
mode: "auto",
prompt:
"Build a dashboard canvas that brings together the metrics that matter for this work.\n\n\nUser input:\n- What should the dashboard cover:\n- Key metrics or breakdowns to include (optional):",
},
{
label: "Visualize a metric",
description: "Chart a single metric with the right breakdowns",
icon: ChartPieSlice,
color: "purple",
mode: "auto",
prompt:
"Create a canvas that visualizes a single metric over time, with the breakdowns that make it useful.\n\n\nUser input:\n- Metric to visualize:\n- Breakdowns or filters (optional):",
},
],
},
];

// Flat list for the new-task screen's card grid (WebsiteNewTask), which shows
// every starter prompt at once rather than grouping them behind chips.
export const CHANNEL_TASK_SUGGESTIONS: SuggestedPrompt[] =
CHANNEL_SUGGESTION_CATEGORIES.flatMap((category) => category.suggestions);
56 changes: 53 additions & 3 deletions packages/ui/src/features/canvas/components/ChannelHomeComposer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { FileText, X } from "@phosphor-icons/react";
import { isValidConfigValue } from "@posthog/core/task-detail/configOptions";
import type { Task } from "@posthog/shared/domain-types";
import { Tooltip } from "@radix-ui/themes";
import {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState,
Expand Down Expand Up @@ -35,6 +38,9 @@ interface ChannelHomeComposerProps {
channelName?: string;
/** Channel CONTEXT.md, attached to the created task as background. */
channelContext?: string;
/** Fires as the editor goes empty ⇄ non-empty, so the home page can fade out
* its suggestions / lists while the user is typing. */
onEmptyChange?: (isEmpty: boolean) => void;
onTaskCreated: (task: Task) => void;
}

Expand All @@ -48,14 +54,36 @@ export const ChannelHomeComposer = forwardRef<
ChannelHomeComposerHandle,
ChannelHomeComposerProps
>(function ChannelHomeComposer(
{ channelId, channelName, channelContext, onTaskCreated },
{ channelId, channelName, channelContext, onEmptyChange, onTaskCreated },
ref,
) {
const sessionId = `channel-home:${channelId}`;
const editorRef = useRef<EditorHandle>(null);
const [editorIsEmpty, setEditorIsEmpty] = useState(true);
const { isOnline } = useConnectivity();

// The channel CONTEXT.md is attached to new tasks by default; the chip below
// the prompt surfaces that it's included and lets the user drop it from this
// task. Re-include whenever the source context changes (e.g. the doc loads or
// the channel switches) so a dismissal doesn't stick. Mirrors TaskInput.
const [channelContextDismissed, setChannelContextDismissed] = useState(false);
const lastChannelContextRef = useRef(channelContext);
useEffect(() => {
if (lastChannelContextRef.current !== channelContext) {
lastChannelContextRef.current = channelContext;
setChannelContextDismissed(false);
}
}, [channelContext]);
const includeChannelContext = !!channelContext && !channelContextDismissed;

const handleEmptyChange = useCallback(
(isEmpty: boolean) => {
setEditorIsEmpty(isEmpty);
onEmptyChange?.(isEmpty);
},
[onEmptyChange],
);

const {
lastUsedAdapter,
setLastUsedAdapter,
Expand Down Expand Up @@ -125,7 +153,7 @@ export const ChannelHomeComposer = forwardRef<
model: currentModel,
reasoningLevel: currentReasoningLevel,
allowNoRepo: true,
channelContext,
channelContext: includeChannelContext ? channelContext : undefined,
channelName,
onTaskCreated,
});
Expand Down Expand Up @@ -225,12 +253,34 @@ export const ChannelHomeComposer = forwardRef<
/>
)
}
onEmptyChange={setEditorIsEmpty}
onEmptyChange={handleEmptyChange}
onSubmitClick={handleSubmit}
onSubmit={() => {
if (canSubmit) handleSubmit();
}}
/>

{includeChannelContext && (
<div className="-mt-px mx-2 flex select-none flex-wrap items-center gap-1.5 rounded-b-md border border-gray-6 border-t-0 bg-gray-2 px-2 py-1 text-[12px] text-gray-11">
<span className="shrink-0 text-gray-10">Using:</span>
<span className="inline-flex items-center gap-1 rounded-[var(--radius-1)] bg-[var(--gray-a3)] px-1.5 py-px font-medium text-[var(--gray-11)]">
<FileText size={12} />
<span className="truncate">
{channelName ? `#${channelName} ` : ""}CONTEXT.md
</span>
<Tooltip content="Don't include this context">
<button
type="button"
onClick={() => setChannelContextDismissed(true)}
aria-label="Remove channel context from prompt"
className="ml-0.5 inline-flex size-3.5 items-center justify-center rounded text-gray-10 hover:bg-gray-5 hover:text-gray-12"
>
<X size={12} />
</button>
</Tooltip>
</span>
</div>
)}
</div>
);
});
Loading
Loading