vanilla-agent-proxy 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +40 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +40 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/flows/scheduling.ts +42 -6
package/dist/index.cjs
CHANGED
|
@@ -58,8 +58,8 @@ var CONVERSATIONAL_FLOW = {
|
|
|
58
58
|
|
|
59
59
|
// src/flows/scheduling.ts
|
|
60
60
|
var FORM_DIRECTIVE_FLOW = {
|
|
61
|
-
name: "Form Flow",
|
|
62
|
-
description: "Returns
|
|
61
|
+
name: "Dynamic Form Flow",
|
|
62
|
+
description: "Returns dynamic forms as component directives",
|
|
63
63
|
steps: [
|
|
64
64
|
{
|
|
65
65
|
id: "form_prompt",
|
|
@@ -72,8 +72,44 @@ var FORM_DIRECTIVE_FLOW = {
|
|
|
72
72
|
responseFormat: "JSON",
|
|
73
73
|
outputVariable: "prompt_result",
|
|
74
74
|
userPrompt: "{{user_message}}",
|
|
75
|
-
systemPrompt: `You are a helpful
|
|
76
|
-
|
|
75
|
+
systemPrompt: `You are a helpful assistant that can have conversations and collect user information via forms.
|
|
76
|
+
|
|
77
|
+
RESPONSE FORMAT:
|
|
78
|
+
Always respond with valid JSON. Choose the appropriate format:
|
|
79
|
+
|
|
80
|
+
1. For CONVERSATIONAL responses or text answers:
|
|
81
|
+
{"text": "Your response here"}
|
|
82
|
+
|
|
83
|
+
2. When the user wants to SCHEDULE, BOOK, SIGN UP, or provide DETAILS (show a form):
|
|
84
|
+
{"component": "DynamicForm", "props": {"title": "Form Title", "description": "Optional description", "fields": [...], "submit_text": "Submit"}}
|
|
85
|
+
|
|
86
|
+
3. For BOTH explanation AND form:
|
|
87
|
+
{"text": "Your explanation", "component": "DynamicForm", "props": {...}}
|
|
88
|
+
|
|
89
|
+
FORM FIELD FORMAT:
|
|
90
|
+
Each field in the "fields" array should have:
|
|
91
|
+
- label (required): Display name for the field
|
|
92
|
+
- name (optional): Field identifier (defaults to lowercase label with underscores)
|
|
93
|
+
- type (optional): "text", "email", "tel", "date", "time", "textarea", "number" (defaults to "text")
|
|
94
|
+
- placeholder (optional): Placeholder text
|
|
95
|
+
- required (optional): true/false
|
|
96
|
+
|
|
97
|
+
EXAMPLES:
|
|
98
|
+
|
|
99
|
+
User: "Schedule a demo for me"
|
|
100
|
+
Response: {"text": "I'd be happy to help you schedule a demo! Please fill out the form below:", "component": "DynamicForm", "props": {"title": "Schedule a Demo", "description": "Share your details and we'll follow up with a confirmation.", "fields": [{"label": "Full Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Company", "type": "text"}, {"label": "Preferred Date", "type": "date", "required": true}, {"label": "Notes", "type": "textarea", "placeholder": "Any specific topics you'd like to cover?"}], "submit_text": "Request Demo"}}
|
|
101
|
+
|
|
102
|
+
User: "What is AI?"
|
|
103
|
+
Response: {"text": "AI (Artificial Intelligence) refers to computer systems designed to perform tasks that typically require human intelligence, such as learning, reasoning, problem-solving, and understanding language."}
|
|
104
|
+
|
|
105
|
+
User: "Collect my contact details"
|
|
106
|
+
Response: {"component": "DynamicForm", "props": {"title": "Contact Details", "fields": [{"label": "Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Phone", "type": "tel"}], "submit_text": "Save Details"}}
|
|
107
|
+
|
|
108
|
+
IMPORTANT:
|
|
109
|
+
- Use {"text": "..."} for questions, explanations, and general conversation
|
|
110
|
+
- Show a DynamicForm when user wants to provide information, schedule, book, or sign up
|
|
111
|
+
- Create contextually appropriate form fields based on what the user is trying to do
|
|
112
|
+
- Keep forms focused with only the relevant fields needed`,
|
|
77
113
|
previousMessages: "{{messages}}"
|
|
78
114
|
}
|
|
79
115
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/scheduling.ts","../src/flows/shopping-assistant.ts","../src/flows/components.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\");\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n \n // Determine the CORS origin to allow\n let corsOrigin: string;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No restrictions - allow any origin (or use the request origin)\n corsOrigin = origin || \"*\";\n } else if (allowedOrigins.includes(origin || \"\")) {\n // Origin is in the allowed list\n corsOrigin = origin || \"*\";\n } else if (isDevelopment && origin) {\n // In development, allow the actual origin even if not in the list\n // This helps with local development where ports might vary\n corsOrigin = origin;\n } else {\n // Production: origin not allowed - reject by not setting CORS headers\n // Return error for preflight, or continue without CORS headers\n if (c.req.method === \"OPTIONS\") {\n return c.json({ error: \"CORS policy violation: origin not allowed\" }, 403);\n }\n // For non-preflight requests, continue but browser will block due to missing CORS headers\n await next();\n return;\n }\n\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsOrigin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n id: flowId\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Scheduling flow configuration\n * This flow returns a form to test rendering using post processing:\n */\nexport const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {\n name: \"Form Flow\",\n description: \"Returns Form for rendering in chat\",\n steps: [\n {\n id: \"form_prompt\",\n name: \"Form Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful scheduling assistant.\nWhen the user provides scheduling details, respond with the directive <Form type=\\\"init\\\"/> so the widget can render an interactive form.`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Component-aware flow for custom component rendering\n * This flow instructs the AI to respond with component directives in JSON format\n */\nexport const COMPONENT_FLOW: TravrseFlowConfig = {\n name: \"Component Flow\",\n description: \"Flow configured for custom component rendering\",\n steps: [\n {\n id: \"component_prompt\",\n name: \"Component Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can both have conversations and render custom UI components.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format based on the user's request:\n\n1. For CONVERSATIONAL questions or text responses:\n {\"text\": \"Your response here\"}\n\n2. For VISUAL DISPLAYS or when the user asks to SHOW/DISPLAY something:\n {\"component\": \"ComponentName\", \"props\": {...}}\n\n3. For BOTH explanation AND visual:\n {\"text\": \"Your explanation here\", \"component\": \"ComponentName\", \"props\": {...}}\n\nAvailable components for visual displays:\n- ProductCard: Display product information. Props: title (string), price (number), description (string, optional), image (string, optional)\n- SimpleChart: Display a bar chart. Props: title (string), data (array of numbers), labels (array of strings, optional)\n- StatusBadge: Display a status badge. Props: status (string: \"success\", \"error\", \"warning\", \"info\", \"pending\"), message (string)\n- InfoCard: Display an information card. Props: title (string), content (string), icon (string, optional)\n\nExamples:\n- User asks \"What is the capital of France?\": {\"text\": \"The capital of France is Paris.\"}\n- User asks \"What does that chart show?\": {\"text\": \"The chart shows sales data increasing from 100 to 200 over three months.\"}\n- User asks \"Show me a product card\": {\"component\": \"ProductCard\", \"props\": {\"title\": \"Laptop\", \"price\": 999, \"description\": \"A great laptop\"}}\n- User asks \"Display a chart\": {\"component\": \"SimpleChart\", \"props\": {\"title\": \"Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n- User asks \"Show me a chart and explain it\": {\"text\": \"Here's the sales data for Q1:\", \"component\": \"SimpleChart\", \"props\": {\"title\": \"Q1 Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, discussions, and general chat\n- Use {\"component\": \"...\", \"props\": {...}} ONLY when the user explicitly wants to SEE/VIEW/DISPLAY visual content\n- You can combine both: {\"text\": \"...\", \"component\": \"...\", \"props\": {...}} when you want to explain something AND show a visual\n- Never force a component when the user just wants information`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/scheduling.ts","../src/flows/shopping-assistant.ts","../src/flows/components.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\");\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n \n // Determine the CORS origin to allow\n let corsOrigin: string;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No restrictions - allow any origin (or use the request origin)\n corsOrigin = origin || \"*\";\n } else if (allowedOrigins.includes(origin || \"\")) {\n // Origin is in the allowed list\n corsOrigin = origin || \"*\";\n } else if (isDevelopment && origin) {\n // In development, allow the actual origin even if not in the list\n // This helps with local development where ports might vary\n corsOrigin = origin;\n } else {\n // Production: origin not allowed - reject by not setting CORS headers\n // Return error for preflight, or continue without CORS headers\n if (c.req.method === \"OPTIONS\") {\n return c.json({ error: \"CORS policy violation: origin not allowed\" }, 403);\n }\n // For non-preflight requests, continue but browser will block due to missing CORS headers\n await next();\n return;\n }\n\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsOrigin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n id: flowId\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Dynamic Form flow configuration\n * This flow returns forms as component directives for the widget to render\n */\nexport const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {\n name: \"Dynamic Form Flow\",\n description: \"Returns dynamic forms as component directives\",\n steps: [\n {\n id: \"form_prompt\",\n name: \"Form Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can have conversations and collect user information via forms.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format:\n\n1. For CONVERSATIONAL responses or text answers:\n {\"text\": \"Your response here\"}\n\n2. When the user wants to SCHEDULE, BOOK, SIGN UP, or provide DETAILS (show a form):\n {\"component\": \"DynamicForm\", \"props\": {\"title\": \"Form Title\", \"description\": \"Optional description\", \"fields\": [...], \"submit_text\": \"Submit\"}}\n\n3. For BOTH explanation AND form:\n {\"text\": \"Your explanation\", \"component\": \"DynamicForm\", \"props\": {...}}\n\nFORM FIELD FORMAT:\nEach field in the \"fields\" array should have:\n- label (required): Display name for the field\n- name (optional): Field identifier (defaults to lowercase label with underscores)\n- type (optional): \"text\", \"email\", \"tel\", \"date\", \"time\", \"textarea\", \"number\" (defaults to \"text\")\n- placeholder (optional): Placeholder text\n- required (optional): true/false\n\nEXAMPLES:\n\nUser: \"Schedule a demo for me\"\nResponse: {\"text\": \"I'd be happy to help you schedule a demo! Please fill out the form below:\", \"component\": \"DynamicForm\", \"props\": {\"title\": \"Schedule a Demo\", \"description\": \"Share your details and we'll follow up with a confirmation.\", \"fields\": [{\"label\": \"Full Name\", \"type\": \"text\", \"required\": true}, {\"label\": \"Email\", \"type\": \"email\", \"required\": true}, {\"label\": \"Company\", \"type\": \"text\"}, {\"label\": \"Preferred Date\", \"type\": \"date\", \"required\": true}, {\"label\": \"Notes\", \"type\": \"textarea\", \"placeholder\": \"Any specific topics you'd like to cover?\"}], \"submit_text\": \"Request Demo\"}}\n\nUser: \"What is AI?\"\nResponse: {\"text\": \"AI (Artificial Intelligence) refers to computer systems designed to perform tasks that typically require human intelligence, such as learning, reasoning, problem-solving, and understanding language.\"}\n\nUser: \"Collect my contact details\"\nResponse: {\"component\": \"DynamicForm\", \"props\": {\"title\": \"Contact Details\", \"fields\": [{\"label\": \"Name\", \"type\": \"text\", \"required\": true}, {\"label\": \"Email\", \"type\": \"email\", \"required\": true}, {\"label\": \"Phone\", \"type\": \"tel\"}], \"submit_text\": \"Save Details\"}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, and general conversation\n- Show a DynamicForm when user wants to provide information, schedule, book, or sign up\n- Create contextually appropriate form fields based on what the user is trying to do\n- Keep forms focused with only the relevant fields needed`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Component-aware flow for custom component rendering\n * This flow instructs the AI to respond with component directives in JSON format\n */\nexport const COMPONENT_FLOW: TravrseFlowConfig = {\n name: \"Component Flow\",\n description: \"Flow configured for custom component rendering\",\n steps: [\n {\n id: \"component_prompt\",\n name: \"Component Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can both have conversations and render custom UI components.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format based on the user's request:\n\n1. For CONVERSATIONAL questions or text responses:\n {\"text\": \"Your response here\"}\n\n2. For VISUAL DISPLAYS or when the user asks to SHOW/DISPLAY something:\n {\"component\": \"ComponentName\", \"props\": {...}}\n\n3. For BOTH explanation AND visual:\n {\"text\": \"Your explanation here\", \"component\": \"ComponentName\", \"props\": {...}}\n\nAvailable components for visual displays:\n- ProductCard: Display product information. Props: title (string), price (number), description (string, optional), image (string, optional)\n- SimpleChart: Display a bar chart. Props: title (string), data (array of numbers), labels (array of strings, optional)\n- StatusBadge: Display a status badge. Props: status (string: \"success\", \"error\", \"warning\", \"info\", \"pending\"), message (string)\n- InfoCard: Display an information card. Props: title (string), content (string), icon (string, optional)\n\nExamples:\n- User asks \"What is the capital of France?\": {\"text\": \"The capital of France is Paris.\"}\n- User asks \"What does that chart show?\": {\"text\": \"The chart shows sales data increasing from 100 to 200 over three months.\"}\n- User asks \"Show me a product card\": {\"component\": \"ProductCard\", \"props\": {\"title\": \"Laptop\", \"price\": 999, \"description\": \"A great laptop\"}}\n- User asks \"Display a chart\": {\"component\": \"SimpleChart\", \"props\": {\"title\": \"Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n- User asks \"Show me a chart and explain it\": {\"text\": \"Here's the sales data for Q1:\", \"component\": \"SimpleChart\", \"props\": {\"title\": \"Q1 Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, discussions, and general chat\n- Use {\"component\": \"...\", \"props\": {...}} ONLY when the user explicitly wants to SEE/VIEW/DISPLAY visual content\n- You can combine both: {\"text\": \"...\", \"component\": \"...\", \"props\": {...}} when you want to explain something AND show a visual\n- Never force a component when the user just wants information`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -8,8 +8,8 @@ import { Hono } from 'hono';
|
|
|
8
8
|
declare const CONVERSATIONAL_FLOW: TravrseFlowConfig;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* This flow returns
|
|
11
|
+
* Dynamic Form flow configuration
|
|
12
|
+
* This flow returns forms as component directives for the widget to render
|
|
13
13
|
*/
|
|
14
14
|
declare const FORM_DIRECTIVE_FLOW: TravrseFlowConfig;
|
|
15
15
|
|
package/dist/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ import { Hono } from 'hono';
|
|
|
8
8
|
declare const CONVERSATIONAL_FLOW: TravrseFlowConfig;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* This flow returns
|
|
11
|
+
* Dynamic Form flow configuration
|
|
12
|
+
* This flow returns forms as component directives for the widget to render
|
|
13
13
|
*/
|
|
14
14
|
declare const FORM_DIRECTIVE_FLOW: TravrseFlowConfig;
|
|
15
15
|
|
package/dist/index.js
CHANGED
|
@@ -26,8 +26,8 @@ var CONVERSATIONAL_FLOW = {
|
|
|
26
26
|
|
|
27
27
|
// src/flows/scheduling.ts
|
|
28
28
|
var FORM_DIRECTIVE_FLOW = {
|
|
29
|
-
name: "Form Flow",
|
|
30
|
-
description: "Returns
|
|
29
|
+
name: "Dynamic Form Flow",
|
|
30
|
+
description: "Returns dynamic forms as component directives",
|
|
31
31
|
steps: [
|
|
32
32
|
{
|
|
33
33
|
id: "form_prompt",
|
|
@@ -40,8 +40,44 @@ var FORM_DIRECTIVE_FLOW = {
|
|
|
40
40
|
responseFormat: "JSON",
|
|
41
41
|
outputVariable: "prompt_result",
|
|
42
42
|
userPrompt: "{{user_message}}",
|
|
43
|
-
systemPrompt: `You are a helpful
|
|
44
|
-
|
|
43
|
+
systemPrompt: `You are a helpful assistant that can have conversations and collect user information via forms.
|
|
44
|
+
|
|
45
|
+
RESPONSE FORMAT:
|
|
46
|
+
Always respond with valid JSON. Choose the appropriate format:
|
|
47
|
+
|
|
48
|
+
1. For CONVERSATIONAL responses or text answers:
|
|
49
|
+
{"text": "Your response here"}
|
|
50
|
+
|
|
51
|
+
2. When the user wants to SCHEDULE, BOOK, SIGN UP, or provide DETAILS (show a form):
|
|
52
|
+
{"component": "DynamicForm", "props": {"title": "Form Title", "description": "Optional description", "fields": [...], "submit_text": "Submit"}}
|
|
53
|
+
|
|
54
|
+
3. For BOTH explanation AND form:
|
|
55
|
+
{"text": "Your explanation", "component": "DynamicForm", "props": {...}}
|
|
56
|
+
|
|
57
|
+
FORM FIELD FORMAT:
|
|
58
|
+
Each field in the "fields" array should have:
|
|
59
|
+
- label (required): Display name for the field
|
|
60
|
+
- name (optional): Field identifier (defaults to lowercase label with underscores)
|
|
61
|
+
- type (optional): "text", "email", "tel", "date", "time", "textarea", "number" (defaults to "text")
|
|
62
|
+
- placeholder (optional): Placeholder text
|
|
63
|
+
- required (optional): true/false
|
|
64
|
+
|
|
65
|
+
EXAMPLES:
|
|
66
|
+
|
|
67
|
+
User: "Schedule a demo for me"
|
|
68
|
+
Response: {"text": "I'd be happy to help you schedule a demo! Please fill out the form below:", "component": "DynamicForm", "props": {"title": "Schedule a Demo", "description": "Share your details and we'll follow up with a confirmation.", "fields": [{"label": "Full Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Company", "type": "text"}, {"label": "Preferred Date", "type": "date", "required": true}, {"label": "Notes", "type": "textarea", "placeholder": "Any specific topics you'd like to cover?"}], "submit_text": "Request Demo"}}
|
|
69
|
+
|
|
70
|
+
User: "What is AI?"
|
|
71
|
+
Response: {"text": "AI (Artificial Intelligence) refers to computer systems designed to perform tasks that typically require human intelligence, such as learning, reasoning, problem-solving, and understanding language."}
|
|
72
|
+
|
|
73
|
+
User: "Collect my contact details"
|
|
74
|
+
Response: {"component": "DynamicForm", "props": {"title": "Contact Details", "fields": [{"label": "Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Phone", "type": "tel"}], "submit_text": "Save Details"}}
|
|
75
|
+
|
|
76
|
+
IMPORTANT:
|
|
77
|
+
- Use {"text": "..."} for questions, explanations, and general conversation
|
|
78
|
+
- Show a DynamicForm when user wants to provide information, schedule, book, or sign up
|
|
79
|
+
- Create contextually appropriate form fields based on what the user is trying to do
|
|
80
|
+
- Keep forms focused with only the relevant fields needed`,
|
|
45
81
|
previousMessages: "{{messages}}"
|
|
46
82
|
}
|
|
47
83
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/scheduling.ts","../src/flows/shopping-assistant.ts","../src/flows/components.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\");\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n \n // Determine the CORS origin to allow\n let corsOrigin: string;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No restrictions - allow any origin (or use the request origin)\n corsOrigin = origin || \"*\";\n } else if (allowedOrigins.includes(origin || \"\")) {\n // Origin is in the allowed list\n corsOrigin = origin || \"*\";\n } else if (isDevelopment && origin) {\n // In development, allow the actual origin even if not in the list\n // This helps with local development where ports might vary\n corsOrigin = origin;\n } else {\n // Production: origin not allowed - reject by not setting CORS headers\n // Return error for preflight, or continue without CORS headers\n if (c.req.method === \"OPTIONS\") {\n return c.json({ error: \"CORS policy violation: origin not allowed\" }, 403);\n }\n // For non-preflight requests, continue but browser will block due to missing CORS headers\n await next();\n return;\n }\n\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsOrigin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n id: flowId\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Scheduling flow configuration\n * This flow returns a form to test rendering using post processing:\n */\nexport const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {\n name: \"Form Flow\",\n description: \"Returns Form for rendering in chat\",\n steps: [\n {\n id: \"form_prompt\",\n name: \"Form Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful scheduling assistant.\nWhen the user provides scheduling details, respond with the directive <Form type=\\\"init\\\"/> so the widget can render an interactive form.`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Component-aware flow for custom component rendering\n * This flow instructs the AI to respond with component directives in JSON format\n */\nexport const COMPONENT_FLOW: TravrseFlowConfig = {\n name: \"Component Flow\",\n description: \"Flow configured for custom component rendering\",\n steps: [\n {\n id: \"component_prompt\",\n name: \"Component Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can both have conversations and render custom UI components.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format based on the user's request:\n\n1. For CONVERSATIONAL questions or text responses:\n {\"text\": \"Your response here\"}\n\n2. For VISUAL DISPLAYS or when the user asks to SHOW/DISPLAY something:\n {\"component\": \"ComponentName\", \"props\": {...}}\n\n3. For BOTH explanation AND visual:\n {\"text\": \"Your explanation here\", \"component\": \"ComponentName\", \"props\": {...}}\n\nAvailable components for visual displays:\n- ProductCard: Display product information. Props: title (string), price (number), description (string, optional), image (string, optional)\n- SimpleChart: Display a bar chart. Props: title (string), data (array of numbers), labels (array of strings, optional)\n- StatusBadge: Display a status badge. Props: status (string: \"success\", \"error\", \"warning\", \"info\", \"pending\"), message (string)\n- InfoCard: Display an information card. Props: title (string), content (string), icon (string, optional)\n\nExamples:\n- User asks \"What is the capital of France?\": {\"text\": \"The capital of France is Paris.\"}\n- User asks \"What does that chart show?\": {\"text\": \"The chart shows sales data increasing from 100 to 200 over three months.\"}\n- User asks \"Show me a product card\": {\"component\": \"ProductCard\", \"props\": {\"title\": \"Laptop\", \"price\": 999, \"description\": \"A great laptop\"}}\n- User asks \"Display a chart\": {\"component\": \"SimpleChart\", \"props\": {\"title\": \"Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n- User asks \"Show me a chart and explain it\": {\"text\": \"Here's the sales data for Q1:\", \"component\": \"SimpleChart\", \"props\": {\"title\": \"Q1 Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, discussions, and general chat\n- Use {\"component\": \"...\", \"props\": {...}} ONLY when the user explicitly wants to SEE/VIEW/DISPLAY visual content\n- You can combine both: {\"text\": \"...\", \"component\": \"...\", \"props\": {...}} when you want to explain something AND show a visual\n- Never force a component when the user just wants information`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/flows/conversational.ts","../src/flows/scheduling.ts","../src/flows/shopping-assistant.ts","../src/flows/components.ts","../src/utils/stripe.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport type { Context } from \"hono\";\nimport { handle } from \"hono/vercel\";\n\nexport type TravrseFlowStep = {\n id: string;\n name: string;\n type: string;\n enabled: boolean;\n config: Record<string, unknown>;\n};\n\nexport type TravrseFlowConfig = {\n name: string;\n description: string;\n steps: TravrseFlowStep[];\n};\n\nexport type ChatProxyOptions = {\n upstreamUrl?: string;\n apiKey?: string;\n path?: string;\n allowedOrigins?: string[];\n flowId?: string;\n flowConfig?: TravrseFlowConfig;\n};\n\nconst DEFAULT_ENDPOINT = \"https://api.travrse.ai/v1/dispatch\";\nconst DEFAULT_PATH = \"/api/chat/dispatch\";\n\nconst DEFAULT_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n // model: \"gpt-4o\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n // tools: {\n // tool_ids: [\n // \"builtin:dalle\"\n // ]\n // },\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n\nconst withCors =\n (allowedOrigins: string[] | undefined) =>\n async (c: Context, next: () => Promise<void>) => {\n const origin = c.req.header(\"origin\");\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n \n // Determine the CORS origin to allow\n let corsOrigin: string;\n if (!allowedOrigins || allowedOrigins.length === 0) {\n // No restrictions - allow any origin (or use the request origin)\n corsOrigin = origin || \"*\";\n } else if (allowedOrigins.includes(origin || \"\")) {\n // Origin is in the allowed list\n corsOrigin = origin || \"*\";\n } else if (isDevelopment && origin) {\n // In development, allow the actual origin even if not in the list\n // This helps with local development where ports might vary\n corsOrigin = origin;\n } else {\n // Production: origin not allowed - reject by not setting CORS headers\n // Return error for preflight, or continue without CORS headers\n if (c.req.method === \"OPTIONS\") {\n return c.json({ error: \"CORS policy violation: origin not allowed\" }, 403);\n }\n // For non-preflight requests, continue but browser will block due to missing CORS headers\n await next();\n return;\n }\n\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\": corsOrigin,\n \"Access-Control-Allow-Headers\":\n c.req.header(\"access-control-request-headers\") ??\n \"Content-Type, Authorization\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n Vary: \"Origin\"\n };\n\n if (c.req.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers });\n }\n\n await next();\n Object.entries(headers).forEach(([key, value]) =>\n c.header(key, value, { append: false })\n );\n };\n\nexport const createChatProxyApp = (options: ChatProxyOptions = {}) => {\n const app = new Hono();\n const path = options.path ?? DEFAULT_PATH;\n const upstream = options.upstreamUrl ?? DEFAULT_ENDPOINT;\n\n app.use(\"*\", withCors(options.allowedOrigins));\n\n app.post(path, async (c) => {\n const apiKey = options.apiKey ?? process.env.TRAVRSE_API_KEY;\n if (!apiKey) {\n return c.json(\n { error: \"Missing API key. Set TRAVRSE_API_KEY.\" },\n 401\n );\n }\n\n let clientPayload: {\n messages?: Array<{ role: string; content: string; createdAt?: string }>;\n flowId?: string;\n metadata?: Record<string, unknown>;\n };\n try {\n clientPayload = await c.req.json();\n } catch (error) {\n return c.json(\n { error: \"Invalid JSON body\", details: error },\n 400\n );\n }\n\n // Build the Travrse payload\n const messages = clientPayload.messages ?? [];\n // Sort messages by timestamp to ensure correct order\n const sortedMessages = [...messages].sort((a, b) => {\n const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return timeA - timeB;\n });\n const formattedMessages = sortedMessages.map((message) => ({\n role: message.role,\n content: message.content\n }));\n\n // Determine which flow to use\n const flowId = clientPayload.flowId ?? options.flowId;\n const flowConfig = options.flowConfig ?? DEFAULT_FLOW;\n\n const travrsePayload: Record<string, unknown> = {\n record: {\n name: \"Streaming Chat Widget\",\n type: \"standalone\",\n metadata: clientPayload.metadata || {}\n },\n messages: formattedMessages,\n options: {\n stream_response: true,\n record_mode: \"virtual\",\n flow_mode: flowId ? \"existing\" : \"virtual\",\n auto_append_metadata: false\n }\n };\n\n // Use flow ID if provided, otherwise use flow config\n if (flowId) {\n travrsePayload.flow = {\n id: flowId\n }\n } else {\n travrsePayload.flow = flowConfig;\n }\n\n // Development logging\n const isDevelopment = process.env.NODE_ENV === \"development\" || !process.env.NODE_ENV;\n\n if (isDevelopment) {\n console.log(\"\\n=== Travrse Proxy Request ===\");\n console.log(\"URL:\", upstream);\n console.log(\"API Key Used:\", apiKey ? \"Yes\" : \"No\");\n console.log(\"API Key (first 12 chars):\", apiKey ? apiKey.substring(0, 12) : \"N/A\");\n console.log(\"Request Payload:\", JSON.stringify(travrsePayload, null, 2));\n }\n\n const response = await fetch(upstream, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(travrsePayload)\n });\n\n if (isDevelopment) {\n console.log(\"Response Status:\", response.status);\n console.log(\"Response Status Text:\", response.statusText);\n\n // If there's an error, try to read and log the response body\n if (!response.ok) {\n const clonedResponse = response.clone();\n try {\n const errorBody = await clonedResponse.text();\n console.log(\"Error Response Body:\", errorBody);\n } catch (e) {\n console.log(\"Could not read error response body:\", e);\n }\n }\n console.log(\"=== End Travrse Proxy Request ===\\n\");\n }\n\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"Content-Type\":\n response.headers.get(\"content-type\") ?? \"application/json\",\n \"Cache-Control\": \"no-store\"\n }\n });\n });\n\n return app;\n};\n\nexport const createVercelHandler = (options?: ChatProxyOptions) =>\n handle(createChatProxyApp(options));\n\n// Export pre-configured flows\nexport * from \"./flows/index.js\";\n\n// Export utility functions\nexport * from \"./utils/index.js\";\n\nexport default createChatProxyApp;\n\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Basic conversational assistant flow\n * This is the default flow for simple chat interactions\n */\nexport const CONVERSATIONAL_FLOW: TravrseFlowConfig = {\n name: \"Streaming Prompt Flow\",\n description: \"Streaming chat generated by the widget\",\n steps: [\n {\n id: \"widget_prompt\",\n name: \"Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"meta/llama3.1-8b-instruct-free\",\n response_format: \"markdown\",\n output_variable: \"prompt_result\",\n user_prompt: \"{{user_message}}\",\n system_prompt: \"you are a helpful assistant, chatting with a user\",\n previous_messages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Dynamic Form flow configuration\n * This flow returns forms as component directives for the widget to render\n */\nexport const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {\n name: \"Dynamic Form Flow\",\n description: \"Returns dynamic forms as component directives\",\n steps: [\n {\n id: \"form_prompt\",\n name: \"Form Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can have conversations and collect user information via forms.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format:\n\n1. For CONVERSATIONAL responses or text answers:\n {\"text\": \"Your response here\"}\n\n2. When the user wants to SCHEDULE, BOOK, SIGN UP, or provide DETAILS (show a form):\n {\"component\": \"DynamicForm\", \"props\": {\"title\": \"Form Title\", \"description\": \"Optional description\", \"fields\": [...], \"submit_text\": \"Submit\"}}\n\n3. For BOTH explanation AND form:\n {\"text\": \"Your explanation\", \"component\": \"DynamicForm\", \"props\": {...}}\n\nFORM FIELD FORMAT:\nEach field in the \"fields\" array should have:\n- label (required): Display name for the field\n- name (optional): Field identifier (defaults to lowercase label with underscores)\n- type (optional): \"text\", \"email\", \"tel\", \"date\", \"time\", \"textarea\", \"number\" (defaults to \"text\")\n- placeholder (optional): Placeholder text\n- required (optional): true/false\n\nEXAMPLES:\n\nUser: \"Schedule a demo for me\"\nResponse: {\"text\": \"I'd be happy to help you schedule a demo! Please fill out the form below:\", \"component\": \"DynamicForm\", \"props\": {\"title\": \"Schedule a Demo\", \"description\": \"Share your details and we'll follow up with a confirmation.\", \"fields\": [{\"label\": \"Full Name\", \"type\": \"text\", \"required\": true}, {\"label\": \"Email\", \"type\": \"email\", \"required\": true}, {\"label\": \"Company\", \"type\": \"text\"}, {\"label\": \"Preferred Date\", \"type\": \"date\", \"required\": true}, {\"label\": \"Notes\", \"type\": \"textarea\", \"placeholder\": \"Any specific topics you'd like to cover?\"}], \"submit_text\": \"Request Demo\"}}\n\nUser: \"What is AI?\"\nResponse: {\"text\": \"AI (Artificial Intelligence) refers to computer systems designed to perform tasks that typically require human intelligence, such as learning, reasoning, problem-solving, and understanding language.\"}\n\nUser: \"Collect my contact details\"\nResponse: {\"component\": \"DynamicForm\", \"props\": {\"title\": \"Contact Details\", \"fields\": [{\"label\": \"Name\", \"type\": \"text\", \"required\": true}, {\"label\": \"Email\", \"type\": \"email\", \"required\": true}, {\"label\": \"Phone\", \"type\": \"tel\"}], \"submit_text\": \"Save Details\"}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, and general conversation\n- Show a DynamicForm when user wants to provide information, schedule, book, or sign up\n- Create contextually appropriate form fields based on what the user is trying to do\n- Keep forms focused with only the relevant fields needed`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Shopping assistant flow configuration\n * This flow returns JSON actions for page interaction including:\n * - Simple messages\n * - Navigation with messages\n * - Element clicks with messages\n * - Stripe checkout\n */\nexport const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {\n name: \"Shopping Assistant Flow\",\n description: \"Returns JSON actions for page interaction\",\n steps: [\n {\n id: \"action_prompt\",\n name: \"Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\nYou will receive information about the current page's elements (class names and text content)\nand user messages. You must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names provided in the page context\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n\n/**\n * Metadata-based shopping assistant flow configuration\n * This flow uses DOM context from record metadata instead of user message.\n * The metadata should include dom_elements, dom_body, page_url, and page_title.\n */\nexport const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {\n name: \"Metadata-Based Shopping Assistant\",\n description: \"Uses DOM context from record metadata for page interaction\",\n steps: [\n {\n id: \"metadata_action_prompt\",\n name: \"Metadata Action Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful shopping assistant that can interact with web pages.\n\nIMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:\n- dom_elements: Array of page elements with className, innerText, and tagName\n- dom_body: Complete HTML body of the page (if provided)\n- page_url: Current page URL\n- page_title: Page title\n\nThe dom_elements array provides information about clickable elements and their text content.\nUse this metadata to understand what's available on the page and help users interact with it.\n\nYou must respond with JSON in one of these formats:\n\n1. Simple message:\n{\n \"action\": \"message\",\n \"text\": \"Your response text here\"\n}\n\n2. Navigate then show message (for navigation to another page):\n{\n \"action\": \"nav_then_click\",\n \"page\": \"http://site.com/page-url\",\n \"on_load_text\": \"Message to show after navigation\"\n}\n\n3. Show message and click an element:\n{\n \"action\": \"message_and_click\",\n \"element\": \".className-of-element\",\n \"text\": \"Your message text\"\n}\n\n4. Create Stripe checkout:\n{\n \"action\": \"checkout\",\n \"text\": \"Your message text\",\n \"items\": [\n {\"name\": \"Product Name\", \"price\": 2999, \"quantity\": 1}\n ]\n}\n\nGuidelines:\n- Use \"message\" for simple conversational responses\n- Use \"nav_then_click\" when you need to navigate to a different page (like a product detail page)\n- Use \"message_and_click\" when you want to click a button or element on the current page\n- Use \"checkout\" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)\n- When selecting elements, use the class names from the dom_elements in the metadata\n- Always respond with valid JSON only, no additional text\n- For product searches, format results as markdown links: [Product Name](url)\n- Be helpful and conversational in your messages\n- Product prices: Black Shirt - Medium: $29.99 (2999 cents), Blue Shirt - Large: $34.99 (3499 cents), Red T-Shirt - Small: $19.99 (1999 cents), Jeans - Medium: $49.99 (4999 cents)\n\nExample conversation flow:\n- User: \"I am looking for a black shirt in medium\"\n- You: {\"action\": \"message\", \"text\": \"Here are the products I found:\\\\n1. [Black Shirt - Medium](/products.html?product=black-shirt-medium) - $29.99\\\\n2. [Blue Shirt - Large](/products.html?product=blue-shirt-large) - $34.99\\\\n3. [Red T-Shirt - Small](/products.html?product=red-tshirt-small) - $19.99\\\\n4. [Jeans - Medium](/products.html?product=jeans-medium) - $49.99\\\\n\\\\nWould you like me to navigate to the first result and add it to your cart?\"}\n\n- User: \"No, I would like to add another shirt to the cart\"\n- You: {\"action\": \"message_and_click\", \"element\": \".AddToCartButton-blue-shirt-large\", \"text\": \"I've added the Blue Shirt - Large to your cart. Ready to checkout?\"}\n\n- User: \"yes\"\n- You: {\"action\": \"checkout\", \"text\": \"Perfect! I'll set up the checkout for you.\", \"items\": [{\"name\": \"Black Shirt - Medium\", \"price\": 2999, \"quantity\": 1}]}`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","import type { TravrseFlowConfig } from \"../index.js\";\n\n/**\n * Component-aware flow for custom component rendering\n * This flow instructs the AI to respond with component directives in JSON format\n */\nexport const COMPONENT_FLOW: TravrseFlowConfig = {\n name: \"Component Flow\",\n description: \"Flow configured for custom component rendering\",\n steps: [\n {\n id: \"component_prompt\",\n name: \"Component Prompt\",\n type: \"prompt\",\n enabled: true,\n config: {\n model: \"qwen/qwen3-8b\",\n reasoning: false,\n responseFormat: \"JSON\",\n outputVariable: \"prompt_result\",\n userPrompt: \"{{user_message}}\",\n systemPrompt: `You are a helpful assistant that can both have conversations and render custom UI components.\n\nRESPONSE FORMAT:\nAlways respond with valid JSON. Choose the appropriate format based on the user's request:\n\n1. For CONVERSATIONAL questions or text responses:\n {\"text\": \"Your response here\"}\n\n2. For VISUAL DISPLAYS or when the user asks to SHOW/DISPLAY something:\n {\"component\": \"ComponentName\", \"props\": {...}}\n\n3. For BOTH explanation AND visual:\n {\"text\": \"Your explanation here\", \"component\": \"ComponentName\", \"props\": {...}}\n\nAvailable components for visual displays:\n- ProductCard: Display product information. Props: title (string), price (number), description (string, optional), image (string, optional)\n- SimpleChart: Display a bar chart. Props: title (string), data (array of numbers), labels (array of strings, optional)\n- StatusBadge: Display a status badge. Props: status (string: \"success\", \"error\", \"warning\", \"info\", \"pending\"), message (string)\n- InfoCard: Display an information card. Props: title (string), content (string), icon (string, optional)\n\nExamples:\n- User asks \"What is the capital of France?\": {\"text\": \"The capital of France is Paris.\"}\n- User asks \"What does that chart show?\": {\"text\": \"The chart shows sales data increasing from 100 to 200 over three months.\"}\n- User asks \"Show me a product card\": {\"component\": \"ProductCard\", \"props\": {\"title\": \"Laptop\", \"price\": 999, \"description\": \"A great laptop\"}}\n- User asks \"Display a chart\": {\"component\": \"SimpleChart\", \"props\": {\"title\": \"Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n- User asks \"Show me a chart and explain it\": {\"text\": \"Here's the sales data for Q1:\", \"component\": \"SimpleChart\", \"props\": {\"title\": \"Q1 Sales\", \"data\": [100, 150, 200], \"labels\": [\"Jan\", \"Feb\", \"Mar\"]}}\n\nIMPORTANT:\n- Use {\"text\": \"...\"} for questions, explanations, discussions, and general chat\n- Use {\"component\": \"...\", \"props\": {...}} ONLY when the user explicitly wants to SEE/VIEW/DISPLAY visual content\n- You can combine both: {\"text\": \"...\", \"component\": \"...\", \"props\": {...}} when you want to explain something AND show a visual\n- Never force a component when the user just wants information`,\n previousMessages: \"{{messages}}\"\n }\n }\n ]\n};\n","/**\n * Stripe checkout helpers using the REST API\n * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.\n */\n\nexport interface CheckoutItem {\n name: string;\n price: number; // Price in cents\n quantity: number;\n}\n\nexport interface CreateCheckoutSessionOptions {\n secretKey: string;\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n}\n\nexport interface CheckoutSessionResponse {\n success: boolean;\n checkoutUrl?: string;\n sessionId?: string;\n error?: string;\n}\n\n/**\n * Creates a Stripe checkout session using the REST API\n * @param options - Checkout session configuration\n * @returns Checkout session response with URL and session ID\n */\nexport async function createCheckoutSession(\n options: CreateCheckoutSessionOptions\n): Promise<CheckoutSessionResponse> {\n const { secretKey, items, successUrl, cancelUrl } = options;\n\n try {\n // Validate items\n if (!items || !Array.isArray(items) || items.length === 0) {\n return {\n success: false,\n error: \"Items array is required\"\n };\n }\n\n for (const item of items) {\n if (!item.name || typeof item.price !== \"number\" || typeof item.quantity !== \"number\") {\n return {\n success: false,\n error: \"Each item must have name (string), price (number in cents), and quantity (number)\"\n };\n }\n }\n\n // Build line items for URL encoding\n const lineItems = items.map((item) => ({\n price_data: {\n currency: \"usd\",\n product_data: {\n name: item.name,\n },\n unit_amount: item.price,\n },\n quantity: item.quantity,\n }));\n\n // Convert line items to URL-encoded format\n const params = new URLSearchParams({\n \"payment_method_types[0]\": \"card\",\n \"mode\": \"payment\",\n \"success_url\": successUrl,\n \"cancel_url\": cancelUrl,\n });\n\n // Add line items to params\n lineItems.forEach((item, index) => {\n params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);\n params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);\n params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());\n params.append(`line_items[${index}][quantity]`, item.quantity.toString());\n });\n\n // Create Stripe checkout session using REST API\n const stripeResponse = await fetch(\"https://api.stripe.com/v1/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${secretKey}`,\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: params,\n });\n\n if (!stripeResponse.ok) {\n const errorData = await stripeResponse.text();\n console.error(\"Stripe API error:\", errorData);\n return {\n success: false,\n error: \"Failed to create checkout session\"\n };\n }\n\n const session = await stripeResponse.json() as { url: string; id: string };\n\n return {\n success: true,\n checkoutUrl: session.url,\n sessionId: session.id,\n };\n } catch (error) {\n console.error(\"Stripe checkout error:\", error);\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Failed to create checkout session\"\n };\n }\n}\n"],"mappings":"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","names":["_a","_b"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-agent-proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Proxy server for vanilla-agent widget - handles flow configuration and forwards requests to Travrse or other AI backends.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
package/src/flows/scheduling.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { TravrseFlowConfig } from "../index.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* This flow returns
|
|
4
|
+
* Dynamic Form flow configuration
|
|
5
|
+
* This flow returns forms as component directives for the widget to render
|
|
6
6
|
*/
|
|
7
7
|
export const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {
|
|
8
|
-
name: "Form Flow",
|
|
9
|
-
description: "Returns
|
|
8
|
+
name: "Dynamic Form Flow",
|
|
9
|
+
description: "Returns dynamic forms as component directives",
|
|
10
10
|
steps: [
|
|
11
11
|
{
|
|
12
12
|
id: "form_prompt",
|
|
@@ -19,8 +19,44 @@ export const FORM_DIRECTIVE_FLOW: TravrseFlowConfig = {
|
|
|
19
19
|
responseFormat: "JSON",
|
|
20
20
|
outputVariable: "prompt_result",
|
|
21
21
|
userPrompt: "{{user_message}}",
|
|
22
|
-
systemPrompt: `You are a helpful
|
|
23
|
-
|
|
22
|
+
systemPrompt: `You are a helpful assistant that can have conversations and collect user information via forms.
|
|
23
|
+
|
|
24
|
+
RESPONSE FORMAT:
|
|
25
|
+
Always respond with valid JSON. Choose the appropriate format:
|
|
26
|
+
|
|
27
|
+
1. For CONVERSATIONAL responses or text answers:
|
|
28
|
+
{"text": "Your response here"}
|
|
29
|
+
|
|
30
|
+
2. When the user wants to SCHEDULE, BOOK, SIGN UP, or provide DETAILS (show a form):
|
|
31
|
+
{"component": "DynamicForm", "props": {"title": "Form Title", "description": "Optional description", "fields": [...], "submit_text": "Submit"}}
|
|
32
|
+
|
|
33
|
+
3. For BOTH explanation AND form:
|
|
34
|
+
{"text": "Your explanation", "component": "DynamicForm", "props": {...}}
|
|
35
|
+
|
|
36
|
+
FORM FIELD FORMAT:
|
|
37
|
+
Each field in the "fields" array should have:
|
|
38
|
+
- label (required): Display name for the field
|
|
39
|
+
- name (optional): Field identifier (defaults to lowercase label with underscores)
|
|
40
|
+
- type (optional): "text", "email", "tel", "date", "time", "textarea", "number" (defaults to "text")
|
|
41
|
+
- placeholder (optional): Placeholder text
|
|
42
|
+
- required (optional): true/false
|
|
43
|
+
|
|
44
|
+
EXAMPLES:
|
|
45
|
+
|
|
46
|
+
User: "Schedule a demo for me"
|
|
47
|
+
Response: {"text": "I'd be happy to help you schedule a demo! Please fill out the form below:", "component": "DynamicForm", "props": {"title": "Schedule a Demo", "description": "Share your details and we'll follow up with a confirmation.", "fields": [{"label": "Full Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Company", "type": "text"}, {"label": "Preferred Date", "type": "date", "required": true}, {"label": "Notes", "type": "textarea", "placeholder": "Any specific topics you'd like to cover?"}], "submit_text": "Request Demo"}}
|
|
48
|
+
|
|
49
|
+
User: "What is AI?"
|
|
50
|
+
Response: {"text": "AI (Artificial Intelligence) refers to computer systems designed to perform tasks that typically require human intelligence, such as learning, reasoning, problem-solving, and understanding language."}
|
|
51
|
+
|
|
52
|
+
User: "Collect my contact details"
|
|
53
|
+
Response: {"component": "DynamicForm", "props": {"title": "Contact Details", "fields": [{"label": "Name", "type": "text", "required": true}, {"label": "Email", "type": "email", "required": true}, {"label": "Phone", "type": "tel"}], "submit_text": "Save Details"}}
|
|
54
|
+
|
|
55
|
+
IMPORTANT:
|
|
56
|
+
- Use {"text": "..."} for questions, explanations, and general conversation
|
|
57
|
+
- Show a DynamicForm when user wants to provide information, schedule, book, or sign up
|
|
58
|
+
- Create contextually appropriate form fields based on what the user is trying to do
|
|
59
|
+
- Keep forms focused with only the relevant fields needed`,
|
|
24
60
|
previousMessages: "{{messages}}"
|
|
25
61
|
}
|
|
26
62
|
}
|