Skip to content

Commit

Permalink
feat(max): Use new "Product description" project setting (#25937)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
Twixes and github-actions[bot] authored Nov 4, 2024
1 parent 79dc03b commit 456466b
Show file tree
Hide file tree
Showing 51 changed files with 240 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-plugin-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ jobs:
- name: Install sqlx-cli
if: needs.changes.outputs.plugin-server == 'true'
working-directory: rust
run: cargo install [email protected] --no-default-features --features native-tls,postgres
run: cargo install [email protected] --locked --no-default-features --features native-tls,postgres

- name: Install SAML (python3-saml) dependencies
if: needs.changes.outputs.plugin-server == 'true'
Expand Down
1 change: 1 addition & 0 deletions ee/hogai/trends/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def run(self, state: AssistantState, config: RunnableConfig):
AgentAction,
agent.invoke(
{
"product_description": self._team.project.product_description,
"tools": toolkit.render_text_description(),
"tool_names": ", ".join([t["name"] for t in toolkit.tools]),
"agent_scratchpad": self._get_agent_scratchpad(intermediate_steps),
Expand Down
5 changes: 4 additions & 1 deletion ee/hogai/trends/prompts.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
react_system_prompt = """
You're a product analyst agent. Your task is to define trends series: events, property filters, and values of property filters from the user's data in order to correctly answer on the user's question.
The product being analyzed is described as follows:
{{product_description}}
You have access to the following tools:
{{tools}}
Use a json blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).
Use a JSON blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).
Valid "action" values: {{tool_names}}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-max-ai--welcome--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-max-ai--welcome--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const SidePanelFeaturePreviews = (): JSX.Element => {
return (
<div className="flex flex-col overflow-hidden">
<SidePanelPaneHeader title="Feature previews" />
<div className="flex-1 p-4 overflow-y-auto space-y-4">
<div className="flex-1 p-3 overflow-y-auto space-y-4">
<LemonBanner type="info">
Get early access to these upcoming features. Let us know what you think!
</LemonBanner>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IconExternal } from '@posthog/icons'
import { LemonButton } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { capitalizeFirstLetter } from 'lib/utils'
import { useEffect } from 'react'
import { Settings } from 'scenes/settings/Settings'
import { settingsLogic } from 'scenes/settings/settingsLogic'
Expand Down Expand Up @@ -30,6 +31,9 @@ export const SidePanelSettings = (): JSX.Element => {
return (
<div className="flex flex-col overflow-hidden">
<SidePanelPaneHeader>
<span className="flex-1 px-2 font-semibold text-base truncate">
{capitalizeFirstLetter(selectedLevel)} settings
</span>
<LemonButton
size="small"
to={urls.settings(settings.sectionId ?? settings.settingLevelId, settings.settingId)}
Expand All @@ -39,7 +43,7 @@ export const SidePanelSettings = (): JSX.Element => {
All settings
</LemonButton>
</SidePanelPaneHeader>
<div className="flex-1 p-4 overflow-y-auto">
<div className="flex-1 p-3 overflow-y-auto">
<Settings hideSections {...settingsLogicProps} />
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/api.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const MOCK_DEFAULT_PROJECT: ProjectType = {
name: 'MockHog App + Marketing',
organization_id: MOCK_ORGANIZATION_ID,
created_at: '2020-06-30T09:53:35.932534Z',
product_description: null,
}

export const MOCK_DEFAULT_ORGANIZATION: OrganizationType = {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/scenes/max/Intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ export function Intro(): JSX.Element {
</div>
<div className="text-center mb-2">
<h2 className="text-2xl font-bold mb-2 text-balance">{headline}</h2>
<span className="text-muted">
<div className="text-muted text-balance">
I'm Max, here to help you build a succesful product. Ask me about your product and your users.
</span>
</div>
</div>
</>
)
Expand Down
58 changes: 37 additions & 21 deletions frontend/src/scenes/max/Max.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Meta, StoryFn } from '@storybook/react'
import { BindLogic, useActions, useValues } from 'kea'
import { MOCK_DEFAULT_PROJECT } from 'lib/api.mock'
import { useEffect } from 'react'
import { projectLogic } from 'scenes/projectLogic'

import { mswDecorator, useStorybookMocks } from '~/mocks/browser'

Expand All @@ -25,10 +27,13 @@ const meta: Meta = {
}
export default meta

const Template = ({ sessionId }: { sessionId: string }): JSX.Element => {
// The session ID is hard-coded here, as it's used for randomizing the welcome headline
const SESSION_ID = 'b1b4b3b4-1b3b-4b3b-1b3b4b3b4b3b'

const Template = ({ sessionId: SESSION_ID }: { sessionId: string }): JSX.Element => {
return (
<div className="relative flex flex-col h-fit">
<BindLogic logic={maxLogic} props={{ sessionId }}>
<BindLogic logic={maxLogic} props={{ sessionId: SESSION_ID }}>
<MaxInstance />
</BindLogic>
</div>
Expand All @@ -38,7 +43,7 @@ const Template = ({ sessionId }: { sessionId: string }): JSX.Element => {
export const Welcome: StoryFn = () => {
useStorybookMocks({
post: {
'/api/projects/:team_id/query/': () => [
'/api/environments/:team_id/query/': () => [
200,
{
questions: [
Expand All @@ -52,19 +57,33 @@ export const Welcome: StoryFn = () => {
},
})

const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
return <Template sessionId={sessionId} />
return <Template sessionId={SESSION_ID} />
}

export const WelcomeSuggestionsAvailable: StoryFn = () => {
const { loadCurrentProjectSuccess } = useActions(projectLogic)

useEffect(() => {
loadCurrentProjectSuccess({ ...MOCK_DEFAULT_PROJECT, product_description: 'A Storybook test.' })
})

return <Welcome />
}

export const WelcomeLoadingSuggestions: StoryFn = () => {
useStorybookMocks({
post: {
'/api/projects/:team_id/query/': (_req, _res, ctx) => [ctx.delay('infinite')],
'/api/environments/:team_id/query/': (_req, _res, ctx) => [ctx.delay('infinite')],
},
})

const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
return <Template sessionId={sessionId} />
const { loadCurrentProjectSuccess } = useActions(projectLogic)

useEffect(() => {
loadCurrentProjectSuccess({ ...MOCK_DEFAULT_PROJECT, product_description: 'A Storybook test.' })
})

return <Template sessionId={SESSION_ID} />
}
WelcomeLoadingSuggestions.parameters = {
testOptions: {
Expand All @@ -73,14 +92,13 @@ WelcomeLoadingSuggestions.parameters = {
}

export const Thread: StoryFn = () => {
const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
const { askMax } = useActions(maxLogic({ sessionId: SESSION_ID }))

const { askMax } = useActions(maxLogic({ sessionId }))
useEffect(() => {
askMax('What are my most popular pages?')
}, [])

return <Template sessionId={sessionId} />
return <Template sessionId={SESSION_ID} />
}

export const EmptyThreadLoading: StoryFn = () => {
Expand All @@ -90,14 +108,13 @@ export const EmptyThreadLoading: StoryFn = () => {
},
})

const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
const { askMax } = useActions(maxLogic({ sessionId: SESSION_ID }))

const { askMax } = useActions(maxLogic({ sessionId }))
useEffect(() => {
askMax('What are my most popular pages?')
}, [])

return <Template sessionId={sessionId} />
return <Template sessionId={SESSION_ID} />
}
EmptyThreadLoading.parameters = {
testOptions: {
Expand All @@ -112,20 +129,20 @@ export const GenerationFailureThread: StoryFn = () => {
},
})

const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
const { askMax, setMessageStatus } = useActions(maxLogic({ sessionId: SESSION_ID }))
const { thread, threadLoading } = useValues(maxLogic({ sessionId: SESSION_ID }))

const { askMax, setMessageStatus } = useActions(maxLogic({ sessionId }))
const { thread, threadLoading } = useValues(maxLogic({ sessionId }))
useEffect(() => {
askMax('What are my most popular pages?')
}, [])

useEffect(() => {
if (thread.length === 2 && !threadLoading) {
setMessageStatus(1, 'error')
}
}, [thread.length, threadLoading])

return <Template sessionId={sessionId} />
return <Template sessionId={SESSION_ID} />
}

export const ThreadWithFailedGeneration: StoryFn = () => {
Expand All @@ -135,12 +152,11 @@ export const ThreadWithFailedGeneration: StoryFn = () => {
},
})

const sessionId = 'd210b263-8521-4c5b-b3c4-8e0348df574b'
const { askMax } = useActions(maxLogic({ sessionId: SESSION_ID }))

const { askMax } = useActions(maxLogic({ sessionId }))
useEffect(() => {
askMax('What are my most popular pages?')
}, [])

return <Template sessionId={sessionId} />
return <Template sessionId={SESSION_ID} />
}
2 changes: 1 addition & 1 deletion frontend/src/scenes/max/Max.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function MaxInstance(): JSX.Element {
{!thread.length ? (
<div className="relative flex flex-col gap-4 px-4 items-center grow justify-center">
<Intro />
<div className="flex flex-col gap-3 items-center w-[min(40rem,100%)]">
<div className="flex flex-col gap-3 items-center w-full">
<QuestionInput />
<QuestionSuggestions />
</div>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/scenes/max/QuestionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export function QuestionInput(): JSX.Element {
return (
<div
className={clsx(
'w-full',
!isFloating
? 'w-[min(40rem,100%)] relative'
: 'max-w-200 sticky z-10 self-center p-1 mx-3 mb-3 bottom-3 border border-[var(--glass-border-3000)] rounded-[0.625rem] backdrop-blur bg-[var(--glass-bg-3000)]'
: 'w-full max-w-200 sticky z-10 self-center p-1 mx-3 mb-3 bottom-3 border border-[var(--glass-border-3000)] rounded-[0.625rem] backdrop-blur bg-[var(--glass-bg-3000)]'
)}
>
<LemonTextArea
Expand Down
92 changes: 60 additions & 32 deletions frontend/src/scenes/max/QuestionSuggestions.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
import { IconArrowUpRight, IconShuffle } from '@posthog/icons'
import { IconArrowUpRight, IconGear, IconOpenSidebar, IconShuffle } from '@posthog/icons'
import { LemonButton, LemonSkeleton } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { useEffect } from 'react'

import { sidePanelSettingsLogic } from '~/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic'

import { maxLogic } from './maxLogic'

export function QuestionSuggestions(): JSX.Element {
const { visibleSuggestions, wasSuggestionLoadingInitiated, allSuggestionsLoading } = useValues(maxLogic)
const { askMax, loadSuggestions, shuffleVisibleSuggestions } = useActions(maxLogic)
const { visibleSuggestions, allSuggestionsLoading, currentProject } = useValues(maxLogic)
const { askMax, shuffleVisibleSuggestions } = useActions(maxLogic)
const { openSettingsPanel } = useActions(sidePanelSettingsLogic)

useEffect(() => {
if (!wasSuggestionLoadingInitiated) {
loadSuggestions()
}
}, [wasSuggestionLoadingInitiated, loadSuggestions])
if (currentProject && !currentProject.product_description) {
return (
<LemonButton
size="xsmall"
type="primary"
sideIcon={<IconOpenSidebar />}
className="relative"
onClick={() => {
openSettingsPanel({ settingId: 'product-description' })
setTimeout(() => document.getElementById('product-description-textarea')?.focus(), 1)
}}
>
Tell me a bit about your product, and I'll offer better answers and suggestions
</LemonButton>
)
}

return (
<div className="flex items-center justify-center gap-2 min-w-full">
<div
className={clsx(
'flex items-center justify-center flex-wrap gap-x-2 gap-y-1.5',
!visibleSuggestions && allSuggestionsLoading ? 'w-[min(40rem,100%)]' : 'w-[min(48rem,100%)]'
)}
>
{
visibleSuggestions ? (
<>
{visibleSuggestions.map((suggestion, index) => (
<LemonButton
key={index}
onClick={() => askMax(suggestion)}
size="xsmall"
type="secondary"
sideIcon={<IconArrowUpRight />}
>
{suggestion}
</LemonButton>
))}
<LemonButton
onClick={shuffleVisibleSuggestions}
size="xsmall"
type="secondary"
icon={<IconShuffle />}
tooltip="Shuffle suggestions"
/>
</>
) : allSuggestionsLoading ? (
allSuggestionsLoading ? (
Array.from({ length: 4 }).map((_, index) => (
<LemonButton
key={index}
Expand All @@ -53,6 +51,36 @@ export function QuestionSuggestions(): JSX.Element {
<LemonSkeleton className="h-3 w-full" />
</LemonButton>
))
) : visibleSuggestions ? (
<>
{visibleSuggestions.map((suggestion, index) => (
<LemonButton
key={index}
onClick={() => askMax(suggestion)}
size="xsmall"
type="secondary"
sideIcon={<IconArrowUpRight />}
>
{suggestion}
</LemonButton>
))}
<div className="flex gap-2">
<LemonButton
onClick={shuffleVisibleSuggestions}
size="xsmall"
type="secondary"
icon={<IconShuffle />}
tooltip="Shuffle suggestions"
/>
<LemonButton
onClick={() => openSettingsPanel({ settingId: 'product-description' })}
size="xsmall"
type="secondary"
icon={<IconGear />}
tooltip="Edit product description"
/>
</div>
</>
) : null /* Some error */
}
</div>
Expand Down
Loading

0 comments on commit 456466b

Please sign in to comment.