beddel 1.0.6 → 1.0.7
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/README.md +2 -1
- package/dist/agents/{business-analyzer.yaml → google-business/business-analyzer.yaml} +41 -27
- package/dist/agents/index.d.ts +24 -3
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +52 -11
- package/dist/agents/marketing/newsletter-signup.yaml +106 -0
- package/dist/server/handler.js +4 -4
- package/docs/architecture/api-reference.md +194 -11
- package/docs/architecture/components.md +14 -10
- package/docs/architecture/core-workflows.md +1 -0
- package/docs/architecture/source-tree.md +39 -18
- package/docs/prd/requirements.md +1 -1
- package/package.json +2 -2
- package/src/agents/{business-analyzer.yaml → google-business/business-analyzer.yaml} +41 -27
- package/src/agents/index.ts +63 -13
- package/src/agents/marketing/newsletter-signup.yaml +106 -0
- package/src/server/handler.ts +4 -4
- /package/dist/agents/{assistant-bedrock.yaml → chat/assistant-bedrock.yaml} +0 -0
- /package/dist/agents/{assistant-openrouter.yaml → chat/assistant-openrouter.yaml} +0 -0
- /package/dist/agents/{assistant.yaml → chat/assistant.yaml} +0 -0
- /package/dist/agents/{multi-step-assistant.yaml → examples/multi-step-assistant.yaml} +0 -0
- /package/dist/agents/{assistant-gitmcp.yaml → mcp/assistant-gitmcp.yaml} +0 -0
- /package/dist/agents/{text-generator.yaml → utility/text-generator.yaml} +0 -0
- /package/src/agents/{assistant-bedrock.yaml → chat/assistant-bedrock.yaml} +0 -0
- /package/src/agents/{assistant-openrouter.yaml → chat/assistant-openrouter.yaml} +0 -0
- /package/src/agents/{assistant.yaml → chat/assistant.yaml} +0 -0
- /package/src/agents/{multi-step-assistant.yaml → examples/multi-step-assistant.yaml} +0 -0
- /package/src/agents/{assistant-gitmcp.yaml → mcp/assistant-gitmcp.yaml} +0 -0
- /package/src/agents/{text-generator.yaml → utility/text-generator.yaml} +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Beddel Protocol
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
|
-
[](https://www.npmjs.com/package/beddel)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
[](https://sdk.vercel.ai/)
|
|
7
7
|
|
|
@@ -236,6 +236,7 @@ workflow:
|
|
|
236
236
|
|---------|-------------|---------|
|
|
237
237
|
| `$input.*` | Access request input | `$input.messages` |
|
|
238
238
|
| `$stepResult.varName.*` | Access step result | `$stepResult.llmOutput.text` |
|
|
239
|
+
| `$env.*` | Access environment variables | `$env.NOTION_DATABASE_ID` |
|
|
239
240
|
|
|
240
241
|
## Built-in Tools
|
|
241
242
|
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
metadata:
|
|
15
15
|
name: "Business Analyzer"
|
|
16
|
-
version: "1.
|
|
16
|
+
version: "1.1.0"
|
|
17
17
|
description: "Analyzes business reviews and generates actionable insights"
|
|
18
|
+
builtin: true
|
|
18
19
|
|
|
19
20
|
workflow:
|
|
20
21
|
# Step 1: Fetch all reviews with auto-pagination
|
|
@@ -46,20 +47,28 @@ workflow:
|
|
|
46
47
|
5. Trend analysis comparing recent vs older reviews
|
|
47
48
|
6. Actionable recommendations
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
Return ONLY valid JSON (no markdown, no ```):
|
|
51
|
+
{
|
|
52
|
+
"sentimentScore": 8,
|
|
53
|
+
"positiveThemes": [{"theme": "Great service", "count": 15}],
|
|
54
|
+
"improvementAreas": [{"area": "Wait times", "count": 5}],
|
|
55
|
+
"urgentReviews": [{"reviewId": "xxx", "rating": 1, "issue": "summary"}],
|
|
56
|
+
"trendAnalysis": "Recent reviews show improvement...",
|
|
57
|
+
"recommendations": ["Focus on...", "Consider..."]
|
|
58
|
+
}
|
|
50
59
|
messages:
|
|
51
60
|
- role: "user"
|
|
52
|
-
content:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
content: "$input.reviewsPayload"
|
|
62
|
+
result: "analysisRaw"
|
|
63
|
+
|
|
64
|
+
# Step 3: Parse analysis JSON
|
|
65
|
+
- id: "parse-analysis"
|
|
66
|
+
type: "output-generator"
|
|
67
|
+
config:
|
|
68
|
+
json: "$stepResult.analysisRaw.text"
|
|
60
69
|
result: "analysis"
|
|
61
70
|
|
|
62
|
-
# Step
|
|
71
|
+
# Step 4: Generate response suggestions for negative reviews
|
|
63
72
|
- id: "generate-responses"
|
|
64
73
|
type: "llm"
|
|
65
74
|
config:
|
|
@@ -76,24 +85,29 @@ workflow:
|
|
|
76
85
|
- Keep responses under 150 words
|
|
77
86
|
- Be specific to the complaint mentioned
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
Return ONLY valid JSON array (no markdown, no ```):
|
|
89
|
+
[{"reviewId": "xxx", "rating": 2, "originalComment": "...", "suggestedResponse": "..."}]
|
|
90
|
+
|
|
91
|
+
If no negative reviews, return: []
|
|
80
92
|
messages:
|
|
81
93
|
- role: "user"
|
|
82
|
-
content:
|
|
83
|
-
|
|
84
|
-
$stepResult.reviewsData.reviews
|
|
85
|
-
result: "responseSuggestions"
|
|
94
|
+
content: "$input.reviewsPayload"
|
|
95
|
+
result: "responsesRaw"
|
|
86
96
|
|
|
87
|
-
# Step
|
|
88
|
-
- id: "
|
|
97
|
+
# Step 5: Parse responses JSON
|
|
98
|
+
- id: "parse-responses"
|
|
89
99
|
type: "output-generator"
|
|
90
100
|
config:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
json: "$stepResult.responsesRaw.text"
|
|
102
|
+
result: "responseSuggestions"
|
|
103
|
+
|
|
104
|
+
# Explicit Return: Define the API response contract
|
|
105
|
+
return:
|
|
106
|
+
success: true
|
|
107
|
+
summary:
|
|
108
|
+
totalReviews: "$stepResult.reviewsData.totalReviewCount"
|
|
109
|
+
averageRating: "$stepResult.reviewsData.averageRating"
|
|
110
|
+
pagesFetched: "$stepResult.reviewsData.data.pagesFetched"
|
|
111
|
+
analysis: "$stepResult.analysis"
|
|
112
|
+
responseSuggestions: "$stepResult.responseSuggestions"
|
|
113
|
+
reviews: "$stepResult.reviewsData.reviews"
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Lists all agents bundled with the beddel package.
|
|
5
5
|
* These are available automatically without user configuration.
|
|
6
|
+
*
|
|
7
|
+
* Agents are organized by category:
|
|
8
|
+
* - chat/ Streaming chat assistants (different providers)
|
|
9
|
+
* - mcp/ MCP server integrations (GitMCP, Context7, etc.)
|
|
10
|
+
* - google-business/ Google Business Profile agents
|
|
11
|
+
* - marketing/ Lead capture, newsletters, CRM
|
|
12
|
+
* - utility/ General-purpose tools
|
|
13
|
+
* - examples/ Demo pipelines showing multi-step workflows
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Built-in agent definitions with their category paths
|
|
6
17
|
*/
|
|
18
|
+
export declare const BUILTIN_AGENT_PATHS: Record<string, string>;
|
|
7
19
|
/**
|
|
8
20
|
* List of built-in agent IDs available in the package
|
|
9
21
|
*/
|
|
10
|
-
export declare const BUILTIN_AGENTS: readonly [
|
|
11
|
-
export type BuiltinAgentId = typeof
|
|
22
|
+
export declare const BUILTIN_AGENTS: readonly string[];
|
|
23
|
+
export type BuiltinAgentId = keyof typeof BUILTIN_AGENT_PATHS;
|
|
12
24
|
/**
|
|
13
25
|
* Get the absolute path to the built-in agents directory
|
|
14
26
|
*/
|
|
@@ -20,5 +32,14 @@ export declare function isBuiltinAgent(agentId: string): agentId is BuiltinAgent
|
|
|
20
32
|
/**
|
|
21
33
|
* Get the full path to a built-in agent YAML file
|
|
22
34
|
*/
|
|
23
|
-
export declare function getBuiltinAgentPath(agentId:
|
|
35
|
+
export declare function getBuiltinAgentPath(agentId: string): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Get all agents in a specific category
|
|
38
|
+
*/
|
|
39
|
+
export declare function getAgentsByCategory(category: string): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Available categories
|
|
42
|
+
*/
|
|
43
|
+
export declare const AGENT_CATEGORIES: readonly ["chat", "mcp", "google-business", "marketing", "utility", "examples"];
|
|
44
|
+
export type AgentCategory = typeof AGENT_CATEGORIES[number];
|
|
24
45
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoBtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAuC,SAAS,MAAM,EAAE,CAAC;AAEpF,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAE9D;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,IAAI,cAAc,CAEzE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIlE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9D;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,iFAOnB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/agents/index.js
CHANGED
|
@@ -3,24 +3,43 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Lists all agents bundled with the beddel package.
|
|
5
5
|
* These are available automatically without user configuration.
|
|
6
|
+
*
|
|
7
|
+
* Agents are organized by category:
|
|
8
|
+
* - chat/ Streaming chat assistants (different providers)
|
|
9
|
+
* - mcp/ MCP server integrations (GitMCP, Context7, etc.)
|
|
10
|
+
* - google-business/ Google Business Profile agents
|
|
11
|
+
* - marketing/ Lead capture, newsletters, CRM
|
|
12
|
+
* - utility/ General-purpose tools
|
|
13
|
+
* - examples/ Demo pipelines showing multi-step workflows
|
|
6
14
|
*/
|
|
7
15
|
import { fileURLToPath } from 'url';
|
|
8
16
|
import { dirname, join } from 'path';
|
|
9
17
|
// Get the directory where built-in agents are located
|
|
10
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
19
|
const __dirname = dirname(__filename);
|
|
20
|
+
/**
|
|
21
|
+
* Built-in agent definitions with their category paths
|
|
22
|
+
*/
|
|
23
|
+
export const BUILTIN_AGENT_PATHS = {
|
|
24
|
+
// Chat assistants
|
|
25
|
+
'assistant': 'chat/assistant.yaml',
|
|
26
|
+
'assistant-bedrock': 'chat/assistant-bedrock.yaml',
|
|
27
|
+
'assistant-openrouter': 'chat/assistant-openrouter.yaml',
|
|
28
|
+
// MCP integrations
|
|
29
|
+
'assistant-gitmcp': 'mcp/assistant-gitmcp.yaml',
|
|
30
|
+
// Google Business
|
|
31
|
+
'business-analyzer': 'google-business/business-analyzer.yaml',
|
|
32
|
+
// Marketing
|
|
33
|
+
'newsletter-signup': 'marketing/newsletter-signup.yaml',
|
|
34
|
+
// Utility
|
|
35
|
+
'text-generator': 'utility/text-generator.yaml',
|
|
36
|
+
// Examples
|
|
37
|
+
'multi-step-assistant': 'examples/multi-step-assistant.yaml',
|
|
38
|
+
};
|
|
12
39
|
/**
|
|
13
40
|
* List of built-in agent IDs available in the package
|
|
14
41
|
*/
|
|
15
|
-
export const BUILTIN_AGENTS =
|
|
16
|
-
'assistant',
|
|
17
|
-
'assistant-bedrock',
|
|
18
|
-
'assistant-openrouter',
|
|
19
|
-
'assistant-gitmcp',
|
|
20
|
-
'text-generator',
|
|
21
|
-
'multi-step-assistant',
|
|
22
|
-
'business-analyzer',
|
|
23
|
-
];
|
|
42
|
+
export const BUILTIN_AGENTS = Object.keys(BUILTIN_AGENT_PATHS);
|
|
24
43
|
/**
|
|
25
44
|
* Get the absolute path to the built-in agents directory
|
|
26
45
|
*/
|
|
@@ -31,11 +50,33 @@ export function getBuiltinAgentsPath() {
|
|
|
31
50
|
* Check if an agent ID is a built-in agent
|
|
32
51
|
*/
|
|
33
52
|
export function isBuiltinAgent(agentId) {
|
|
34
|
-
return
|
|
53
|
+
return agentId in BUILTIN_AGENT_PATHS;
|
|
35
54
|
}
|
|
36
55
|
/**
|
|
37
56
|
* Get the full path to a built-in agent YAML file
|
|
38
57
|
*/
|
|
39
58
|
export function getBuiltinAgentPath(agentId) {
|
|
40
|
-
|
|
59
|
+
const relativePath = BUILTIN_AGENT_PATHS[agentId];
|
|
60
|
+
if (!relativePath)
|
|
61
|
+
return null;
|
|
62
|
+
return join(__dirname, relativePath);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all agents in a specific category
|
|
66
|
+
*/
|
|
67
|
+
export function getAgentsByCategory(category) {
|
|
68
|
+
return Object.entries(BUILTIN_AGENT_PATHS)
|
|
69
|
+
.filter(([_, path]) => path.startsWith(`${category}/`))
|
|
70
|
+
.map(([id]) => id);
|
|
41
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Available categories
|
|
74
|
+
*/
|
|
75
|
+
export const AGENT_CATEGORIES = [
|
|
76
|
+
'chat',
|
|
77
|
+
'mcp',
|
|
78
|
+
'google-business',
|
|
79
|
+
'marketing',
|
|
80
|
+
'utility',
|
|
81
|
+
'examples',
|
|
82
|
+
];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Newsletter Signup Agent
|
|
2
|
+
# Registers users to the newsletter with AI analysis and saves to Notion
|
|
3
|
+
#
|
|
4
|
+
# Required Environment Variables:
|
|
5
|
+
# - NOTION_TOKEN (Internal Integration Secret)
|
|
6
|
+
# - NOTION_DATABASE_ID (Database ID for newsletter signups)
|
|
7
|
+
# - GEMINI_API_KEY (for AI analysis)
|
|
8
|
+
#
|
|
9
|
+
# Input:
|
|
10
|
+
# - name: User's name
|
|
11
|
+
# - email: User's email
|
|
12
|
+
# - message: Optional message from user
|
|
13
|
+
# - createdAt: ISO date string
|
|
14
|
+
|
|
15
|
+
metadata:
|
|
16
|
+
name: "Newsletter Signup Agent"
|
|
17
|
+
version: "1.3.0"
|
|
18
|
+
description: "Registers users to the newsletter with AI analysis and saves to Notion"
|
|
19
|
+
builtin: true
|
|
20
|
+
|
|
21
|
+
workflow:
|
|
22
|
+
# Step 1: Analyze user profile and generate structured JSON
|
|
23
|
+
- id: "analyze-user"
|
|
24
|
+
type: "llm"
|
|
25
|
+
config:
|
|
26
|
+
provider: "google"
|
|
27
|
+
model: "gemini-2.0-flash-exp"
|
|
28
|
+
system: |
|
|
29
|
+
You are a lead analyst for a technology newsletter.
|
|
30
|
+
|
|
31
|
+
Analyze the user data and return ONLY a valid JSON (no markdown, no ```):
|
|
32
|
+
{
|
|
33
|
+
"tags": [{"name": "Tag1"}],
|
|
34
|
+
"sentiment": {"name": "Positive"},
|
|
35
|
+
"summary": "One-line summary"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
IMPORTANT RULES:
|
|
39
|
+
- tags: Array of objects with "name". Allowed values: "Support", "Sales", "Partnership", "Feedback"
|
|
40
|
+
- sentiment: Object with "name". Allowed values: "Positive", "Neutral", "Negative"
|
|
41
|
+
- summary: Short summary string (maximum 100 characters)
|
|
42
|
+
|
|
43
|
+
Example for a positive message about the product:
|
|
44
|
+
{"tags": [{"name": "Feedback"}], "sentiment": {"name": "Positive"}, "summary": "User praises the product"}
|
|
45
|
+
|
|
46
|
+
If there is no significant message:
|
|
47
|
+
{"tags": [{"name": "Feedback"}], "sentiment": {"name": "Neutral"}, "summary": "New newsletter subscriber"}
|
|
48
|
+
|
|
49
|
+
Return ONLY the JSON, nothing else.
|
|
50
|
+
messages:
|
|
51
|
+
- role: "user"
|
|
52
|
+
content: |
|
|
53
|
+
Name: $input.name
|
|
54
|
+
Email: $input.email
|
|
55
|
+
Message: $input.message
|
|
56
|
+
result: "userAnalysis"
|
|
57
|
+
|
|
58
|
+
# Step 2: Parse the JSON from LLM
|
|
59
|
+
- id: "parse-analysis"
|
|
60
|
+
type: "output-generator"
|
|
61
|
+
config:
|
|
62
|
+
json: "$stepResult.userAnalysis.text"
|
|
63
|
+
result: "parsedAnalysis"
|
|
64
|
+
|
|
65
|
+
# Step 3: Create Notion page with structured data
|
|
66
|
+
- id: "create-notion-entry"
|
|
67
|
+
type: "notion"
|
|
68
|
+
config:
|
|
69
|
+
action: "createPage"
|
|
70
|
+
parent:
|
|
71
|
+
type: "database_id"
|
|
72
|
+
database_id: "$env.NOTION_DATABASE_ID"
|
|
73
|
+
properties:
|
|
74
|
+
Name:
|
|
75
|
+
title:
|
|
76
|
+
- text:
|
|
77
|
+
content: "$input.name"
|
|
78
|
+
Email:
|
|
79
|
+
email: "$input.email"
|
|
80
|
+
Message:
|
|
81
|
+
rich_text:
|
|
82
|
+
- text:
|
|
83
|
+
content: "$input.message"
|
|
84
|
+
Summary:
|
|
85
|
+
rich_text:
|
|
86
|
+
- text:
|
|
87
|
+
content: "$stepResult.parsedAnalysis.summary"
|
|
88
|
+
Tags:
|
|
89
|
+
multi_select: "$stepResult.parsedAnalysis.tags"
|
|
90
|
+
Sentiment:
|
|
91
|
+
select: "$stepResult.parsedAnalysis.sentiment"
|
|
92
|
+
CreatedAt:
|
|
93
|
+
date:
|
|
94
|
+
start: "$input.createdAt"
|
|
95
|
+
result: "notionResult"
|
|
96
|
+
|
|
97
|
+
# Explicit Return: Define the API response contract
|
|
98
|
+
return:
|
|
99
|
+
success: true
|
|
100
|
+
message: "Registration completed successfully!"
|
|
101
|
+
notionPageId: "$stepResult.notionResult.pageId"
|
|
102
|
+
notionUrl: "$stepResult.notionResult.url"
|
|
103
|
+
analysis:
|
|
104
|
+
tags: "$stepResult.parsedAnalysis.tags"
|
|
105
|
+
sentiment: "$stepResult.parsedAnalysis.sentiment"
|
|
106
|
+
summary: "$stepResult.parsedAnalysis.summary"
|
package/dist/server/handler.js
CHANGED
|
@@ -2,7 +2,7 @@ import { loadYaml } from '../core/parser';
|
|
|
2
2
|
import { WorkflowExecutor } from '../core/workflow';
|
|
3
3
|
import { join, normalize } from 'path';
|
|
4
4
|
import { access } from 'fs/promises';
|
|
5
|
-
import {
|
|
5
|
+
import { getBuiltinAgentPath } from '../agents';
|
|
6
6
|
/**
|
|
7
7
|
* Validate agentId to prevent path traversal attacks.
|
|
8
8
|
* Only allows alphanumeric characters, hyphens, and underscores.
|
|
@@ -39,10 +39,10 @@ async function resolveAgentPath(agentId, userAgentsPath, disableBuiltinAgents) {
|
|
|
39
39
|
if (userPath.startsWith(basePath) && await fileExists(userPath)) {
|
|
40
40
|
return userPath;
|
|
41
41
|
}
|
|
42
|
-
// 2. Fallback: built-in agents from package
|
|
42
|
+
// 2. Fallback: built-in agents from package (supports subfolder structure)
|
|
43
43
|
if (!disableBuiltinAgents) {
|
|
44
|
-
const builtinPath =
|
|
45
|
-
if (await fileExists(builtinPath)) {
|
|
44
|
+
const builtinPath = getBuiltinAgentPath(agentId);
|
|
45
|
+
if (builtinPath && await fileExists(builtinPath)) {
|
|
46
46
|
return builtinPath;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# API Reference
|
|
2
2
|
|
|
3
|
-
> **Beddel Protocol v1.0.
|
|
3
|
+
> **Beddel Protocol v1.0.6** — Complete API documentation for all public exports.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ console.log(yaml.metadata.name); // "Streaming Assistant"
|
|
|
31
31
|
|
|
32
32
|
#### `resolveVariables(template: unknown, context: ExecutionContext): unknown`
|
|
33
33
|
|
|
34
|
-
Resolve variable references (`$input.*`, `$stepResult.*`) in templates.
|
|
34
|
+
Resolve variable references (`$input.*`, `$stepResult.*`, `$env.*`) in templates.
|
|
35
35
|
|
|
36
36
|
```typescript
|
|
37
37
|
import { resolveVariables } from 'beddel';
|
|
@@ -81,6 +81,8 @@ Map of primitive step types to their handler functions.
|
|
|
81
81
|
- `output-generator` — Deterministic JSON transform
|
|
82
82
|
- `call-agent` — Sub-agent invocation
|
|
83
83
|
- `mcp-tool` — External MCP server tool execution
|
|
84
|
+
- `google-business` — Google Business Profile API integration
|
|
85
|
+
- `notion` — Notion workspace integration (pages, databases, blocks)
|
|
84
86
|
|
|
85
87
|
#### `toolRegistry: Record<string, ToolImplementation>`
|
|
86
88
|
|
|
@@ -240,6 +242,59 @@ import type {
|
|
|
240
242
|
|
|
241
243
|
---
|
|
242
244
|
|
|
245
|
+
## YAML Workflow Structure
|
|
246
|
+
|
|
247
|
+
### Explicit Return Template
|
|
248
|
+
|
|
249
|
+
The `return` property at the workflow level defines the exact shape of the API response. This provides explicit control over the API contract, separating internal workflow state from the public response.
|
|
250
|
+
|
|
251
|
+
**Without `return`:** API returns all accumulated step variables (internal state exposed)
|
|
252
|
+
|
|
253
|
+
**With `return`:** API returns only the resolved template (clean contract)
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
metadata:
|
|
257
|
+
name: "Newsletter Signup"
|
|
258
|
+
version: "1.0.0"
|
|
259
|
+
|
|
260
|
+
workflow:
|
|
261
|
+
- id: "analyze"
|
|
262
|
+
type: "llm"
|
|
263
|
+
config:
|
|
264
|
+
# ... LLM config ...
|
|
265
|
+
result: "analysis" # Stored internally
|
|
266
|
+
|
|
267
|
+
- id: "save"
|
|
268
|
+
type: "notion"
|
|
269
|
+
config:
|
|
270
|
+
# ... Notion config ...
|
|
271
|
+
result: "notionResult" # Stored internally
|
|
272
|
+
|
|
273
|
+
# Explicit API response shape
|
|
274
|
+
return:
|
|
275
|
+
success: true
|
|
276
|
+
pageId: "$stepResult.notionResult.pageId"
|
|
277
|
+
url: "$stepResult.notionResult.url"
|
|
278
|
+
summary: "$stepResult.analysis.text"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Response:**
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"success": true,
|
|
285
|
+
"pageId": "abc123...",
|
|
286
|
+
"url": "https://notion.so/...",
|
|
287
|
+
"summary": "Analysis text..."
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Return Resolution Order:**
|
|
292
|
+
1. If `return` is defined → resolve and return the template
|
|
293
|
+
2. If last step has no `result` → return last step's output directly
|
|
294
|
+
3. Otherwise → return all accumulated variables
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
243
298
|
## Primitives
|
|
244
299
|
|
|
245
300
|
### `chat` Primitive
|
|
@@ -316,7 +371,16 @@ workflow:
|
|
|
316
371
|
|
|
317
372
|
### `output-generator` Primitive
|
|
318
373
|
|
|
319
|
-
Deterministic JSON transform using variable resolution.
|
|
374
|
+
Deterministic JSON transform using variable resolution. Supports optional JSON parsing from LLM text output.
|
|
375
|
+
|
|
376
|
+
**Config Options:**
|
|
377
|
+
|
|
378
|
+
| Property | Type | Required | Description |
|
|
379
|
+
|----------|------|----------|-------------|
|
|
380
|
+
| `template` | `object` | No | JSON template with variable references |
|
|
381
|
+
| `json` | `string` | No | Variable reference to parse as JSON (e.g., `$stepResult.llmOutput.text`) |
|
|
382
|
+
|
|
383
|
+
**Basic Usage:**
|
|
320
384
|
|
|
321
385
|
```yaml
|
|
322
386
|
workflow:
|
|
@@ -329,6 +393,36 @@ workflow:
|
|
|
329
393
|
result: "finalOutput"
|
|
330
394
|
```
|
|
331
395
|
|
|
396
|
+
**JSON Parsing from LLM Output:**
|
|
397
|
+
|
|
398
|
+
When LLM returns JSON as text, use the `json` parameter to parse it and access fields via `$json.*`:
|
|
399
|
+
|
|
400
|
+
```yaml
|
|
401
|
+
workflow:
|
|
402
|
+
# Step 1: LLM generates JSON
|
|
403
|
+
- id: "analyze"
|
|
404
|
+
type: "llm"
|
|
405
|
+
config:
|
|
406
|
+
system: "Return JSON: {\"tags\": [\"tag1\"], \"sentiment\": \"Positive\"}"
|
|
407
|
+
messages: "$input.messages"
|
|
408
|
+
result: "analysis"
|
|
409
|
+
|
|
410
|
+
# Step 2: Parse JSON and extract fields
|
|
411
|
+
- id: "parse"
|
|
412
|
+
type: "output-generator"
|
|
413
|
+
config:
|
|
414
|
+
json: "$stepResult.analysis.text"
|
|
415
|
+
template:
|
|
416
|
+
tags: "$json.tags"
|
|
417
|
+
sentiment: "$json.sentiment"
|
|
418
|
+
result: "parsed"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The `json` parameter:
|
|
422
|
+
- Extracts JSON from markdown code blocks if present
|
|
423
|
+
- Parses the JSON and makes it available as `$json.*`
|
|
424
|
+
- If no template is provided, returns the parsed JSON directly
|
|
425
|
+
|
|
332
426
|
### `mcp-tool` Primitive
|
|
333
427
|
|
|
334
428
|
Connect to external MCP servers via SSE and execute tools.
|
|
@@ -389,18 +483,102 @@ workflow:
|
|
|
389
483
|
messages: "$input.messages"
|
|
390
484
|
```
|
|
391
485
|
|
|
486
|
+
### `notion` Primitive
|
|
487
|
+
|
|
488
|
+
Integrate with Notion API for pages, databases, blocks, and search.
|
|
489
|
+
|
|
490
|
+
**Environment Variables:**
|
|
491
|
+
- `NOTION_TOKEN` — Internal Integration Secret (starts with `ntn_`)
|
|
492
|
+
|
|
493
|
+
**Supported Actions:**
|
|
494
|
+
|
|
495
|
+
| Action | Description | Required Config |
|
|
496
|
+
|--------|-------------|-----------------|
|
|
497
|
+
| `search` | Search pages and databases | `query?`, `filter?` |
|
|
498
|
+
| `getPage` | Retrieve a page by ID | `pageId` |
|
|
499
|
+
| `createPage` | Create a new page | `parent`, `properties` |
|
|
500
|
+
| `updatePage` | Update page properties | `pageId`, `properties?` |
|
|
501
|
+
| `getDatabase` | Retrieve database schema | `databaseId` |
|
|
502
|
+
| `queryDatabase` | Query database with filters | `databaseId`, `filter?`, `sorts?` |
|
|
503
|
+
| `getBlocks` | Get block children | `blockId` or `pageId` |
|
|
504
|
+
| `appendBlocks` | Append blocks to page/block | `blockId` or `pageId`, `children` |
|
|
505
|
+
| `createDatabase` | Create a new database | `parent`, `properties`, `title?` |
|
|
506
|
+
|
|
507
|
+
**Example:**
|
|
508
|
+
|
|
509
|
+
```yaml
|
|
510
|
+
workflow:
|
|
511
|
+
- id: "create-entry"
|
|
512
|
+
type: "notion"
|
|
513
|
+
config:
|
|
514
|
+
action: "createPage"
|
|
515
|
+
parent:
|
|
516
|
+
type: "database_id"
|
|
517
|
+
database_id: "a7661a0a-c5b7-47a0-98f8-fd07789d1647"
|
|
518
|
+
properties:
|
|
519
|
+
Name:
|
|
520
|
+
title:
|
|
521
|
+
- text:
|
|
522
|
+
content: "$input.name"
|
|
523
|
+
Email:
|
|
524
|
+
email: "$input.email"
|
|
525
|
+
result: "notionResult"
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
> See `packages/beddel/docs/primitives/notion-primitive.md` for full documentation.
|
|
529
|
+
|
|
530
|
+
### `google-business` Primitive
|
|
531
|
+
|
|
532
|
+
Integrate with Google Business Profile APIs for reviews, posts, Q&A, and metrics.
|
|
533
|
+
|
|
534
|
+
**Environment Variables:**
|
|
535
|
+
- `GOOGLE_CLIENT_ID` — OAuth2 Client ID
|
|
536
|
+
- `GOOGLE_CLIENT_SECRET` — OAuth2 Client Secret
|
|
537
|
+
- `GOOGLE_REFRESH_TOKEN` — OAuth2 Refresh Token
|
|
538
|
+
|
|
539
|
+
**Supported Actions:**
|
|
540
|
+
|
|
541
|
+
| Action | Description |
|
|
542
|
+
|--------|-------------|
|
|
543
|
+
| `listReviews` | Fetch reviews with auto-pagination |
|
|
544
|
+
| `replyReview` | Reply to a specific review |
|
|
545
|
+
| `batchGetReviews` | Fetch from multiple locations |
|
|
546
|
+
| `createPost` | Create a local post |
|
|
547
|
+
| `listPosts` | List all posts |
|
|
548
|
+
| `getMetrics` | Fetch performance metrics |
|
|
549
|
+
| `listQuestions` | List Q&A |
|
|
550
|
+
| `answerQuestion` | Answer a question |
|
|
551
|
+
|
|
552
|
+
**Example:**
|
|
553
|
+
|
|
554
|
+
```yaml
|
|
555
|
+
workflow:
|
|
556
|
+
- id: "fetch-reviews"
|
|
557
|
+
type: "google-business"
|
|
558
|
+
config:
|
|
559
|
+
action: "listReviews"
|
|
560
|
+
accountId: "$input.accountId"
|
|
561
|
+
locationId: "$input.locationId"
|
|
562
|
+
pageSize: 100
|
|
563
|
+
result: "reviewsData"
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
> See `packages/beddel/docs/primitives/google-business-primitive.md` for full documentation.
|
|
567
|
+
|
|
392
568
|
---
|
|
393
569
|
|
|
394
570
|
## Built-in Agents
|
|
395
571
|
|
|
396
|
-
| Agent ID | Provider | Description |
|
|
397
|
-
|
|
398
|
-
| `assistant` | Google | Streaming chat assistant |
|
|
399
|
-
| `assistant-bedrock` | Bedrock | Llama 3.2 assistant |
|
|
400
|
-
| `assistant-openrouter` | OpenRouter | Free tier assistant |
|
|
401
|
-
| `assistant-gitmcp` | Google + MCP | Documentation assistant via GitMCP |
|
|
402
|
-
| `
|
|
403
|
-
| `
|
|
572
|
+
| Agent ID | Category | Provider | Description |
|
|
573
|
+
|----------|----------|----------|-------------|
|
|
574
|
+
| `assistant` | `chat/` | Google | Streaming chat assistant |
|
|
575
|
+
| `assistant-bedrock` | `chat/` | Bedrock | Llama 3.2 assistant |
|
|
576
|
+
| `assistant-openrouter` | `chat/` | OpenRouter | Free tier assistant |
|
|
577
|
+
| `assistant-gitmcp` | `mcp/` | Google + MCP | Documentation assistant via GitMCP |
|
|
578
|
+
| `business-analyzer` | `google-business/` | Google | Business reviews analyzer |
|
|
579
|
+
| `newsletter-signup` | `marketing/` | Google | Lead capture with Notion integration |
|
|
580
|
+
| `text-generator` | `utility/` | Google | Text generation (non-streaming) |
|
|
581
|
+
| `multi-step-assistant` | `examples/` | Google | 4-step analysis pipeline |
|
|
404
582
|
|
|
405
583
|
---
|
|
406
584
|
|
|
@@ -412,6 +590,7 @@ workflow:
|
|
|
412
590
|
interface ParsedYaml {
|
|
413
591
|
metadata: YamlMetadata;
|
|
414
592
|
workflow: WorkflowStep[];
|
|
593
|
+
return?: unknown; // Optional explicit return template
|
|
415
594
|
}
|
|
416
595
|
```
|
|
417
596
|
|
|
@@ -456,3 +635,7 @@ type PrimitiveHandler = (
|
|
|
456
635
|
| 2024-12-26 | 1.0.3 | OpenRouter provider, built-in agents |
|
|
457
636
|
| 2024-12-27 | 1.0.4 | Separated `chat` and `llm` primitives, implemented `call-agent` |
|
|
458
637
|
| 2024-12-28 | 1.0.5 | Added `mcp-tool` primitive, `assistant-gitmcp` agent, system prompt variable resolution |
|
|
638
|
+
| 2024-12-30 | 1.0.6 | Added `google-business` primitive for Google Business Profile API |
|
|
639
|
+
| 2026-01-01 | 1.0.7 | Added `notion` primitive for Notion API integration |
|
|
640
|
+
| 2026-01-19 | 1.0.8 | Added `json` parameter to `output-generator`, explicit `return` template support |
|
|
641
|
+
| 2026-01-19 | 1.0.9 | Reorganized built-in agents into category subfolders, added `newsletter-signup` agent |
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
### Variable Resolver (`src/core/variable-resolver.ts`)
|
|
33
33
|
|
|
34
|
-
**Responsibility:** Resolve `$input
|
|
34
|
+
**Responsibility:** Resolve `$input.*`, `$stepResult.*`, and `$env.*` variable references.
|
|
35
35
|
|
|
36
36
|
**Key Interfaces:**
|
|
37
37
|
- `resolveVariables(template: any, context: ExecutionContext): any`
|
|
@@ -249,16 +249,20 @@ This design is cleaner than a `stream: true/false` flag because:
|
|
|
249
249
|
|
|
250
250
|
## Built-in Agents (`src/agents/`)
|
|
251
251
|
|
|
252
|
-
Pre-configured agents bundled with the package:
|
|
252
|
+
Pre-configured agents bundled with the package, organized by category:
|
|
253
253
|
|
|
254
|
-
| Agent | Type | Description |
|
|
255
|
-
|
|
256
|
-
| `assistant
|
|
257
|
-
| `assistant-bedrock
|
|
258
|
-
| `assistant-openrouter
|
|
259
|
-
| `assistant-gitmcp
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
254
|
+
| Agent | Category | Type | Description |
|
|
255
|
+
|-------|----------|------|-------------|
|
|
256
|
+
| `assistant` | `chat/` | `chat` | Google Gemini streaming assistant |
|
|
257
|
+
| `assistant-bedrock` | `chat/` | `chat` | Amazon Bedrock assistant |
|
|
258
|
+
| `assistant-openrouter` | `chat/` | `chat` | OpenRouter free tier assistant |
|
|
259
|
+
| `assistant-gitmcp` | `mcp/` | `mcp-tool` + `chat` | Documentation assistant via GitMCP |
|
|
260
|
+
| `business-analyzer` | `google-business/` | `google-business` + `llm` | Business reviews analyzer |
|
|
261
|
+
| `newsletter-signup` | `marketing/` | `llm` + `notion` | Lead capture with Notion |
|
|
262
|
+
| `text-generator` | `utility/` | `llm` | Text generation (non-streaming) |
|
|
263
|
+
| `multi-step-assistant` | `examples/` | `call-agent` + `llm` | 4-step analysis pipeline |
|
|
264
|
+
|
|
265
|
+
**Categories:** `chat/`, `mcp/`, `google-business/`, `marketing/`, `utility/`, `examples/`
|
|
262
266
|
|
|
263
267
|
---
|
|
264
268
|
|
|
@@ -167,6 +167,7 @@ workflow:
|
|
|
167
167
|
|---------|-------------|---------|
|
|
168
168
|
| `$input.*` | Access request input data | `$input.messages` |
|
|
169
169
|
| `$stepResult.varName.*` | Access step result by name | `$stepResult.llmOutput.text` |
|
|
170
|
+
| `$env.*` | Access environment variables | `$env.NOTION_DATABASE_ID` |
|
|
170
171
|
|
|
171
172
|
---
|
|
172
173
|
|
|
@@ -7,13 +7,21 @@ packages/beddel/
|
|
|
7
7
|
│ ├── server.ts # Server handler barrel export
|
|
8
8
|
│ ├── client.ts # Client exports (types only, browser-safe)
|
|
9
9
|
│ ├── agents/ # Built-in agents (bundled with package)
|
|
10
|
-
│ │ ├── index.ts # Built-in agents registry
|
|
11
|
-
│ │ ├──
|
|
12
|
-
│ │ ├── assistant
|
|
13
|
-
│ │ ├── assistant-
|
|
14
|
-
│ │
|
|
15
|
-
│ │ ├──
|
|
16
|
-
│ │ └── assistant-gitmcp.yaml
|
|
10
|
+
│ │ ├── index.ts # Built-in agents registry (BUILTIN_AGENT_PATHS)
|
|
11
|
+
│ │ ├── chat/ # Streaming chat assistants
|
|
12
|
+
│ │ │ ├── assistant.yaml
|
|
13
|
+
│ │ │ ├── assistant-bedrock.yaml
|
|
14
|
+
│ │ │ └── assistant-openrouter.yaml
|
|
15
|
+
│ │ ├── mcp/ # MCP server integrations
|
|
16
|
+
│ │ │ └── assistant-gitmcp.yaml
|
|
17
|
+
│ │ ├── google-business/ # Google Business Profile agents
|
|
18
|
+
│ │ │ └── business-analyzer.yaml
|
|
19
|
+
│ │ ├── marketing/ # Lead capture, newsletters
|
|
20
|
+
│ │ │ └── newsletter-signup.yaml
|
|
21
|
+
│ │ ├── utility/ # General-purpose tools
|
|
22
|
+
│ │ │ └── text-generator.yaml
|
|
23
|
+
│ │ └── examples/ # Demo pipelines
|
|
24
|
+
│ │ └── multi-step-assistant.yaml
|
|
17
25
|
│ ├── core/
|
|
18
26
|
│ │ ├── parser.ts # YAML parsing (FAILSAFE_SCHEMA)
|
|
19
27
|
│ │ ├── workflow.ts # WorkflowExecutor class
|
|
@@ -86,20 +94,33 @@ primitives/
|
|
|
86
94
|
|
|
87
95
|
## Built-in Agents
|
|
88
96
|
|
|
89
|
-
Agents bundled with the package, available without configuration:
|
|
90
|
-
|
|
91
|
-
|
|
|
92
|
-
|
|
93
|
-
| `assistant
|
|
94
|
-
| `assistant-bedrock
|
|
95
|
-
| `assistant-openrouter
|
|
96
|
-
| `assistant-gitmcp
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
97
|
+
Agents bundled with the package, available without configuration. Organized by category:
|
|
98
|
+
|
|
99
|
+
| Agent ID | Category | Type | Provider | Description |
|
|
100
|
+
|----------|----------|------|----------|-------------|
|
|
101
|
+
| `assistant` | `chat/` | `chat` | Google | Streaming chat assistant |
|
|
102
|
+
| `assistant-bedrock` | `chat/` | `chat` | Bedrock | Llama 3.2 assistant |
|
|
103
|
+
| `assistant-openrouter` | `chat/` | `chat` | OpenRouter | Free tier assistant |
|
|
104
|
+
| `assistant-gitmcp` | `mcp/` | `mcp-tool` + `chat` | Google + MCP | Documentation assistant via GitMCP |
|
|
105
|
+
| `business-analyzer` | `google-business/` | `google-business` + `llm` | Google | Business reviews analyzer |
|
|
106
|
+
| `newsletter-signup` | `marketing/` | `llm` + `notion` | Google | Lead capture with Notion |
|
|
107
|
+
| `text-generator` | `utility/` | `llm` | Google | Text generation |
|
|
108
|
+
| `multi-step-assistant` | `examples/` | `call-agent` + `llm` | Google | 4-step pipeline |
|
|
109
|
+
|
|
110
|
+
**Agent Categories:**
|
|
111
|
+
|
|
112
|
+
| Category | Folder | Description |
|
|
113
|
+
|----------|--------|-------------|
|
|
114
|
+
| Chat | `chat/` | Streaming chat assistants (different providers) |
|
|
115
|
+
| MCP | `mcp/` | MCP server integrations (GitMCP, Context7) |
|
|
116
|
+
| Google Business | `google-business/` | Google Business Profile API agents |
|
|
117
|
+
| Marketing | `marketing/` | Lead capture, newsletters, CRM |
|
|
118
|
+
| Utility | `utility/` | General-purpose tools |
|
|
119
|
+
| Examples | `examples/` | Demo pipelines |
|
|
99
120
|
|
|
100
121
|
**Resolution Order:**
|
|
101
122
|
1. User agents (`src/agents/*.yaml`) — allows override
|
|
102
|
-
2. Built-in agents (package) — fallback
|
|
123
|
+
2. Built-in agents (package, via `BUILTIN_AGENT_PATHS` map) — fallback
|
|
103
124
|
|
|
104
125
|
---
|
|
105
126
|
|
package/docs/prd/requirements.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- `stream: true` → returns `Response` from `streamText`
|
|
9
9
|
- `stream: false` → returns JSON object from `generateText`
|
|
10
10
|
- **FR4:** The executor MUST immediately return a `Response` when a primitive returns a stream
|
|
11
|
-
- **FR5:** The system MUST resolve variables using `$input
|
|
11
|
+
- **FR5:** The system MUST resolve variables using `$input.*`, `$stepResult.*`, and `$env.*` syntax
|
|
12
12
|
- **FR6:** The `output-generator` primitive MUST perform deterministic JSON transformation without LLM calls
|
|
13
13
|
- **FR7:** The `call-agent` primitive MUST allow recursive invocation of other YAML workflow files
|
|
14
14
|
- **FR8:** The system MUST expose a REST endpoint (`POST /api/beddel/chat`) for chat interactions
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beddel",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Declarative Sequential Pipeline Executor for YAML workflows with native streaming and Vercel AI SDK v6 support",
|
|
5
5
|
"author": "Bota na Rede",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsc && npm run copy-agents",
|
|
34
|
-
"copy-agents": "
|
|
34
|
+
"copy-agents": "rsync -av --include='*/' --include='*.yaml' --exclude='*' src/agents/ dist/agents/",
|
|
35
35
|
"dev": "tsc --watch"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
metadata:
|
|
15
15
|
name: "Business Analyzer"
|
|
16
|
-
version: "1.
|
|
16
|
+
version: "1.1.0"
|
|
17
17
|
description: "Analyzes business reviews and generates actionable insights"
|
|
18
|
+
builtin: true
|
|
18
19
|
|
|
19
20
|
workflow:
|
|
20
21
|
# Step 1: Fetch all reviews with auto-pagination
|
|
@@ -46,20 +47,28 @@ workflow:
|
|
|
46
47
|
5. Trend analysis comparing recent vs older reviews
|
|
47
48
|
6. Actionable recommendations
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
Return ONLY valid JSON (no markdown, no ```):
|
|
51
|
+
{
|
|
52
|
+
"sentimentScore": 8,
|
|
53
|
+
"positiveThemes": [{"theme": "Great service", "count": 15}],
|
|
54
|
+
"improvementAreas": [{"area": "Wait times", "count": 5}],
|
|
55
|
+
"urgentReviews": [{"reviewId": "xxx", "rating": 1, "issue": "summary"}],
|
|
56
|
+
"trendAnalysis": "Recent reviews show improvement...",
|
|
57
|
+
"recommendations": ["Focus on...", "Consider..."]
|
|
58
|
+
}
|
|
50
59
|
messages:
|
|
51
60
|
- role: "user"
|
|
52
|
-
content:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
content: "$input.reviewsPayload"
|
|
62
|
+
result: "analysisRaw"
|
|
63
|
+
|
|
64
|
+
# Step 3: Parse analysis JSON
|
|
65
|
+
- id: "parse-analysis"
|
|
66
|
+
type: "output-generator"
|
|
67
|
+
config:
|
|
68
|
+
json: "$stepResult.analysisRaw.text"
|
|
60
69
|
result: "analysis"
|
|
61
70
|
|
|
62
|
-
# Step
|
|
71
|
+
# Step 4: Generate response suggestions for negative reviews
|
|
63
72
|
- id: "generate-responses"
|
|
64
73
|
type: "llm"
|
|
65
74
|
config:
|
|
@@ -76,24 +85,29 @@ workflow:
|
|
|
76
85
|
- Keep responses under 150 words
|
|
77
86
|
- Be specific to the complaint mentioned
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
Return ONLY valid JSON array (no markdown, no ```):
|
|
89
|
+
[{"reviewId": "xxx", "rating": 2, "originalComment": "...", "suggestedResponse": "..."}]
|
|
90
|
+
|
|
91
|
+
If no negative reviews, return: []
|
|
80
92
|
messages:
|
|
81
93
|
- role: "user"
|
|
82
|
-
content:
|
|
83
|
-
|
|
84
|
-
$stepResult.reviewsData.reviews
|
|
85
|
-
result: "responseSuggestions"
|
|
94
|
+
content: "$input.reviewsPayload"
|
|
95
|
+
result: "responsesRaw"
|
|
86
96
|
|
|
87
|
-
# Step
|
|
88
|
-
- id: "
|
|
97
|
+
# Step 5: Parse responses JSON
|
|
98
|
+
- id: "parse-responses"
|
|
89
99
|
type: "output-generator"
|
|
90
100
|
config:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
json: "$stepResult.responsesRaw.text"
|
|
102
|
+
result: "responseSuggestions"
|
|
103
|
+
|
|
104
|
+
# Explicit Return: Define the API response contract
|
|
105
|
+
return:
|
|
106
|
+
success: true
|
|
107
|
+
summary:
|
|
108
|
+
totalReviews: "$stepResult.reviewsData.totalReviewCount"
|
|
109
|
+
averageRating: "$stepResult.reviewsData.averageRating"
|
|
110
|
+
pagesFetched: "$stepResult.reviewsData.data.pagesFetched"
|
|
111
|
+
analysis: "$stepResult.analysis"
|
|
112
|
+
responseSuggestions: "$stepResult.responseSuggestions"
|
|
113
|
+
reviews: "$stepResult.reviewsData.reviews"
|
package/src/agents/index.ts
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Lists all agents bundled with the beddel package.
|
|
5
5
|
* These are available automatically without user configuration.
|
|
6
|
+
*
|
|
7
|
+
* Agents are organized by category:
|
|
8
|
+
* - chat/ Streaming chat assistants (different providers)
|
|
9
|
+
* - mcp/ MCP server integrations (GitMCP, Context7, etc.)
|
|
10
|
+
* - google-business/ Google Business Profile agents
|
|
11
|
+
* - marketing/ Lead capture, newsletters, CRM
|
|
12
|
+
* - utility/ General-purpose tools
|
|
13
|
+
* - examples/ Demo pipelines showing multi-step workflows
|
|
6
14
|
*/
|
|
7
15
|
|
|
8
16
|
import { fileURLToPath } from 'url';
|
|
@@ -12,20 +20,37 @@ import { dirname, join } from 'path';
|
|
|
12
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
21
|
const __dirname = dirname(__filename);
|
|
14
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Built-in agent definitions with their category paths
|
|
25
|
+
*/
|
|
26
|
+
export const BUILTIN_AGENT_PATHS: Record<string, string> = {
|
|
27
|
+
// Chat assistants
|
|
28
|
+
'assistant': 'chat/assistant.yaml',
|
|
29
|
+
'assistant-bedrock': 'chat/assistant-bedrock.yaml',
|
|
30
|
+
'assistant-openrouter': 'chat/assistant-openrouter.yaml',
|
|
31
|
+
|
|
32
|
+
// MCP integrations
|
|
33
|
+
'assistant-gitmcp': 'mcp/assistant-gitmcp.yaml',
|
|
34
|
+
|
|
35
|
+
// Google Business
|
|
36
|
+
'business-analyzer': 'google-business/business-analyzer.yaml',
|
|
37
|
+
|
|
38
|
+
// Marketing
|
|
39
|
+
'newsletter-signup': 'marketing/newsletter-signup.yaml',
|
|
40
|
+
|
|
41
|
+
// Utility
|
|
42
|
+
'text-generator': 'utility/text-generator.yaml',
|
|
43
|
+
|
|
44
|
+
// Examples
|
|
45
|
+
'multi-step-assistant': 'examples/multi-step-assistant.yaml',
|
|
46
|
+
};
|
|
47
|
+
|
|
15
48
|
/**
|
|
16
49
|
* List of built-in agent IDs available in the package
|
|
17
50
|
*/
|
|
18
|
-
export const BUILTIN_AGENTS = [
|
|
19
|
-
'assistant',
|
|
20
|
-
'assistant-bedrock',
|
|
21
|
-
'assistant-openrouter',
|
|
22
|
-
'assistant-gitmcp',
|
|
23
|
-
'text-generator',
|
|
24
|
-
'multi-step-assistant',
|
|
25
|
-
'business-analyzer',
|
|
26
|
-
] as const;
|
|
51
|
+
export const BUILTIN_AGENTS = Object.keys(BUILTIN_AGENT_PATHS) as readonly string[];
|
|
27
52
|
|
|
28
|
-
export type BuiltinAgentId = typeof
|
|
53
|
+
export type BuiltinAgentId = keyof typeof BUILTIN_AGENT_PATHS;
|
|
29
54
|
|
|
30
55
|
/**
|
|
31
56
|
* Get the absolute path to the built-in agents directory
|
|
@@ -38,12 +63,37 @@ export function getBuiltinAgentsPath(): string {
|
|
|
38
63
|
* Check if an agent ID is a built-in agent
|
|
39
64
|
*/
|
|
40
65
|
export function isBuiltinAgent(agentId: string): agentId is BuiltinAgentId {
|
|
41
|
-
return
|
|
66
|
+
return agentId in BUILTIN_AGENT_PATHS;
|
|
42
67
|
}
|
|
43
68
|
|
|
44
69
|
/**
|
|
45
70
|
* Get the full path to a built-in agent YAML file
|
|
46
71
|
*/
|
|
47
|
-
export function getBuiltinAgentPath(agentId:
|
|
48
|
-
|
|
72
|
+
export function getBuiltinAgentPath(agentId: string): string | null {
|
|
73
|
+
const relativePath = BUILTIN_AGENT_PATHS[agentId];
|
|
74
|
+
if (!relativePath) return null;
|
|
75
|
+
return join(__dirname, relativePath);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get all agents in a specific category
|
|
80
|
+
*/
|
|
81
|
+
export function getAgentsByCategory(category: string): string[] {
|
|
82
|
+
return Object.entries(BUILTIN_AGENT_PATHS)
|
|
83
|
+
.filter(([_, path]) => path.startsWith(`${category}/`))
|
|
84
|
+
.map(([id]) => id);
|
|
49
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Available categories
|
|
89
|
+
*/
|
|
90
|
+
export const AGENT_CATEGORIES = [
|
|
91
|
+
'chat',
|
|
92
|
+
'mcp',
|
|
93
|
+
'google-business',
|
|
94
|
+
'marketing',
|
|
95
|
+
'utility',
|
|
96
|
+
'examples',
|
|
97
|
+
] as const;
|
|
98
|
+
|
|
99
|
+
export type AgentCategory = typeof AGENT_CATEGORIES[number];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Newsletter Signup Agent
|
|
2
|
+
# Registers users to the newsletter with AI analysis and saves to Notion
|
|
3
|
+
#
|
|
4
|
+
# Required Environment Variables:
|
|
5
|
+
# - NOTION_TOKEN (Internal Integration Secret)
|
|
6
|
+
# - NOTION_DATABASE_ID (Database ID for newsletter signups)
|
|
7
|
+
# - GEMINI_API_KEY (for AI analysis)
|
|
8
|
+
#
|
|
9
|
+
# Input:
|
|
10
|
+
# - name: User's name
|
|
11
|
+
# - email: User's email
|
|
12
|
+
# - message: Optional message from user
|
|
13
|
+
# - createdAt: ISO date string
|
|
14
|
+
|
|
15
|
+
metadata:
|
|
16
|
+
name: "Newsletter Signup Agent"
|
|
17
|
+
version: "1.3.0"
|
|
18
|
+
description: "Registers users to the newsletter with AI analysis and saves to Notion"
|
|
19
|
+
builtin: true
|
|
20
|
+
|
|
21
|
+
workflow:
|
|
22
|
+
# Step 1: Analyze user profile and generate structured JSON
|
|
23
|
+
- id: "analyze-user"
|
|
24
|
+
type: "llm"
|
|
25
|
+
config:
|
|
26
|
+
provider: "google"
|
|
27
|
+
model: "gemini-2.0-flash-exp"
|
|
28
|
+
system: |
|
|
29
|
+
You are a lead analyst for a technology newsletter.
|
|
30
|
+
|
|
31
|
+
Analyze the user data and return ONLY a valid JSON (no markdown, no ```):
|
|
32
|
+
{
|
|
33
|
+
"tags": [{"name": "Tag1"}],
|
|
34
|
+
"sentiment": {"name": "Positive"},
|
|
35
|
+
"summary": "One-line summary"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
IMPORTANT RULES:
|
|
39
|
+
- tags: Array of objects with "name". Allowed values: "Support", "Sales", "Partnership", "Feedback"
|
|
40
|
+
- sentiment: Object with "name". Allowed values: "Positive", "Neutral", "Negative"
|
|
41
|
+
- summary: Short summary string (maximum 100 characters)
|
|
42
|
+
|
|
43
|
+
Example for a positive message about the product:
|
|
44
|
+
{"tags": [{"name": "Feedback"}], "sentiment": {"name": "Positive"}, "summary": "User praises the product"}
|
|
45
|
+
|
|
46
|
+
If there is no significant message:
|
|
47
|
+
{"tags": [{"name": "Feedback"}], "sentiment": {"name": "Neutral"}, "summary": "New newsletter subscriber"}
|
|
48
|
+
|
|
49
|
+
Return ONLY the JSON, nothing else.
|
|
50
|
+
messages:
|
|
51
|
+
- role: "user"
|
|
52
|
+
content: |
|
|
53
|
+
Name: $input.name
|
|
54
|
+
Email: $input.email
|
|
55
|
+
Message: $input.message
|
|
56
|
+
result: "userAnalysis"
|
|
57
|
+
|
|
58
|
+
# Step 2: Parse the JSON from LLM
|
|
59
|
+
- id: "parse-analysis"
|
|
60
|
+
type: "output-generator"
|
|
61
|
+
config:
|
|
62
|
+
json: "$stepResult.userAnalysis.text"
|
|
63
|
+
result: "parsedAnalysis"
|
|
64
|
+
|
|
65
|
+
# Step 3: Create Notion page with structured data
|
|
66
|
+
- id: "create-notion-entry"
|
|
67
|
+
type: "notion"
|
|
68
|
+
config:
|
|
69
|
+
action: "createPage"
|
|
70
|
+
parent:
|
|
71
|
+
type: "database_id"
|
|
72
|
+
database_id: "$env.NOTION_DATABASE_ID"
|
|
73
|
+
properties:
|
|
74
|
+
Name:
|
|
75
|
+
title:
|
|
76
|
+
- text:
|
|
77
|
+
content: "$input.name"
|
|
78
|
+
Email:
|
|
79
|
+
email: "$input.email"
|
|
80
|
+
Message:
|
|
81
|
+
rich_text:
|
|
82
|
+
- text:
|
|
83
|
+
content: "$input.message"
|
|
84
|
+
Summary:
|
|
85
|
+
rich_text:
|
|
86
|
+
- text:
|
|
87
|
+
content: "$stepResult.parsedAnalysis.summary"
|
|
88
|
+
Tags:
|
|
89
|
+
multi_select: "$stepResult.parsedAnalysis.tags"
|
|
90
|
+
Sentiment:
|
|
91
|
+
select: "$stepResult.parsedAnalysis.sentiment"
|
|
92
|
+
CreatedAt:
|
|
93
|
+
date:
|
|
94
|
+
start: "$input.createdAt"
|
|
95
|
+
result: "notionResult"
|
|
96
|
+
|
|
97
|
+
# Explicit Return: Define the API response contract
|
|
98
|
+
return:
|
|
99
|
+
success: true
|
|
100
|
+
message: "Registration completed successfully!"
|
|
101
|
+
notionPageId: "$stepResult.notionResult.pageId"
|
|
102
|
+
notionUrl: "$stepResult.notionResult.url"
|
|
103
|
+
analysis:
|
|
104
|
+
tags: "$stepResult.parsedAnalysis.tags"
|
|
105
|
+
sentiment: "$stepResult.parsedAnalysis.sentiment"
|
|
106
|
+
summary: "$stepResult.parsedAnalysis.summary"
|
package/src/server/handler.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { loadYaml } from '../core/parser';
|
|
|
3
3
|
import { WorkflowExecutor } from '../core/workflow';
|
|
4
4
|
import { join, normalize } from 'path';
|
|
5
5
|
import { access } from 'fs/promises';
|
|
6
|
-
import {
|
|
6
|
+
import { getBuiltinAgentPath } from '../agents';
|
|
7
7
|
|
|
8
8
|
export interface BeddelHandlerOptions {
|
|
9
9
|
/** Path to user-defined agents (relative to CWD). Default: 'src/agents' */
|
|
@@ -57,10 +57,10 @@ async function resolveAgentPath(
|
|
|
57
57
|
return userPath;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// 2. Fallback: built-in agents from package
|
|
60
|
+
// 2. Fallback: built-in agents from package (supports subfolder structure)
|
|
61
61
|
if (!disableBuiltinAgents) {
|
|
62
|
-
const builtinPath =
|
|
63
|
-
if (await fileExists(builtinPath)) {
|
|
62
|
+
const builtinPath = getBuiltinAgentPath(agentId);
|
|
63
|
+
if (builtinPath && await fileExists(builtinPath)) {
|
|
64
64
|
return builtinPath;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|