+
+
+
+
+
+
+ ← Back
+
+
+
+ What kind of tools do you want to connect?
+
+
+ Pick the ones you're likely to use, this helps us set up your agent.
+ You can always add or remove tools later.
+
+
+
+ {displayTools.slice(0, 12).map((tool, idx) => (
+
+
+ setSelected((prev) =>
+ e.target.checked
+ ? [...prev, tool.name]
+ : prev.filter((t) => t !== tool.name),
+ )
+ }
+ />
+
+ {_.startCase(tool.name)}
+
+
+ ))}
+
+
+
+
+ Skip
+
+ (onCreate ? onCreate(selected) : onContinue())}
+ >
+ Select triggers
+
+
+
+
+ );
+}
diff --git a/apps/web-v2/src/features/onboarding/TriggersStep.tsx b/apps/web-v2/src/features/onboarding/TriggersStep.tsx
new file mode 100644
index 00000000..933a6ba4
--- /dev/null
+++ b/apps/web-v2/src/features/onboarding/TriggersStep.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import React from "react";
+import { cn } from "@/lib/utils";
+import { Button } from "@/components/ui/button";
+import TriggersInterface from "@/features/triggers";
+import { OAPLogoBlue } from "@/components/icons/oap-logo-blue";
+
+type TriggersStepProps = {
+ onSkip: () => void;
+ onContinue: () => void;
+ onBack: () => void;
+};
+
+export default function TriggersStep({
+ onSkip,
+ onContinue,
+ onBack,
+}: TriggersStepProps) {
+ return (
+
+
+ {steps.map((_, idx) => (
+
currentIndex && "bg-gray-200",
+ )}
+ />
+ ))}
+
+
+
+ {steps.map((label, idx) => (
+
+ {label}
+
+ ))}
+
+
+
+ {percentComplete}% complete
+
+
+ );
+}
+
+export default OnboardingProgress;
diff --git a/apps/web-v2/src/features/onboarding/components/QuestionPillStep.tsx b/apps/web-v2/src/features/onboarding/components/QuestionPillStep.tsx
new file mode 100644
index 00000000..19340593
--- /dev/null
+++ b/apps/web-v2/src/features/onboarding/components/QuestionPillStep.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import React from "react";
+import { cn } from "@/lib/utils";
+import { ArrowLeft } from "lucide-react";
+import { OAPLogoBlue } from "@/components/icons/oap-logo-blue";
+
+export type PillOption = {
+ id: string;
+ label: string;
+};
+
+type QuestionPillStepProps = {
+ title: string;
+ options: PillOption[];
+ onBack: () => void;
+ onSelect: (id: string) => void;
+ footer?: React.ReactNode;
+};
+
+export function QuestionPillStep({
+ title,
+ options,
+ onBack,
+ onSelect,
+ footer,
+}: QuestionPillStepProps) {
+ return (
+
+
+
+
+
+
+
+ Back
+
+
+
+ {title}
+
+
+
+ {options.map((opt) => (
+
onSelect(opt.id)}
+ >
+
+ {opt.label}
+
+
+ ))}
+
+ {footer &&
{footer}
}
+
+
+ );
+}
+
+export default QuestionPillStep;
diff --git a/apps/web-v2/src/features/onboarding/constants.ts b/apps/web-v2/src/features/onboarding/constants.ts
new file mode 100644
index 00000000..0865bbf9
--- /dev/null
+++ b/apps/web-v2/src/features/onboarding/constants.ts
@@ -0,0 +1,185 @@
+export enum Roles {
+ ANSWER_SUPPORT = "answer_support",
+ ANALYSE_REPORTS = "analyse_reports",
+ SUMMARIZE_TRANSFORM = "summarize_transform",
+ AUTOMATE_WORKFLOWS = "automate_workflows",
+ OTHER = "other",
+}
+
+export const roleToText: Record
= {
+ [Roles.ANSWER_SUPPORT]: "Answer user questions or provide support",
+ [Roles.ANALYSE_REPORTS]: "Analyse data or generate reports",
+ [Roles.SUMMARIZE_TRANSFORM]: "Summarize or transform text",
+ [Roles.AUTOMATE_WORKFLOWS]: "Automate internal workflows",
+ [Roles.OTHER]: "Something else (please specify)",
+};
+
+export enum Audience {
+ INTERNAL_TEAMMATES = "internal_teammates",
+ EXTERNAL_USERS = "external_users",
+ OTHER_AGENTS = "other_agents",
+ JUST_ME = "just_me",
+ NOT_SURE = "not_sure",
+ OTHER = "other",
+}
+
+export const audienceToText: Record = {
+ [Audience.INTERNAL_TEAMMATES]: "Internal teammates",
+ [Audience.EXTERNAL_USERS]: "External users or customers",
+ [Audience.OTHER_AGENTS]: "Other agents or systems",
+ [Audience.JUST_ME]: "Just me for now",
+ [Audience.NOT_SURE]: "Not sure yet",
+ [Audience.OTHER]: "Something else (please specify)",
+};
+
+export enum InputKind {
+ TEXT_PROMPTS = "text_prompts",
+ UPLOADED_FILES = "uploaded_files",
+ STRUCTURED_DATA = "structured_data",
+ API_EVENTS = "api_events",
+ NOT_SURE = "not_sure",
+ OTHER = "other",
+}
+
+export const inputKindToText: Record = {
+ [InputKind.TEXT_PROMPTS]: "Text prompts or questions",
+ [InputKind.UPLOADED_FILES]: "Uploaded files",
+ [InputKind.STRUCTURED_DATA]: "Structured data (JSON, CSV, forms)",
+ [InputKind.API_EVENTS]: "API events or webhooks",
+ [InputKind.NOT_SURE]: "Not sure yet",
+ [InputKind.OTHER]: "Something else (please specify)",
+};
+
+export enum AccessKind {
+ INTERNAL_DOCS = "internal_docs",
+ EXTERNAL_APIS = "external_apis",
+ WEB_SEARCH = "web_search",
+ NOTHING = "nothing",
+ NOT_SURE = "not_sure",
+ OTHER = "other",
+}
+
+export const accessKindToText: Record = {
+ [AccessKind.INTERNAL_DOCS]: "Internal docs or databases",
+ [AccessKind.EXTERNAL_APIS]: "External APIs",
+ [AccessKind.WEB_SEARCH]: "Real-time web search",
+ [AccessKind.NOTHING]: "Nothing - just reasoning and context",
+ [AccessKind.NOT_SURE]: "Not sure yet",
+ [AccessKind.OTHER]: "Something else (please specify)",
+};
+
+export enum MemoryKind {
+ STORE_ACROSS_SESSIONS = "store_across_sessions",
+ SINGLE_SESSION = "single_session",
+ STATELESS = "stateless",
+ NOT_SURE = "not_sure",
+ OTHER = "other",
+}
+
+export const memoryKindToText: Record = {
+ [MemoryKind.STORE_ACROSS_SESSIONS]: "Yes, store memory across sessions",
+ [MemoryKind.SINGLE_SESSION]: "Only remember things during a single session",
+ [MemoryKind.STATELESS]: "No, it should be stateless",
+ [MemoryKind.NOT_SURE]: "Not sure yet",
+ [MemoryKind.OTHER]: "Something else (please specify)",
+};
+
+export enum CapabilityKind {
+ READ_ONLY = "read_only",
+ WRITE_DATA = "write_data",
+ SEND_MESSAGES = "send_messages",
+ EXECUTE_FUNCTIONS = "execute_functions",
+ EXPLORE = "explore",
+ OTHER = "other",
+}
+
+export const capabilityKindToText: Record = {
+ [CapabilityKind.READ_ONLY]: "Read only",
+ [CapabilityKind.WRITE_DATA]: "Write data",
+ [CapabilityKind.SEND_MESSAGES]: "Send messages or notifications",
+ [CapabilityKind.EXECUTE_FUNCTIONS]: "Execute functions or code",
+ [CapabilityKind.EXPLORE]: "Just explore for now",
+ [CapabilityKind.OTHER]: "Something else (please specify)",
+};
+
+export enum SubAgentsChoice {
+ YES = "yes",
+ NOT_RIGHT_NOW = "not_right_now",
+ NOT_SURE_MEANS = "not_sure_means",
+}
+
+export const subAgentsChoiceToText: Record = {
+ [SubAgentsChoice.YES]: "Yes",
+ [SubAgentsChoice.NOT_RIGHT_NOW]: "Not right now",
+ [SubAgentsChoice.NOT_SURE_MEANS]: "I'm not sure what that means",
+};
+
+export enum ToneKind {
+ PROFESSIONAL = "professional",
+ FRIENDLY = "friendly",
+ CASUAL = "casual",
+ FORMAL = "formal",
+ CUSTOM = "custom",
+}
+
+export const toneKindToText: Record = {
+ [ToneKind.PROFESSIONAL]: "Professional and concise",
+ [ToneKind.FRIENDLY]: "Friendly and helpful",
+ [ToneKind.CASUAL]: "Casual and informal",
+ [ToneKind.FORMAL]: "Formal and structured",
+ [ToneKind.CUSTOM]: "I'll write a custom tone",
+};
+
+export enum ReasoningKind {
+ ALWAYS = "always",
+ ON_REQUEST = "on_request",
+ NO = "no",
+}
+
+export const reasoningKindToText: Record = {
+ [ReasoningKind.ALWAYS]: "Yes, always explain the steps",
+ [ReasoningKind.ON_REQUEST]: "Only when I ask for it",
+ [ReasoningKind.NO]: "No, just show me the result",
+};
+
+export enum GuardrailKind {
+ NO_SENSITIVE = "no_sensitive",
+ CONFIRM_BEFORE_ACTION = "confirm_before_action",
+ NEVER_DELETE_MODIFY = "never_delete_modify",
+ NO_CONSTRAINTS = "no_constraints",
+ CUSTOM = "custom",
+}
+
+export const guardrailKindToText: Record = {
+ [GuardrailKind.NO_SENSITIVE]: "Don't store or share sensitive data",
+ [GuardrailKind.CONFIRM_BEFORE_ACTION]: "Always confirm before taking action",
+ [GuardrailKind.NEVER_DELETE_MODIFY]: "Never delete or modify data",
+ [GuardrailKind.NO_CONSTRAINTS]: "No constraints",
+ [GuardrailKind.CUSTOM]: "I'll define my own",
+};
+
+export enum RunLocationKind {
+ WEB_APP_DASHBOARD = "web_app_dashboard",
+ CHAT_INTERFACE = "chat_interface",
+ EMBEDDED_PRODUCT = "embedded_product",
+ NONE_EXPERIMENTING = "none_experimenting",
+}
+
+export const runLocationKindToText: Record = {
+ [RunLocationKind.WEB_APP_DASHBOARD]: "A web app or internal dashboard",
+ [RunLocationKind.CHAT_INTERFACE]: "Chat interface",
+ [RunLocationKind.EMBEDDED_PRODUCT]: "Embedded in a product",
+ [RunLocationKind.NONE_EXPERIMENTING]: "Nowhere yet, I'm still experimenting",
+};
+
+export enum LoggingKind {
+ LOG_EVERYTHING = "log_everything",
+ LOG_MAJOR_DECISIONS = "log_major_decisions",
+ NO_LOGGING = "no_logging",
+}
+
+export const loggingKindToText: Record = {
+ [LoggingKind.LOG_EVERYTHING]: "Yes, log everything",
+ [LoggingKind.LOG_MAJOR_DECISIONS]: "Only log major decisions",
+ [LoggingKind.NO_LOGGING]: "No logging needed",
+};
diff --git a/apps/web-v2/src/features/triggers/index.tsx b/apps/web-v2/src/features/triggers/index.tsx
index 8f2e4742..39514727 100644
--- a/apps/web-v2/src/features/triggers/index.tsx
+++ b/apps/web-v2/src/features/triggers/index.tsx
@@ -20,7 +20,13 @@ import { LaunchDarklyFeatureFlags } from "@/types/launch-darkly";
import { TriggerAccordionItem } from "./components/trigger-accordion-item";
import { Accordion } from "@/components/ui/accordion";
-export default function TriggersInterface() {
+interface TriggersInterfaceProps {
+ hideHeader?: boolean;
+}
+
+export default function TriggersInterface({
+ hideHeader = false,
+}: TriggersInterfaceProps) {
const [triggersLoading, setTriggersLoading] = useState(true);
const [groupedTriggers, setGroupedTriggers] =
useState();
@@ -69,14 +75,16 @@ export default function TriggersInterface() {
if (triggersLoading) {
return (
-
-
-
Triggers
-
- Set up triggers to automatically activate your agents
-
+ {!hideHeader && (
+
+
+
Triggers
+
+ Set up triggers to automatically activate your agents
+
+
-
+ )}
@@ -98,14 +106,16 @@ export default function TriggersInterface() {
if (showTriggersTab === false) {
return (
-
-
-
Triggers
-
- Set up triggers to automatically activate your agents
-
+ {!hideHeader && (
+
+
+
Triggers
+
+ Set up triggers to automatically activate your agents
+
+
-
+ )}
@@ -126,14 +136,16 @@ export default function TriggersInterface() {
if (!groupedTriggers || Object.keys(groupedTriggers).length === 0) {
return (
-
-
-
Triggers
-
- Set up triggers to automatically activate your agents
-
+ {!hideHeader && (
+
+
+
Triggers
+
+ Set up triggers to automatically activate your agents
+
+
-
+ )}
@@ -164,15 +176,17 @@ export default function TriggersInterface() {
return (
-
-
-
Triggers
-
- Authenticate with the following apps and set up triggers to
- automatically activate your agents.
-
+ {!hideHeader && (
+
+
+
Triggers
+
+ Authenticate with the following apps and set up triggers to
+ automatically activate your agents.
+
+
-
+ )}