@ai.ntellect/core 0.6.17 → 0.6.20
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/.mocharc.json +1 -2
- package/README.md +123 -178
- package/dist/graph/controller.js +29 -6
- package/dist/graph/index.js +302 -62
- package/dist/index.js +21 -6
- package/dist/interfaces/index.js +15 -0
- package/dist/modules/agenda/adapters/node-cron/index.js +29 -0
- package/dist/modules/agenda/index.js +140 -0
- package/dist/{services/embedding.js → modules/embedding/adapters/ai/index.js} +24 -7
- package/dist/modules/embedding/index.js +59 -0
- package/dist/modules/memory/adapters/in-memory/index.js +210 -0
- package/dist/{memory → modules/memory}/adapters/meilisearch/index.js +97 -2
- package/dist/{memory → modules/memory}/adapters/redis/index.js +77 -15
- package/dist/modules/memory/index.js +103 -0
- package/dist/utils/{stringifiy-zod-schema.js → generate-action-schema.js} +5 -5
- package/graph/controller.ts +46 -35
- package/graph/index.ts +534 -102
- package/graph.ts +74 -0
- package/index.ts +25 -7
- package/interfaces/index.ts +353 -27
- package/modules/agenda/adapters/node-cron/index.ts +25 -0
- package/modules/agenda/index.ts +159 -0
- package/modules/embedding/adapters/ai/index.ts +42 -0
- package/modules/embedding/index.ts +45 -0
- package/modules/memory/adapters/in-memory/index.ts +203 -0
- package/{memory → modules/memory}/adapters/meilisearch/index.ts +114 -12
- package/modules/memory/adapters/redis/index.ts +164 -0
- package/modules/memory/index.ts +93 -0
- package/package.json +3 -1
- package/test/graph/index.test.ts +578 -0
- package/test/modules/agenda/node-cron.test.ts +286 -0
- package/test/modules/embedding/ai.test.ts +78 -0
- package/test/modules/memory/adapters/in-memory.test.ts +153 -0
- package/test/{memory → modules/memory}/adapters/meilisearch.test.ts +79 -75
- package/test/modules/memory/adapters/redis.test.ts +169 -0
- package/test/modules/memory/base.test.ts +230 -0
- package/test/services/agenda.test.ts +279 -280
- package/types/index.ts +93 -202
- package/utils/{stringifiy-zod-schema.ts → generate-action-schema.ts} +3 -3
- package/app/README.md +0 -36
- package/app/app/favicon.ico +0 -0
- package/app/app/globals.css +0 -21
- package/app/app/gun.ts +0 -0
- package/app/app/layout.tsx +0 -18
- package/app/app/page.tsx +0 -321
- package/app/eslint.config.mjs +0 -16
- package/app/next.config.ts +0 -7
- package/app/package-lock.json +0 -5912
- package/app/package.json +0 -31
- package/app/pnpm-lock.yaml +0 -4031
- package/app/postcss.config.mjs +0 -8
- package/app/public/file.svg +0 -1
- package/app/public/globe.svg +0 -1
- package/app/public/next.svg +0 -1
- package/app/public/vercel.svg +0 -1
- package/app/public/window.svg +0 -1
- package/app/tailwind.config.ts +0 -18
- package/app/tsconfig.json +0 -27
- package/dist/memory/index.js +0 -9
- package/dist/services/agenda.js +0 -115
- package/dist/services/queue.js +0 -142
- package/dist/utils/experimental-graph-rag.js +0 -152
- package/dist/utils/generate-object.js +0 -111
- package/dist/utils/inject-actions.js +0 -16
- package/dist/utils/queue-item-transformer.js +0 -24
- package/dist/utils/sanitize-results.js +0 -60
- package/memory/adapters/redis/index.ts +0 -103
- package/memory/index.ts +0 -22
- package/services/agenda.ts +0 -118
- package/services/embedding.ts +0 -26
- package/services/queue.ts +0 -145
- package/test/memory/adapters/redis.test.ts +0 -159
- package/test/memory/base.test.ts +0 -225
- package/test/services/queue.test.ts +0 -286
- package/utils/experimental-graph-rag.ts +0 -170
- package/utils/generate-object.ts +0 -117
- package/utils/inject-actions.ts +0 -19
- package/utils/queue-item-transformer.ts +0 -38
- package/utils/sanitize-results.ts +0 -66
package/types/index.ts
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
import {
|
1
|
+
import { EventEmitter } from "events";
|
2
|
+
import { IEventEmitter } from "interfaces";
|
3
|
+
import { ZodSchema } from "zod";
|
2
4
|
|
3
5
|
/* ======================== MEMORY ======================== */
|
4
6
|
|
@@ -10,13 +12,13 @@ import { z, ZodSchema } from "zod";
|
|
10
12
|
* @property {string} roomId - The room identifier.
|
11
13
|
* @property {number} [ttl] - Time-to-live in seconds (optional).
|
12
14
|
*/
|
13
|
-
export
|
15
|
+
export interface CreateMemoryInput {
|
14
16
|
id?: string;
|
15
|
-
data:
|
17
|
+
data: string;
|
16
18
|
embedding?: number[];
|
17
19
|
roomId: string;
|
18
20
|
ttl?: number;
|
19
|
-
}
|
21
|
+
}
|
20
22
|
|
21
23
|
/**
|
22
24
|
* Represents a stored memory entry.
|
@@ -28,248 +30,137 @@ export type CreateMemoryInput = {
|
|
28
30
|
* @property {string} roomId - The associated room ID.
|
29
31
|
* @property {Date} createdAt - Creation date.
|
30
32
|
*/
|
31
|
-
export
|
33
|
+
export interface BaseMemoryType {
|
32
34
|
id: string;
|
33
|
-
data:
|
34
|
-
embedding
|
35
|
+
data: string;
|
36
|
+
embedding?: number[];
|
35
37
|
roomId: string;
|
36
38
|
createdAt: Date;
|
37
|
-
}
|
38
|
-
|
39
|
-
/* ======================== QUEUE ======================== */
|
40
|
-
|
41
|
-
/**
|
42
|
-
* Represents a single parameter for a queued action.
|
43
|
-
* @typedef {Object} QueueItemParameter
|
44
|
-
* @property {string} name - Parameter name.
|
45
|
-
* @property {string} value - Parameter value.
|
46
|
-
*/
|
47
|
-
export type QueueItemParameter = {
|
48
|
-
name: string;
|
49
|
-
value: string;
|
50
|
-
};
|
51
|
-
|
52
|
-
/**
|
53
|
-
* Represents an action in the queue.
|
54
|
-
* @typedef {Object} QueueItem
|
55
|
-
* @property {string} name - Name of the action.
|
56
|
-
* @property {QueueItemParameter[]} parameters - List of parameters.
|
57
|
-
*/
|
58
|
-
export type QueueItem = {
|
59
|
-
name: string;
|
60
|
-
parameters: QueueItemParameter[];
|
61
|
-
};
|
62
|
-
|
63
|
-
/**
|
64
|
-
* Represents the result of a processed queue action.
|
65
|
-
* @typedef {Object} QueueResult
|
66
|
-
* @property {string} name - Action name.
|
67
|
-
* @property {Record<string, string>} parameters - Executed parameters.
|
68
|
-
* @property {any} result - The execution result.
|
69
|
-
* @property {string | null} error - Error message if any.
|
70
|
-
* @property {boolean} [cancelled] - Indicates if the action was cancelled.
|
71
|
-
*/
|
72
|
-
export type QueueResult = {
|
73
|
-
name: string;
|
74
|
-
parameters: Record<string, string>;
|
75
|
-
result: any;
|
76
|
-
error: string | null;
|
77
|
-
cancelled?: boolean;
|
78
|
-
};
|
79
|
-
|
80
|
-
/**
|
81
|
-
* Defines callback functions for queue execution events.
|
82
|
-
* @typedef {Object} QueueCallbacks
|
83
|
-
* @property {(action: QueueItem) => void} [onActionStart] - Triggered when an action starts.
|
84
|
-
* @property {(result: QueueResult) => void} [onActionComplete] - Triggered when an action completes.
|
85
|
-
* @property {(results: QueueResult[]) => void} [onQueueComplete] - Triggered when the queue is fully processed.
|
86
|
-
* @property {(message: string) => Promise<boolean>} [onConfirmationRequired] - Triggered when confirmation is needed.
|
87
|
-
*/
|
88
|
-
export type QueueCallbacks = {
|
89
|
-
onActionStart?: (action: QueueItem) => void;
|
90
|
-
onActionComplete?: (result: QueueResult) => void;
|
91
|
-
onQueueComplete?: (results: QueueResult[]) => void;
|
92
|
-
onConfirmationRequired?: (message: string) => Promise<boolean>;
|
93
|
-
};
|
94
|
-
|
95
|
-
/* ======================== ACTION ======================== */
|
96
|
-
|
97
|
-
/**
|
98
|
-
* Represents an executable action schema.
|
99
|
-
* @typedef {Object} ActionSchema
|
100
|
-
* @property {string} name - Action name.
|
101
|
-
* @property {string} description - Action description.
|
102
|
-
* @property {z.ZodObject<Record<string, z.ZodType>>} parameters - Schema for input parameters.
|
103
|
-
* @property {(args: any) => Promise<any>} execute - Function to execute the action.
|
104
|
-
* @property {Object[]} [examples] - Example usages of the action.
|
105
|
-
* @property {Object} [confirmation] - Confirmation requirements.
|
106
|
-
* @property {boolean} confirmation.requireConfirmation - Whether confirmation is needed.
|
107
|
-
* @property {string} confirmation.message - The confirmation message.
|
108
|
-
*/
|
109
|
-
export type ActionSchema = {
|
110
|
-
name: string;
|
111
|
-
description: string;
|
112
|
-
parameters: z.ZodObject<{ [key: string]: z.ZodType }>;
|
113
|
-
execute: (args: any) => Promise<any>;
|
114
|
-
examples?: {
|
115
|
-
role: string;
|
116
|
-
content: string;
|
117
|
-
parameters?: Record<string, any>;
|
118
|
-
}[];
|
119
|
-
confirmation?: {
|
120
|
-
requireConfirmation: boolean;
|
121
|
-
message: string;
|
122
|
-
};
|
123
|
-
};
|
39
|
+
}
|
124
40
|
|
125
41
|
/* ======================== SCHEDULING ======================== */
|
126
42
|
|
127
43
|
/**
|
128
|
-
*
|
129
|
-
* @typedef {Object} ScheduledAction
|
130
|
-
* @property {string} id - Unique identifier for the scheduled action.
|
131
|
-
* @property {Object} action - The action details.
|
132
|
-
* @property {string} action.name - The action name.
|
133
|
-
* @property {QueueItemParameter[]} action.parameters - Action parameters.
|
134
|
-
* @property {Date} scheduledTime - The scheduled execution time.
|
135
|
-
* @property {string} userId - Associated user identifier.
|
136
|
-
* @property {"pending" | "completed" | "failed"} status - The execution status.
|
137
|
-
* @property {Object} [recurrence] - Recurrence details (optional).
|
138
|
-
* @property {"daily" | "weekly" | "monthly"} recurrence.type - Recurrence type.
|
139
|
-
* @property {number} recurrence.interval - Recurrence interval.
|
140
|
-
*/
|
141
|
-
export type ScheduledAction = {
|
142
|
-
id: string;
|
143
|
-
action: {
|
144
|
-
name: string;
|
145
|
-
parameters: QueueItemParameter[];
|
146
|
-
};
|
147
|
-
scheduledTime: Date;
|
148
|
-
userId: string;
|
149
|
-
status: "pending" | "completed" | "failed";
|
150
|
-
recurrence?: {
|
151
|
-
type: "daily" | "weekly" | "monthly";
|
152
|
-
interval: number;
|
153
|
-
};
|
154
|
-
};
|
155
|
-
|
156
|
-
/**
|
157
|
-
* Represents a scheduled request.
|
44
|
+
* Type for scheduled request entries
|
158
45
|
* @typedef {Object} ScheduledRequest
|
159
|
-
* @property {string} id - Unique identifier for the scheduled request.
|
160
|
-
* @property {string} originalRequest - The original request string.
|
161
|
-
* @property {string} cronExpression - The cron expression for scheduling.
|
162
|
-
* @property {boolean} isRecurring - Whether the request is recurring.
|
163
|
-
* @property {Date} createdAt - The creation date.
|
164
46
|
*/
|
165
47
|
export type ScheduledRequest = {
|
48
|
+
/** Unique identifier for the scheduled request */
|
166
49
|
id: string;
|
50
|
+
/** The original request string */
|
167
51
|
originalRequest: string;
|
52
|
+
/** The cron expression for scheduling */
|
168
53
|
cronExpression: string;
|
54
|
+
/** Whether the request is recurring */
|
169
55
|
isRecurring: boolean;
|
56
|
+
/** The creation date */
|
170
57
|
createdAt: Date;
|
171
58
|
};
|
172
59
|
|
173
60
|
/* ======================== GRAPH ======================== */
|
174
61
|
|
175
|
-
|
62
|
+
/**
|
63
|
+
* Utility type for extracting schema type from Zod schema
|
64
|
+
* @template T - Zod schema type
|
65
|
+
*/
|
66
|
+
export type SchemaType<T> = T extends ZodSchema<infer U> ? U : never;
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Type for graph context based on schema
|
70
|
+
* @template T - Schema type
|
71
|
+
*/
|
72
|
+
export type GraphContext<T> = SchemaType<T>;
|
176
73
|
|
177
|
-
|
74
|
+
/**
|
75
|
+
* Interface representing a node in the graph
|
76
|
+
* @interface
|
77
|
+
* @template T - Schema type
|
78
|
+
* @template I - Input schema type
|
79
|
+
* @template O - Output schema type
|
80
|
+
*/
|
81
|
+
export interface Node<T extends ZodSchema, I = any> {
|
82
|
+
/** Name of the node */
|
178
83
|
name: string;
|
179
|
-
|
180
|
-
|
84
|
+
/** Schema for node inputs */
|
85
|
+
inputs?: I extends void ? never : ZodSchema<I>;
|
86
|
+
/** Schema for node outputs */
|
87
|
+
outputs?: ZodSchema;
|
88
|
+
/** Execute function for the node */
|
89
|
+
execute: (
|
181
90
|
context: GraphContext<T>,
|
182
|
-
|
183
|
-
) => Promise<void>;
|
184
|
-
|
91
|
+
inputs: I extends void ? never : I
|
92
|
+
) => Promise<void>;
|
93
|
+
/** Optional condition for node execution */
|
185
94
|
condition?: (context: GraphContext<T>) => boolean;
|
186
|
-
|
95
|
+
/** Array of next node names */
|
96
|
+
next?: string[] | ((context: GraphContext<T>) => string[]);
|
97
|
+
/** Array of event names */
|
187
98
|
events?: string[];
|
188
|
-
|
189
|
-
|
99
|
+
/** Wait for event */
|
100
|
+
waitForEvent?: boolean;
|
101
|
+
/** Retry configuration */
|
190
102
|
retry?: {
|
103
|
+
/** Maximum number of retry attempts */
|
191
104
|
maxAttempts: number;
|
105
|
+
/** Delay between retries in milliseconds */
|
192
106
|
delay: number;
|
107
|
+
/** Error handler function */
|
108
|
+
onRetryFailed?: (error: Error, context: GraphContext<T>) => Promise<void>;
|
109
|
+
/** Continue execution on failed retry */
|
110
|
+
continueOnFailed?: boolean;
|
193
111
|
};
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
name: string;
|
198
|
-
nodes: Node<T>[];
|
199
|
-
initialContext?: GraphContext<T>;
|
200
|
-
validator?: T;
|
201
|
-
globalErrorHandler?: (error: Error, context: GraphContext<T>) => void;
|
202
|
-
};
|
203
|
-
|
204
|
-
export type GraphDefinition<T extends ZodSchema> = {
|
205
|
-
name: string;
|
206
|
-
nodes: Record<string, Node<T>>;
|
207
|
-
entryNode: string;
|
208
|
-
};
|
209
|
-
|
210
|
-
/**
|
211
|
-
* Defines a shared state context for execution graphs.
|
212
|
-
* @typedef {Object} SharedState
|
213
|
-
* @property {Partial<T>} context - The execution context.
|
214
|
-
*/
|
215
|
-
export type SharedState<T> = T;
|
112
|
+
/** Error handler function */
|
113
|
+
onError?: (error: Error) => void;
|
114
|
+
}
|
216
115
|
|
217
116
|
/**
|
218
|
-
*
|
219
|
-
* @
|
220
|
-
* @
|
221
|
-
* @property {string} [description] - Optional description.
|
117
|
+
* Interface for graph definition
|
118
|
+
* @interface
|
119
|
+
* @template T - Schema type
|
222
120
|
*/
|
223
|
-
export
|
121
|
+
export interface GraphDefinition<T extends ZodSchema> {
|
122
|
+
/** Name of the graph */
|
224
123
|
name: string;
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
124
|
+
/** Array of nodes in the graph */
|
125
|
+
nodes: Node<T, any>[];
|
126
|
+
/** Initial context */
|
127
|
+
context: SchemaType<T>;
|
128
|
+
/** Schema for validation */
|
129
|
+
schema: T;
|
130
|
+
/** Global error handler */
|
131
|
+
onError?: (error: Error, context: GraphContext<T>) => void;
|
132
|
+
/** Entry node name */
|
133
|
+
entryNode?: string;
|
134
|
+
/** Event emitter instance */
|
135
|
+
eventEmitter?: IEventEmitter | EventEmitter;
|
136
|
+
/** Array of events */
|
137
|
+
events?: string[];
|
138
|
+
}
|
229
139
|
|
230
|
-
|
231
|
-
* Represents a document that can be indexed and searched.
|
232
|
-
* @typedef {Object} SearchDocument
|
233
|
-
* @property {string} [id] - Optional unique identifier of the document.
|
234
|
-
* @property {string} content - The searchable text content.
|
235
|
-
* @property {Record<string, any>} [metadata] - Additional metadata for context.
|
236
|
-
*/
|
237
|
-
export type SearchDocument = {
|
238
|
-
id?: string;
|
239
|
-
content: string;
|
240
|
-
metadata?: Record<string, any>;
|
241
|
-
};
|
140
|
+
/* ======================== MEILISEARCH ======================== */
|
242
141
|
|
243
142
|
/**
|
244
|
-
*
|
245
|
-
* @typedef {Object}
|
246
|
-
* @property {SearchDocument} document - The matched document.
|
247
|
-
* @property {number} score - The similarity score.
|
143
|
+
* Configuration type for Meilisearch
|
144
|
+
* @typedef {Object} MeilisearchConfig
|
248
145
|
*/
|
249
|
-
export type SearchResult = {
|
250
|
-
document: SearchDocument;
|
251
|
-
score: number;
|
252
|
-
};
|
253
|
-
|
254
|
-
/* ======================== MEILISEARCH ======================== */
|
255
146
|
export type MeilisearchConfig = {
|
147
|
+
/** Meilisearch host URL */
|
256
148
|
host: string;
|
149
|
+
/** API key for authentication */
|
257
150
|
apiKey: string;
|
151
|
+
/** Array of searchable attributes */
|
258
152
|
searchableAttributes?: string[];
|
153
|
+
/** Array of sortable attributes */
|
259
154
|
sortableAttributes?: string[];
|
260
155
|
};
|
261
156
|
|
157
|
+
/**
|
158
|
+
* Settings type for Meilisearch
|
159
|
+
* @typedef {Object} MeilisearchSettings
|
160
|
+
*/
|
262
161
|
export type MeilisearchSettings = {
|
162
|
+
/** Array of searchable attributes */
|
263
163
|
searchableAttributes?: string[];
|
164
|
+
/** Array of sortable attributes */
|
264
165
|
sortableAttributes?: string[];
|
265
166
|
};
|
266
|
-
|
267
|
-
/* ======================== ACTIONS ======================== */
|
268
|
-
|
269
|
-
export type Action = {
|
270
|
-
name: string;
|
271
|
-
parameters: {
|
272
|
-
name: string;
|
273
|
-
value: string;
|
274
|
-
}[];
|
275
|
-
};
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import { z } from "zod";
|
2
2
|
import { Node } from "../types";
|
3
3
|
|
4
|
-
export const
|
4
|
+
export const generateActionSchema = (nodes: Node<any>[]) => {
|
5
5
|
return nodes
|
6
6
|
.map((node) => {
|
7
|
-
const schemaStr = node.
|
8
|
-
? getSchemaString(node.
|
7
|
+
const schemaStr = node.inputs
|
8
|
+
? getSchemaString(node.inputs)
|
9
9
|
: "No parameters";
|
10
10
|
return `Workflow: ${node.name}\nParameters: ${schemaStr}`;
|
11
11
|
})
|
package/app/README.md
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
2
|
-
|
3
|
-
## Getting Started
|
4
|
-
|
5
|
-
First, run the development server:
|
6
|
-
|
7
|
-
```bash
|
8
|
-
npm run dev
|
9
|
-
# or
|
10
|
-
yarn dev
|
11
|
-
# or
|
12
|
-
pnpm dev
|
13
|
-
# or
|
14
|
-
bun dev
|
15
|
-
```
|
16
|
-
|
17
|
-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
18
|
-
|
19
|
-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
20
|
-
|
21
|
-
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
22
|
-
|
23
|
-
## Learn More
|
24
|
-
|
25
|
-
To learn more about Next.js, take a look at the following resources:
|
26
|
-
|
27
|
-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
28
|
-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
29
|
-
|
30
|
-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
31
|
-
|
32
|
-
## Deploy on Vercel
|
33
|
-
|
34
|
-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
35
|
-
|
36
|
-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
package/app/app/favicon.ico
DELETED
Binary file
|
package/app/app/globals.css
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
@tailwind base;
|
2
|
-
@tailwind components;
|
3
|
-
@tailwind utilities;
|
4
|
-
|
5
|
-
:root {
|
6
|
-
--background: #ffffff;
|
7
|
-
--foreground: #171717;
|
8
|
-
}
|
9
|
-
|
10
|
-
@media (prefers-color-scheme: dark) {
|
11
|
-
:root {
|
12
|
-
--background: #0a0a0a;
|
13
|
-
--foreground: #ededed;
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
body {
|
18
|
-
color: var(--foreground);
|
19
|
-
background: var(--background);
|
20
|
-
font-family: Arial, Helvetica, sans-serif;
|
21
|
-
}
|
package/app/app/gun.ts
DELETED
File without changes
|
package/app/app/layout.tsx
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
import type { Metadata } from "next";
|
2
|
-
import "./globals.css";
|
3
|
-
export const metadata: Metadata = {
|
4
|
-
title: "Create Next App",
|
5
|
-
description: "Generated by create next app",
|
6
|
-
};
|
7
|
-
|
8
|
-
export default function RootLayout({
|
9
|
-
children,
|
10
|
-
}: Readonly<{
|
11
|
-
children: React.ReactNode;
|
12
|
-
}>) {
|
13
|
-
return (
|
14
|
-
<html lang="en">
|
15
|
-
<body>{children}</body>
|
16
|
-
</html>
|
17
|
-
);
|
18
|
-
}
|