vanilla-agent-proxy 0.2.0 → 1.1.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.
@@ -0,0 +1,171 @@
1
+ import type { TravrseFlowConfig } from "../index.js";
2
+
3
+ /**
4
+ * Shopping assistant flow configuration
5
+ * This flow returns JSON actions for page interaction including:
6
+ * - Simple messages
7
+ * - Navigation with messages
8
+ * - Element clicks with messages
9
+ * - Stripe checkout
10
+ */
11
+ export const SHOPPING_ASSISTANT_FLOW: TravrseFlowConfig = {
12
+ name: "Shopping Assistant Flow",
13
+ description: "Returns JSON actions for page interaction",
14
+ steps: [
15
+ {
16
+ id: "action_prompt",
17
+ name: "Action Prompt",
18
+ type: "prompt",
19
+ enabled: true,
20
+ config: {
21
+ model: "qwen/qwen3-8b",
22
+ reasoning: false,
23
+ responseFormat: "JSON",
24
+ outputVariable: "prompt_result",
25
+ userPrompt: "{{user_message}}",
26
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
27
+ You will receive information about the current page's elements (class names and text content)
28
+ and user messages. You must respond with JSON in one of these formats:
29
+
30
+ 1. Simple message:
31
+ {
32
+ "action": "message",
33
+ "text": "Your response text here"
34
+ }
35
+
36
+ 2. Navigate then show message (for navigation to another page):
37
+ {
38
+ "action": "nav_then_click",
39
+ "page": "http://site.com/page-url",
40
+ "on_load_text": "Message to show after navigation"
41
+ }
42
+
43
+ 3. Show message and click an element:
44
+ {
45
+ "action": "message_and_click",
46
+ "element": ".className-of-element",
47
+ "text": "Your message text"
48
+ }
49
+
50
+ 4. Create Stripe checkout:
51
+ {
52
+ "action": "checkout",
53
+ "text": "Your message text",
54
+ "items": [
55
+ {"name": "Product Name", "price": 2999, "quantity": 1}
56
+ ]
57
+ }
58
+
59
+ Guidelines:
60
+ - Use "message" for simple conversational responses
61
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
62
+ - Use "message_and_click" when you want to click a button or element on the current page
63
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
64
+ - When selecting elements, use the class names provided in the page context
65
+ - Always respond with valid JSON only, no additional text
66
+ - For product searches, format results as markdown links: [Product Name](url)
67
+ - Be helpful and conversational in your messages
68
+ - 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)
69
+
70
+ Example conversation flow:
71
+ - User: "I am looking for a black shirt in medium"
72
+ - 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?"}
73
+
74
+ - User: "No, I would like to add another shirt to the cart"
75
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
76
+
77
+ - User: "yes"
78
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
79
+ previousMessages: "{{messages}}"
80
+ }
81
+ }
82
+ ]
83
+ };
84
+
85
+ /**
86
+ * Metadata-based shopping assistant flow configuration
87
+ * This flow uses DOM context from record metadata instead of user message.
88
+ * The metadata should include dom_elements, dom_body, page_url, and page_title.
89
+ */
90
+ export const SHOPPING_ASSISTANT_METADATA_FLOW: TravrseFlowConfig = {
91
+ name: "Metadata-Based Shopping Assistant",
92
+ description: "Uses DOM context from record metadata for page interaction",
93
+ steps: [
94
+ {
95
+ id: "metadata_action_prompt",
96
+ name: "Metadata Action Prompt",
97
+ type: "prompt",
98
+ enabled: true,
99
+ config: {
100
+ model: "qwen/qwen3-8b",
101
+ reasoning: false,
102
+ responseFormat: "JSON",
103
+ outputVariable: "prompt_result",
104
+ userPrompt: "{{user_message}}",
105
+ systemPrompt: `You are a helpful shopping assistant that can interact with web pages.
106
+
107
+ IMPORTANT: You have access to the current page's DOM elements through the record metadata, which includes:
108
+ - dom_elements: Array of page elements with className, innerText, and tagName
109
+ - dom_body: Complete HTML body of the page (if provided)
110
+ - page_url: Current page URL
111
+ - page_title: Page title
112
+
113
+ The dom_elements array provides information about clickable elements and their text content.
114
+ Use this metadata to understand what's available on the page and help users interact with it.
115
+
116
+ You must respond with JSON in one of these formats:
117
+
118
+ 1. Simple message:
119
+ {
120
+ "action": "message",
121
+ "text": "Your response text here"
122
+ }
123
+
124
+ 2. Navigate then show message (for navigation to another page):
125
+ {
126
+ "action": "nav_then_click",
127
+ "page": "http://site.com/page-url",
128
+ "on_load_text": "Message to show after navigation"
129
+ }
130
+
131
+ 3. Show message and click an element:
132
+ {
133
+ "action": "message_and_click",
134
+ "element": ".className-of-element",
135
+ "text": "Your message text"
136
+ }
137
+
138
+ 4. Create Stripe checkout:
139
+ {
140
+ "action": "checkout",
141
+ "text": "Your message text",
142
+ "items": [
143
+ {"name": "Product Name", "price": 2999, "quantity": 1}
144
+ ]
145
+ }
146
+
147
+ Guidelines:
148
+ - Use "message" for simple conversational responses
149
+ - Use "nav_then_click" when you need to navigate to a different page (like a product detail page)
150
+ - Use "message_and_click" when you want to click a button or element on the current page
151
+ - Use "checkout" when the user wants to proceed to checkout/payment. Include items array with name (string), price (number in cents), and quantity (number)
152
+ - When selecting elements, use the class names from the dom_elements in the metadata
153
+ - Always respond with valid JSON only, no additional text
154
+ - For product searches, format results as markdown links: [Product Name](url)
155
+ - Be helpful and conversational in your messages
156
+ - 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)
157
+
158
+ Example conversation flow:
159
+ - User: "I am looking for a black shirt in medium"
160
+ - 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?"}
161
+
162
+ - User: "No, I would like to add another shirt to the cart"
163
+ - You: {"action": "message_and_click", "element": ".AddToCartButton-blue-shirt-large", "text": "I've added the Blue Shirt - Large to your cart. Ready to checkout?"}
164
+
165
+ - User: "yes"
166
+ - You: {"action": "checkout", "text": "Perfect! I'll set up the checkout for you.", "items": [{"name": "Black Shirt - Medium", "price": 2999, "quantity": 1}]}`,
167
+ previousMessages: "{{messages}}"
168
+ }
169
+ }
170
+ ]
171
+ };
package/src/index.ts CHANGED
@@ -102,6 +102,7 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
102
102
  let clientPayload: {
103
103
  messages?: Array<{ role: string; content: string; createdAt?: string }>;
104
104
  flowId?: string;
105
+ metadata?: Record<string, unknown>;
105
106
  };
