@nextsparkjs/theme-default 0.1.0-beta.1

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.
Files changed (333) hide show
  1. package/about/business.md +49 -0
  2. package/about/features.json +302 -0
  3. package/about/team.md +79 -0
  4. package/api/ai/chat/stream/route.ts +212 -0
  5. package/api/ai/orchestrator/route.ts +226 -0
  6. package/api/ai/single-agent/route.ts +291 -0
  7. package/api/ai/usage/route.ts +122 -0
  8. package/blocks/benefits/component.tsx +100 -0
  9. package/blocks/benefits/config.ts +11 -0
  10. package/blocks/benefits/examples.ts +85 -0
  11. package/blocks/benefits/fields.ts +156 -0
  12. package/blocks/benefits/schema.ts +33 -0
  13. package/blocks/cta-section/component.tsx +100 -0
  14. package/blocks/cta-section/config.ts +11 -0
  15. package/blocks/cta-section/examples.ts +41 -0
  16. package/blocks/cta-section/fields.ts +89 -0
  17. package/blocks/cta-section/index.ts +6 -0
  18. package/blocks/cta-section/schema.ts +32 -0
  19. package/blocks/cta-section/thumbnail.png +1 -0
  20. package/blocks/faq-accordion/component.tsx +156 -0
  21. package/blocks/faq-accordion/config.ts +11 -0
  22. package/blocks/faq-accordion/examples.ts +77 -0
  23. package/blocks/faq-accordion/fields.ts +119 -0
  24. package/blocks/faq-accordion/index.ts +6 -0
  25. package/blocks/faq-accordion/schema.ts +45 -0
  26. package/blocks/features-grid/component.tsx +112 -0
  27. package/blocks/features-grid/config.ts +11 -0
  28. package/blocks/features-grid/examples.ts +63 -0
  29. package/blocks/features-grid/fields.ts +97 -0
  30. package/blocks/features-grid/index.ts +6 -0
  31. package/blocks/features-grid/schema.ts +40 -0
  32. package/blocks/features-grid/thumbnail.png +1 -0
  33. package/blocks/hero/component.tsx +100 -0
  34. package/blocks/hero/config.ts +11 -0
  35. package/blocks/hero/examples.ts +35 -0
  36. package/blocks/hero/fields.ts +60 -0
  37. package/blocks/hero/index.ts +6 -0
  38. package/blocks/hero/schema.ts +32 -0
  39. package/blocks/hero/thumbnail.png +1 -0
  40. package/blocks/hero/thumbnail.png.txt +6 -0
  41. package/blocks/hero-with-form/component.tsx +232 -0
  42. package/blocks/hero-with-form/config.ts +11 -0
  43. package/blocks/hero-with-form/examples.ts +16 -0
  44. package/blocks/hero-with-form/fields.ts +207 -0
  45. package/blocks/hero-with-form/index.ts +6 -0
  46. package/blocks/hero-with-form/schema.ts +54 -0
  47. package/blocks/jumbotron/component.tsx +136 -0
  48. package/blocks/jumbotron/config.ts +11 -0
  49. package/blocks/jumbotron/examples.ts +36 -0
  50. package/blocks/jumbotron/fields.ts +202 -0
  51. package/blocks/jumbotron/index.ts +6 -0
  52. package/blocks/jumbotron/schema.ts +55 -0
  53. package/blocks/logo-cloud/component.tsx +154 -0
  54. package/blocks/logo-cloud/config.ts +11 -0
  55. package/blocks/logo-cloud/examples.ts +34 -0
  56. package/blocks/logo-cloud/fields.ts +133 -0
  57. package/blocks/logo-cloud/index.ts +6 -0
  58. package/blocks/logo-cloud/schema.ts +46 -0
  59. package/blocks/post-content/component.tsx +197 -0
  60. package/blocks/post-content/config.ts +11 -0
  61. package/blocks/post-content/examples.ts +33 -0
  62. package/blocks/post-content/fields.ts +165 -0
  63. package/blocks/post-content/index.ts +4 -0
  64. package/blocks/post-content/schema.ts +46 -0
  65. package/blocks/pricing-table/component.tsx +154 -0
  66. package/blocks/pricing-table/config.ts +11 -0
  67. package/blocks/pricing-table/examples.ts +96 -0
  68. package/blocks/pricing-table/fields.ts +161 -0
  69. package/blocks/pricing-table/index.ts +4 -0
  70. package/blocks/pricing-table/schema.ts +50 -0
  71. package/blocks/split-content/component.tsx +135 -0
  72. package/blocks/split-content/config.ts +11 -0
  73. package/blocks/split-content/examples.ts +38 -0
  74. package/blocks/split-content/fields.ts +198 -0
  75. package/blocks/split-content/index.ts +6 -0
  76. package/blocks/split-content/schema.ts +67 -0
  77. package/blocks/stats-counter/component.tsx +124 -0
  78. package/blocks/stats-counter/config.ts +11 -0
  79. package/blocks/stats-counter/examples.ts +61 -0
  80. package/blocks/stats-counter/fields.ts +134 -0
  81. package/blocks/stats-counter/index.ts +6 -0
  82. package/blocks/stats-counter/schema.ts +47 -0
  83. package/blocks/testimonials/component.tsx +114 -0
  84. package/blocks/testimonials/config.ts +11 -0
  85. package/blocks/testimonials/examples.ts +65 -0
  86. package/blocks/testimonials/fields.ts +105 -0
  87. package/blocks/testimonials/index.ts +6 -0
  88. package/blocks/testimonials/schema.ts +41 -0
  89. package/blocks/testimonials/thumbnail.png +1 -0
  90. package/blocks/text-content/component.tsx +97 -0
  91. package/blocks/text-content/config.ts +11 -0
  92. package/blocks/text-content/examples.ts +30 -0
  93. package/blocks/text-content/fields.ts +88 -0
  94. package/blocks/text-content/index.ts +6 -0
  95. package/blocks/text-content/schema.ts +30 -0
  96. package/blocks/text-content/thumbnail.png +1 -0
  97. package/blocks/timeline/component.tsx +267 -0
  98. package/blocks/timeline/config.ts +11 -0
  99. package/blocks/timeline/examples.ts +68 -0
  100. package/blocks/timeline/fields.ts +147 -0
  101. package/blocks/timeline/index.ts +6 -0
  102. package/blocks/timeline/schema.ts +49 -0
  103. package/blocks/video-hero/component.tsx +270 -0
  104. package/blocks/video-hero/config.ts +11 -0
  105. package/blocks/video-hero/examples.ts +24 -0
  106. package/blocks/video-hero/fields.ts +98 -0
  107. package/blocks/video-hero/index.ts +6 -0
  108. package/blocks/video-hero/schema.ts +39 -0
  109. package/components/ai-chat/ChatPanel.tsx +575 -0
  110. package/components/ai-chat/ConversationItem.tsx +266 -0
  111. package/components/ai-chat/ConversationSidebar.tsx +99 -0
  112. package/components/ai-chat/MarkdownRenderer.tsx +15 -0
  113. package/components/ai-chat/Message.tsx +42 -0
  114. package/components/ai-chat/MessageInput.tsx +49 -0
  115. package/components/ai-chat/MessageList.tsx +46 -0
  116. package/components/ai-chat/TypingIndicator.tsx +11 -0
  117. package/config/app.config.ts +367 -0
  118. package/config/billing.config.ts +349 -0
  119. package/config/dashboard.config.ts +506 -0
  120. package/config/dev.config.ts +104 -0
  121. package/config/features.config.ts +203 -0
  122. package/config/flows.config.ts +129 -0
  123. package/config/permissions.config.ts +245 -0
  124. package/config/theme.config.ts +74 -0
  125. package/docs/01-overview/01-introduction.md +335 -0
  126. package/docs/01-overview/02-customization.md +671 -0
  127. package/docs/02-features/01-components.md +155 -0
  128. package/docs/02-features/02-styling.md +139 -0
  129. package/docs/02-features/03-tasks-entity.md +407 -0
  130. package/docs/03-ai/01-overview.md +211 -0
  131. package/docs/03-ai/02-customization.md +436 -0
  132. package/entities/customers/customers.config.ts +75 -0
  133. package/entities/customers/customers.fields.ts +165 -0
  134. package/entities/customers/customers.service.ts +516 -0
  135. package/entities/customers/customers.types.ts +83 -0
  136. package/entities/customers/messages/en.json +66 -0
  137. package/entities/customers/messages/es.json +66 -0
  138. package/entities/customers/migrations/001_customers_table.sql +102 -0
  139. package/entities/customers/migrations/002_customers_metas.sql +92 -0
  140. package/entities/pages/messages/en.json +41 -0
  141. package/entities/pages/messages/es.json +41 -0
  142. package/entities/pages/migrations/001_pages_table.sql +112 -0
  143. package/entities/pages/migrations/002_pages_metas.sql +56 -0
  144. package/entities/pages/migrations/003_add_status.sql +50 -0
  145. package/entities/pages/pages-management.service.ts +610 -0
  146. package/entities/pages/pages.config.ts +94 -0
  147. package/entities/pages/pages.fields.ts +101 -0
  148. package/entities/pages/pages.service.ts +290 -0
  149. package/entities/pages/pages.types.ts +124 -0
  150. package/entities/posts/components/post-header.tsx +97 -0
  151. package/entities/posts/messages/en.json +55 -0
  152. package/entities/posts/messages/es.json +55 -0
  153. package/entities/posts/migrations/001_posts_table.sql +115 -0
  154. package/entities/posts/migrations/003_add_status.sql +44 -0
  155. package/entities/posts/migrations/004_entity_taxonomy_relations.sql +129 -0
  156. package/entities/posts/migrations/006_posts_metas.sql +56 -0
  157. package/entities/posts/posts.config.ts +101 -0
  158. package/entities/posts/posts.fields.ts +116 -0
  159. package/entities/posts/posts.service.ts +376 -0
  160. package/entities/posts/posts.types.ts +74 -0
  161. package/entities/tasks/messages/en.json +204 -0
  162. package/entities/tasks/messages/es.json +204 -0
  163. package/entities/tasks/migrations/001_tasks_table.sql +105 -0
  164. package/entities/tasks/migrations/002_task_metas.sql +85 -0
  165. package/entities/tasks/migrations/sample_data.json +77 -0
  166. package/entities/tasks/tasks.config.ts +79 -0
  167. package/entities/tasks/tasks.fields.ts +196 -0
  168. package/entities/tasks/tasks.service.ts +541 -0
  169. package/entities/tasks/tasks.types.ts +56 -0
  170. package/lib/hooks/useAiChat.ts +114 -0
  171. package/lib/hooks/useConversations.ts +376 -0
  172. package/lib/hooks/useOrchestratorChat.ts +122 -0
  173. package/lib/hooks/usePersistentChat.ts +315 -0
  174. package/lib/hooks/useStreamingChat.ts +127 -0
  175. package/lib/hooks/useTokenUsage.ts +63 -0
  176. package/lib/langchain/agents/customer-assistant.md +69 -0
  177. package/lib/langchain/agents/index.ts +61 -0
  178. package/lib/langchain/agents/orchestrator.md +59 -0
  179. package/lib/langchain/agents/page-assistant.md +85 -0
  180. package/lib/langchain/agents/single-agent.md +46 -0
  181. package/lib/langchain/agents/task-assistant.md +55 -0
  182. package/lib/langchain/config.ts +45 -0
  183. package/lib/langchain/handlers/customer-handler.ts +338 -0
  184. package/lib/langchain/handlers/page-handler.ts +232 -0
  185. package/lib/langchain/handlers/task-handler.ts +323 -0
  186. package/lib/langchain/langchain.config.ts +223 -0
  187. package/lib/langchain/observability.config.ts +30 -0
  188. package/lib/langchain/orchestrator.ts +562 -0
  189. package/lib/langchain/tools/customers.ts +176 -0
  190. package/lib/langchain/tools/index.ts +10 -0
  191. package/lib/langchain/tools/orchestrator.ts +92 -0
  192. package/lib/langchain/tools/pages.ts +289 -0
  193. package/lib/langchain/tools/tasks.ts +167 -0
  194. package/lib/scheduled-actions/billing.ts +149 -0
  195. package/lib/scheduled-actions/index.ts +170 -0
  196. package/lib/scheduled-actions/webhook.ts +231 -0
  197. package/lib/selectors.ts +197 -0
  198. package/messages/de/admin.json +219 -0
  199. package/messages/de/aiUsage.json +36 -0
  200. package/messages/de/buttons.json +19 -0
  201. package/messages/de/categories.json +35 -0
  202. package/messages/de/common.json +16 -0
  203. package/messages/de/dev.json +101 -0
  204. package/messages/de/docs.json +27 -0
  205. package/messages/de/entities.json +7 -0
  206. package/messages/de/features.json +119 -0
  207. package/messages/de/footer.json +22 -0
  208. package/messages/de/home.json +57 -0
  209. package/messages/de/index.ts +39 -0
  210. package/messages/de/mobileNav.json +13 -0
  211. package/messages/de/navigation.json +8 -0
  212. package/messages/de/observability.json +74 -0
  213. package/messages/de/posts.json +54 -0
  214. package/messages/de/pricing.json +102 -0
  215. package/messages/de/support.json +9 -0
  216. package/messages/de/teams.json +8 -0
  217. package/messages/en/admin.json +219 -0
  218. package/messages/en/aiUsage.json +36 -0
  219. package/messages/en/buttons.json +19 -0
  220. package/messages/en/categories.json +35 -0
  221. package/messages/en/common.json +16 -0
  222. package/messages/en/dev.json +106 -0
  223. package/messages/en/docs.json +27 -0
  224. package/messages/en/entities.json +7 -0
  225. package/messages/en/features.json +119 -0
  226. package/messages/en/footer.json +22 -0
  227. package/messages/en/home.json +57 -0
  228. package/messages/en/index.ts +39 -0
  229. package/messages/en/mobileNav.json +13 -0
  230. package/messages/en/navigation.json +8 -0
  231. package/messages/en/observability.json +74 -0
  232. package/messages/en/posts.json +54 -0
  233. package/messages/en/pricing.json +102 -0
  234. package/messages/en/support.json +9 -0
  235. package/messages/en/teams.json +8 -0
  236. package/messages/es/admin.json +219 -0
  237. package/messages/es/aiUsage.json +36 -0
  238. package/messages/es/buttons.json +19 -0
  239. package/messages/es/categories.json +35 -0
  240. package/messages/es/common.json +16 -0
  241. package/messages/es/dev.json +101 -0
  242. package/messages/es/docs.json +27 -0
  243. package/messages/es/entities.json +7 -0
  244. package/messages/es/features.json +119 -0
  245. package/messages/es/footer.json +22 -0
  246. package/messages/es/home.json +57 -0
  247. package/messages/es/index.ts +39 -0
  248. package/messages/es/mobileNav.json +13 -0
  249. package/messages/es/navigation.json +8 -0
  250. package/messages/es/observability.json +74 -0
  251. package/messages/es/posts.json +54 -0
  252. package/messages/es/pricing.json +102 -0
  253. package/messages/es/support.json +9 -0
  254. package/messages/es/teams.json +8 -0
  255. package/messages/fr/admin.json +219 -0
  256. package/messages/fr/aiUsage.json +36 -0
  257. package/messages/fr/buttons.json +19 -0
  258. package/messages/fr/categories.json +35 -0
  259. package/messages/fr/common.json +16 -0
  260. package/messages/fr/dev.json +101 -0
  261. package/messages/fr/docs.json +27 -0
  262. package/messages/fr/entities.json +7 -0
  263. package/messages/fr/features.json +119 -0
  264. package/messages/fr/footer.json +22 -0
  265. package/messages/fr/home.json +57 -0
  266. package/messages/fr/index.ts +39 -0
  267. package/messages/fr/mobileNav.json +13 -0
  268. package/messages/fr/navigation.json +8 -0
  269. package/messages/fr/observability.json +74 -0
  270. package/messages/fr/posts.json +54 -0
  271. package/messages/fr/pricing.json +102 -0
  272. package/messages/fr/support.json +9 -0
  273. package/messages/fr/teams.json +8 -0
  274. package/messages/it/admin.json +219 -0
  275. package/messages/it/aiUsage.json +36 -0
  276. package/messages/it/buttons.json +19 -0
  277. package/messages/it/categories.json +35 -0
  278. package/messages/it/common.json +16 -0
  279. package/messages/it/dev.json +101 -0
  280. package/messages/it/docs.json +27 -0
  281. package/messages/it/entities.json +7 -0
  282. package/messages/it/features.json +119 -0
  283. package/messages/it/footer.json +22 -0
  284. package/messages/it/home.json +57 -0
  285. package/messages/it/index.ts +39 -0
  286. package/messages/it/mobileNav.json +13 -0
  287. package/messages/it/navigation.json +8 -0
  288. package/messages/it/observability.json +74 -0
  289. package/messages/it/posts.json +54 -0
  290. package/messages/it/pricing.json +102 -0
  291. package/messages/it/support.json +9 -0
  292. package/messages/it/teams.json +8 -0
  293. package/messages/pt/admin.json +219 -0
  294. package/messages/pt/aiUsage.json +36 -0
  295. package/messages/pt/buttons.json +19 -0
  296. package/messages/pt/categories.json +35 -0
  297. package/messages/pt/common.json +16 -0
  298. package/messages/pt/dev.json +101 -0
  299. package/messages/pt/docs.json +27 -0
  300. package/messages/pt/entities.json +7 -0
  301. package/messages/pt/features.json +119 -0
  302. package/messages/pt/footer.json +22 -0
  303. package/messages/pt/home.json +57 -0
  304. package/messages/pt/index.ts +39 -0
  305. package/messages/pt/mobileNav.json +13 -0
  306. package/messages/pt/navigation.json +8 -0
  307. package/messages/pt/observability.json +74 -0
  308. package/messages/pt/posts.json +54 -0
  309. package/messages/pt/pricing.json +102 -0
  310. package/messages/pt/support.json +9 -0
  311. package/messages/pt/teams.json +8 -0
  312. package/migrations/089_add_editor_team_role.sql +39 -0
  313. package/migrations/090_demo_users_teams.sql +540 -0
  314. package/migrations/091_greek_teams_billing.sql +523 -0
  315. package/migrations/092_billing_sample_data.sql +774 -0
  316. package/migrations/093_pages_sample_data.sql +1158 -0
  317. package/migrations/094_posts_sample_data.sql +278 -0
  318. package/migrations/095_tasks_sample_data.sql +440 -0
  319. package/migrations/096_customers_sample_data.sql +358 -0
  320. package/migrations/097_scheduled_actions_sample_data.sql +111 -0
  321. package/package.json +22 -0
  322. package/public/docs/desktop-layout-example.png +0 -0
  323. package/styles/components.css +11 -0
  324. package/styles/globals.css +179 -0
  325. package/templates/(public)/blog/[slug]/page.tsx +65 -0
  326. package/templates/(public)/layout.tsx +25 -0
  327. package/templates/(public)/page.tsx +200 -0
  328. package/templates/(public)/support/page.tsx +321 -0
  329. package/templates/dashboard/(main)/agent-multi/page.tsx +63 -0
  330. package/templates/dashboard/(main)/agent-single/page.tsx +142 -0
  331. package/templates/dashboard/(main)/settings/ai-usage/page.tsx +157 -0
  332. package/templates/superadmin/ai-observability/[traceId]/page.tsx +27 -0
  333. package/templates/superadmin/ai-observability/page.tsx +17 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Page Handler Node
