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.
- package/dist/index.cjs +288 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +283 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/flows/conversational.ts +26 -0
- package/src/flows/index.ts +10 -0
- package/src/flows/scheduling.ts +28 -0
- package/src/flows/shopping-assistant.ts +171 -0
- package/src/index.ts +8 -26
- package/src/utils/index.ts +10 -0
- package/src/utils/stripe.ts +115 -0
|
@@ -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
|
-
|
|
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,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
|
+
}
|