106
107
  try {
107
108
  clientPayload = await c.req.json();
@@ -133,7 +134,7 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
133
134
  record: {
134
135
  name: "Streaming Chat Widget",
135
136
  type: "standalone",
136
- metadata: {}
137
+ metadata: clientPayload.metadata || {}
137
138
  },
138
139
  messages: formattedMessages,
139
140
  options: {
@@ -147,31 +148,7 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
147
148
  // Use flow ID if provided, otherwise use flow config
148
149
  if (flowId) {
149
150
  travrsePayload.flow = {
150
- "name": "Chat with 8b",
151
- "description": "Flow with 1 step",
152
- "steps": [
153
- {
154
- "id": "step_01k8wnwpdcferbrq79tzj49aec",
155
- "name": "Prompt 1",
156
- "type": "prompt",
157
- "order": 0,
158
- "enabled": true,
159
- "config": {
160
- "text": "{{user_message}}",
161
- "model": "qwen/qwen3-8b",
162
- // "tools": {
163
- // "tool_ids": [
164
- // "tool_01k8ky2xpjfzybye5ywcmjr379",
165
- // "builtin:firecrawl"
166
- // ]
167
- // },
168
- "reasoning": false,
169
- "user_prompt": "{{user_message}}",
170
- "output_variable": "prompt_result",
171
- "response_format": "JSON"
172
- }
173
- }
174
- ]
151
+ id: flowId
175
152
  }
176
153
  } else {
177
154
  travrsePayload.flow = flowConfig;
@@ -230,6 +207,11 @@ export const createChatProxyApp = (options: ChatProxyOptions = {}) => {
230
207
  export const createVercelHandler = (options?: ChatProxyOptions) =>
231
208
  handle(createChatProxyApp(options));
232
209
 
210
+ // Export pre-configured flows
211
+ export * from "./flows/index.js";
212
+
213
+ // Export utility functions
214
+ export * from "./utils/index.js";
233
215
 
234
216
  export default createChatProxyApp;
235
217
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Utility functions for proxy implementations
3
+ */
4
+
5
+ export {
6
+ createCheckoutSession,
7
+ type CheckoutItem,
8
+ type CreateCheckoutSessionOptions,
9
+ type CheckoutSessionResponse
10
+ } from "./stripe.js";
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Stripe checkout helpers using the REST API
3
+ * This approach works on all platforms including Cloudflare Workers, Vercel Edge, etc.
4
+ */
5
+
6
+ export interface CheckoutItem {
7
+ name: string;
8
+ price: number; // Price in cents
9
+ quantity: number;
10
+ }
11
+
12
+ export interface CreateCheckoutSessionOptions {
13
+ secretKey: string;
14
+ items: CheckoutItem[];
15
+ successUrl: string;
16
+ cancelUrl: string;
17
+ }
18
+
19
+ export interface CheckoutSessionResponse {
20
+ success: boolean;
21
+ checkoutUrl?: string;
22
+ sessionId?: string;
23
+ error?: string;
24
+ }
25
+
26
+ /**
27
+ * Creates a Stripe checkout session using the REST API
28
+ * @param options - Checkout session configuration
29
+ * @returns Checkout session response with URL and session ID
30
+ */
31
+ export async function createCheckoutSession(
32
+ options: CreateCheckoutSessionOptions
33
+ ): Promise<CheckoutSessionResponse> {
34
+ const { secretKey, items, successUrl, cancelUrl } = options;
35
+
36
+ try {
37
+ // Validate items
38
+ if (!items || !Array.isArray(items) || items.length === 0) {
39
+ return {
40
+ success: false,
41
+ error: "Items array is required"
42
+ };
43
+ }
44
+
45
+ for (const item of items) {
46
+ if (!item.name || typeof item.price !== "number" || typeof item.quantity !== "number") {
47
+ return {
48
+ success: false,
49
+ error: "Each item must have name (string), price (number in cents), and quantity (number)"
50
+ };
51
+ }
52
+ }
53
+
54
+ // Build line items for URL encoding
55
+ const lineItems = items.map((item) => ({
56
+ price_data: {
57
+ currency: "usd",
58
+ product_data: {
59
+ name: item.name,
60
+ },
61
+ unit_amount: item.price,
62
+ },
63
+ quantity: item.quantity,
64
+ }));
65
+
66
+ // Convert line items to URL-encoded format
67
+ const params = new URLSearchParams({
68
+ "payment_method_types[0]": "card",
69
+ "mode": "payment",
70
+ "success_url": successUrl,
71
+ "cancel_url": cancelUrl,
72
+ });
73
+
74
+ // Add line items to params
75
+ lineItems.forEach((item, index) => {
76
+ params.append(`line_items[${index}][price_data][currency]`, item.price_data.currency);
77
+ params.append(`line_items[${index}][price_data][product_data][name]`, item.price_data.product_data.name);
78
+ params.append(`line_items[${index}][price_data][unit_amount]`, item.price_data.unit_amount.toString());
79
+ params.append(`line_items[${index}][quantity]`, item.quantity.toString());
80
+ });
81
+
82
+ // Create Stripe checkout session using REST API
83
+ const stripeResponse = await fetch("https://api.stripe.com/v1/checkout/sessions", {
84
+ method: "POST",
85
+ headers: {
86
+ "Authorization": `Bearer ${secretKey}`,
87
+ "Content-Type": "application/x-www-form-urlencoded",
88
+ },
89
+ body: params,
90
+ });
91
+
92
+ if (!stripeResponse.ok) {
93
+ const errorData = await stripeResponse.text();
94
+ console.error("Stripe API error:", errorData);
95
+ return {
96
+ success: false,
97
+ error: "Failed to create checkout session"
98
+ };
99
+ }
100
+
101
+ const session = await stripeResponse.json() as { url: string; id: string };
102
+
103
+ return {
104
+ success: true,
105
+ checkoutUrl: session.url,
106
+ sessionId: session.id,
107
+ };
108
+ } catch (error) {
109
+ console.error("Stripe checkout error:", error);
110
+ return {
111
+ success: false,
112
+ error: error instanceof Error ? error.message : "Failed to create checkout session"
113
+ };
114
+ }
115
+ }