3
+ *
4
+ * Executes page operations directly without additional LLM calls.
5
+ * Uses the PagesService to perform read operations.
6
+ */
7
+
8
+ import { PagesService } from '@/themes/default/entities/pages/pages.service'
9
+ import { config as pluginConfig } from '@/plugins/langchain/plugin.config'
10
+ import { createAgentLogger } from '@/plugins/langchain/lib/logger'
11
+ import type { OrchestratorState, PageHandlerResult, PageData, IntentType } from '@/plugins/langchain/lib/graph/types'
12
+
13
+ /**
14
+ * Transform Page entity to PageData for handler result
15
+ */
16
+ function toPageData(page: any): PageData {
17
+ return {
18
+ id: page.id,
19
+ title: page.title,
20
+ slug: page.slug,
21
+ status: page.status,
22
+ locale: page.locale,
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Execute page operation based on intent
28
+ */
29
+ async function executePageOperation(
30
+ action: string,
31
+ parameters: Record<string, unknown>,
32
+ context: { userId: string; teamId: string }
33
+ ): Promise<PageHandlerResult> {
34
+ const { userId } = context
35
+
36
+ try {
37
+ switch (action) {
38
+ case 'list': {
39
+ const locale = (parameters.locale as string) || 'en'
40
+ const { pages, total } = await PagesService.listPublished({
41
+ locale,
42
+ limit: 50,
43
+ orderBy: 'createdAt',
44
+ orderDir: 'desc',
45
+ })
46
+
47
+ return {
48
+ success: true,
49
+ operation: 'list',
50
+ data: pages.map(toPageData),
51
+ count: total,
52
+ message: `Found ${total} published page(s)`,
53
+ }
54
+ }
55
+
56
+ case 'get': {
57
+ const id = parameters.id as string
58
+ const slug = parameters.slug as string
59
+
60
+ if (slug) {
61
+ const locale = (parameters.locale as string) || 'en'
62
+ const page = await PagesService.getPublishedBySlug(slug, locale)
63
+ if (!page) {
64
+ return {
65
+ success: false,
66
+ operation: 'get',
67
+ data: null,
68
+ message: `Page with slug "${slug}" not found`,
69
+ error: 'Page not found',
70
+ }
71
+ }
72
+ return {
73
+ success: true,
74
+ operation: 'get',
75
+ data: toPageData(page),
76
+ message: `Found page: ${page.title}`,
77
+ }
78
+ }
79
+
80
+ if (id) {
81
+ const page = await PagesService.getById(id, userId)
82
+ if (!page) {
83
+ return {
84
+ success: false,
85
+ operation: 'get',
86
+ data: null,
87
+ message: 'Page not found',
88
+ error: 'Page not found',
89
+ }
90
+ }
91
+ return {
92
+ success: true,
93
+ operation: 'get',
94
+ data: toPageData(page),
95
+ message: `Found page: ${page.title}`,
96
+ }
97
+ }
98
+
99
+ return {
100
+ success: false,
101
+ operation: 'get',
102
+ data: null,
103
+ message: 'Page ID or slug is required',
104
+ error: 'Missing page identifier',
105
+ }
106
+ }
107
+
108
+ case 'search': {
109
+ // Pages don't have a search method, so list and filter
110
+ const query = (parameters.query as string)?.toLowerCase()
111
+ const locale = (parameters.locale as string) || 'en'
112
+
113
+ const { pages } = await PagesService.listPublished({
114
+ locale,
115
+ limit: 100,
116
+ })
117
+
118
+ let filteredPages = pages
119
+ if (query) {
120
+ filteredPages = pages.filter(
121
+ (p) =>
122
+ p.title.toLowerCase().includes(query) ||
123
+ p.slug.toLowerCase().includes(query)
124
+ )
125
+ }
126
+
127
+ return {
128
+ success: true,
129
+ operation: 'search',
130
+ data: filteredPages.map(toPageData),
131
+ count: filteredPages.length,
132
+ message: `Found ${filteredPages.length} page(s) matching "${query}"`,
133
+ }
134
+ }
135
+
136
+ case 'create':
137
+ case 'update':
138
+ case 'delete':
139
+ // These operations are not supported through the AI agent
140
+ return {
141
+ success: false,
142
+ operation: action as any,
143
+ data: null,
144
+ message: `Page ${action} is not supported through the AI assistant. Please use the page builder.`,
145
+ error: 'Operation not supported',
146
+ }
147
+
148
+ default:
149
+ return {
150
+ success: false,
151
+ operation: 'unknown',
152
+ data: null,
153
+ message: `Unknown action: ${action}`,
154
+ error: `Unsupported action: ${action}`,
155
+ }
156
+ }
157
+ } catch (error) {
158
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
159
+ return {
160
+ success: false,
161
+ operation: action as any,
162
+ data: null,
163
+ message: `Failed to execute ${action}: ${errorMessage}`,
164
+ error: errorMessage,
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Page handler node
171
+ *
172
+ * Executes page operations without additional LLM calls.
173
+ * Returns JSON result for combiner to format.
174
+ */
175
+ export async function pageHandlerNode(
176
+ state: OrchestratorState
177
+ ): Promise<Partial<OrchestratorState>> {
178
+ const { context, loggerTimestamp } = state
179
+ const logger = createAgentLogger({
180
+ agentName: 'graph-orchestrator',
181
+ userName: (context.userName as string) || 'system',
182
+ timestamp: loggerTimestamp,
183
+ })
184
+
185
+ // Find page intent
186
+ const pageIntent = state.intents.find((i) => i.type === 'page')
187
+
188
+ if (!pageIntent) {
189
+ // No page intent, skip
190
+ return {
191
+ completedHandlers: [...state.completedHandlers, 'page' as IntentType],
192
+ }
193
+ }
194
+
195
+ await logger.info('PAGE_HANDLER_INPUT', {
196
+ action: pageIntent.action,
197
+ parameters: pageIntent.parameters,
198
+ })
199
+
200
+ if (pluginConfig.debug) {
201
+ console.log('[PageHandler] Executing:', pageIntent.action, pageIntent.parameters)
202
+ }
203
+
204
+ const result = await executePageOperation(
205
+ pageIntent.action,
206
+ pageIntent.parameters,
207
+ {
208
+ userId: state.context.userId,
209
+ teamId: state.context.teamId as string,
210
+ }
211
+ )
212
+
213
+ await logger.info('PAGE_HANDLER_OUTPUT', {
214
+ success: result.success,
215
+ operation: result.operation,
216
+ message: result.message,
217
+ count: result.count,
218
+ data: result.data,
219
+ })
220
+
221
+ if (pluginConfig.debug) {
222
+ console.log('[PageHandler] Result:', result.success, result.message)
223
+ }
224
+
225
+ return {
226
+ handlerResults: {
227
+ ...state.handlerResults,
228
+ page: result,
229
+ },
230
+ completedHandlers: [...state.completedHandlers, 'page' as IntentType],
231
+ }
232
+ }
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Task Handler Node
3
+ *
4
+ * Executes task operations directly without additional LLM calls.
5
+ * Uses the TasksService to perform CRUD operations.
6
+ */
7
+
8
+ import { TasksService } from '@/themes/default/entities/tasks/tasks.service'
9
+ import { tracer } from '@/plugins/langchain/lib/tracer'
10
+ import { config as pluginConfig } from '@/plugins/langchain/plugin.config'
11
+ import { createAgentLogger } from '@/plugins/langchain/lib/logger'
12
+ import type { OrchestratorState, TaskHandlerResult, TaskData, IntentType } from '@/plugins/langchain/lib/graph/types'
13
+
14
+ /**
15
+ * Map priority strings to valid values
16
+ */
17
+ function normalizePriority(priority?: unknown): 'low' | 'medium' | 'high' | 'urgent' | undefined {
18
+ if (!priority) return undefined
19
+ const p = String(priority).toLowerCase()
20
+ if (['low', 'medium', 'high', 'urgent'].includes(p)) {
21
+ return p as 'low' | 'medium' | 'high' | 'urgent'
22
+ }
23
+ return undefined
24
+ }
25
+
26
+ /**
27
+ * Map status strings to valid values
28
+ */
29
+ function normalizeStatus(status?: unknown): 'todo' | 'in-progress' | 'review' | 'done' | 'blocked' | undefined {
30
+ if (!status) return undefined
31
+ const s = String(status).toLowerCase().replace(/[_-]/g, '-')
32
+ if (s === 'pending' || s === 'todo') return 'todo'
33
+ if (s === 'in-progress' || s === 'inprogress') return 'in-progress'
34
+ if (s === 'review') return 'review'
35
+ if (s === 'done' || s === 'completed' || s === 'complete') return 'done'
36
+ if (s === 'blocked') return 'blocked'
37
+ return undefined
38
+ }
39
+
40
+ /**
41
+ * Transform Task entity to TaskData for handler result
42
+ */
43
+ function toTaskData(task: any): TaskData {
44
+ return {
45
+ id: task.id,
46
+ title: task.title,
47
+ status: task.status,
48
+ priority: task.priority,
49
+ dueDate: task.dueDate,
50
+ description: task.description,
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Execute task operation based on intent
56
+ */
57
+ async function executeTaskOperation(
58
+ action: string,
59
+ parameters: Record<string, unknown>,
60
+ context: { userId: string; teamId: string }
61
+ ): Promise<TaskHandlerResult> {
62
+ const { userId, teamId } = context
63
+
64
+ try {
65
+ switch (action) {
66
+ case 'list': {
67
+ const priority = normalizePriority(parameters.priority)
68
+ const status = normalizeStatus(parameters.status)
69
+
70
+ const { tasks, total } = await TasksService.list(userId, {
71
+ priority,
72
+ status,
73
+ teamId,
74
+ limit: 50,
75
+ orderBy: 'createdAt',
76
+ orderDir: 'desc',
77
+ })
78
+
79
+ return {
80
+ success: true,
81
+ operation: 'list',
82
+ data: tasks.map(toTaskData),
83
+ count: total,
84
+ message: `Found ${total} task(s)`,
85
+ }
86
+ }
87
+
88
+ case 'get': {
89
+ const id = parameters.id as string
90
+ if (!id) {
91
+ return {
92
+ success: false,
93
+ operation: 'get',
94
+ data: null,
95
+ message: 'Task ID is required',
96
+ error: 'Missing task ID',
97
+ }
98
+ }
99
+
100
+ const task = await TasksService.getById(id, userId)
101
+ if (!task) {
102
+ return {
103
+ success: false,
104
+ operation: 'get',
105
+ data: null,
106
+ message: 'Task not found',
107
+ error: 'Task not found',
108
+ }
109
+ }
110
+
111
+ return {
112
+ success: true,
113
+ operation: 'get',
114
+ data: toTaskData(task),
115
+ message: `Found task: ${task.title}`,
116
+ }
117
+ }
118
+
119
+ case 'create': {
120
+ const title = parameters.title as string
121
+ if (!title) {
122
+ return {
123
+ success: false,
124
+ operation: 'create',
125
+ data: null,
126
+ message: 'Task title is required',
127
+ error: 'Missing title',
128
+ }
129
+ }
130
+
131
+ const task = await TasksService.create(userId, {
132
+ title,
133
+ description: parameters.description as string | undefined,
134
+ priority: normalizePriority(parameters.priority) || 'medium',
135
+ status: normalizeStatus(parameters.status) || 'todo',
136
+ dueDate: parameters.dueDate as string | undefined,
137
+ teamId,
138
+ })
139
+
140
+ return {
141
+ success: true,
142
+ operation: 'create',
143
+ data: toTaskData(task),
144
+ message: `Created task: ${task.title}`,
145
+ }
146
+ }
147
+
148
+ case 'update': {
149
+ const id = parameters.id as string
150
+ if (!id) {
151
+ return {
152
+ success: false,
153
+ operation: 'update',
154
+ data: null,
155
+ message: 'Task ID is required',
156
+ error: 'Missing task ID',
157
+ }
158
+ }
159
+
160
+ const updateData: Record<string, unknown> = {}
161
+ if (parameters.title) updateData.title = parameters.title
162
+ if (parameters.description !== undefined) updateData.description = parameters.description
163
+ if (parameters.priority) updateData.priority = normalizePriority(parameters.priority)
164
+ if (parameters.status) updateData.status = normalizeStatus(parameters.status)
165
+ if (parameters.dueDate) updateData.dueDate = parameters.dueDate
166
+
167
+ const task = await TasksService.update(userId, id, updateData)
168
+
169
+ return {
170
+ success: true,
171
+ operation: 'update',
172
+ data: toTaskData(task),
173
+ message: `Updated task: ${task.title}`,
174
+ }
175
+ }
176
+
177
+ case 'search': {
178
+ // For tasks, search is similar to list with filters
179
+ const query = parameters.query as string
180
+ const priority = normalizePriority(parameters.priority)
181
+ const status = normalizeStatus(parameters.status)
182
+
183
+ const { tasks, total } = await TasksService.list(userId, {
184
+ priority,
185
+ status,
186
+ teamId,
187
+ limit: 20,
188
+ })
189
+
190
+ // Filter by query if provided (title contains)
191
+ let filteredTasks = tasks
192
+ if (query) {
193
+ const lowerQuery = query.toLowerCase()
194
+ filteredTasks = tasks.filter(
195
+ (t) =>
196
+ t.title.toLowerCase().includes(lowerQuery) ||
197
+ t.description?.toLowerCase().includes(lowerQuery)
198
+ )
199
+ }
200
+
201
+ return {
202
+ success: true,
203
+ operation: 'search',
204
+ data: filteredTasks.map(toTaskData),
205
+ count: filteredTasks.length,
206
+ message: `Found ${filteredTasks.length} matching task(s)`,
207
+ }
208
+ }
209
+
210
+ default:
211
+ return {
212
+ success: false,
213
+ operation: 'unknown',
214
+ data: null,
215
+ message: `Unknown action: ${action}`,
216
+ error: `Unsupported action: ${action}`,
217
+ }
218
+ }
219
+ } catch (error) {
220
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
221
+ return {
222
+ success: false,
223
+ operation: action as any,
224
+ data: null,
225
+ message: `Failed to execute ${action}: ${errorMessage}`,
226
+ error: errorMessage,
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Task handler node
233
+ *
234
+ * Executes task operations without additional LLM calls.
235
+ * Returns JSON result for combiner to format.
236
+ */
237
+ export async function taskHandlerNode(
238
+ state: OrchestratorState
239
+ ): Promise<Partial<OrchestratorState>> {
240
+ const { context, traceId, loggerTimestamp } = state
241
+ const logger = createAgentLogger({
242
+ agentName: 'graph-orchestrator',
243
+ userName: (context.userName as string) || 'system',
244
+ timestamp: loggerTimestamp,
245
+ })
246
+
247
+ // Find task intent
248
+ const taskIntent = state.intents.find((i) => i.type === 'task')
249
+
250
+ if (!taskIntent) {
251
+ // No task intent, skip
252
+ return {
253
+ completedHandlers: [...state.completedHandlers, 'task' as IntentType],
254
+ }
255
+ }
256
+
257
+ // Start span for task handler
258
+ const spanContext = traceId
259
+ ? await tracer.startSpan(
260
+ { userId: context.userId, teamId: context.teamId },
261
+ traceId,
262
+ {
263
+ name: 'task-handler',
264
+ type: 'tool',
265
+ toolName: `task_${taskIntent.action}`,
266
+ input: taskIntent.parameters,
267
+ }
268
+ )
269
+ : null
270
+
271
+ await logger.info('TASK_HANDLER_INPUT', {
272
+ action: taskIntent.action,
273
+ parameters: taskIntent.parameters,
274
+ })
275
+
276
+ if (pluginConfig.debug) {
277
+ console.log('[TaskHandler] Executing:', taskIntent.action, taskIntent.parameters)
278
+ }
279
+
280
+ const result = await executeTaskOperation(
281
+ taskIntent.action,
282
+ taskIntent.parameters,
283
+ {
284
+ userId: state.context.userId,
285
+ teamId: state.context.teamId as string,
286
+ }
287
+ )
288
+
289
+ await logger.info('TASK_HANDLER_OUTPUT', {
290
+ success: result.success,
291
+ operation: result.operation,
292
+ message: result.message,
293
+ count: result.count,
294
+ data: result.data,
295
+ })
296
+
297
+ if (pluginConfig.debug) {
298
+ console.log('[TaskHandler] Result:', result.success, result.message)
299
+ }
300
+
301
+ // End span
302
+ if (spanContext && traceId) {
303
+ await tracer.endSpan(
304
+ { userId: context.userId, teamId: context.teamId },
305
+ traceId,
306
+ spanContext.spanId,
307
+ {
308
+ output: { success: result.success, message: result.message, count: result.count },
309
+ toolInput: taskIntent.parameters,
310
+ toolOutput: result,
311
+ error: result.error ? new Error(result.error) : undefined,
312
+ }
313
+ )
314
+ }
315
+
316
+ return {
317
+ handlerResults: {
318
+ ...state.handlerResults,
319
+ task: result,
320
+ },
321
+ completedHandlers: [...state.completedHandlers, 'task' as IntentType],
322
+ }
323
+ }