graphile-llm 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +193 -0
  3. package/__tests__/graphile-llm.test.d.ts +1 -0
  4. package/__tests__/graphile-llm.test.js +721 -0
  5. package/chat.d.ts +37 -0
  6. package/chat.js +105 -0
  7. package/embedder.d.ts +35 -0
  8. package/embedder.js +79 -0
  9. package/esm/__tests__/graphile-llm.test.d.ts +1 -0
  10. package/esm/__tests__/graphile-llm.test.js +683 -0
  11. package/esm/chat.d.ts +37 -0
  12. package/esm/chat.js +97 -0
  13. package/esm/embedder.d.ts +35 -0
  14. package/esm/embedder.js +71 -0
  15. package/esm/index.d.ts +39 -0
  16. package/esm/index.js +42 -0
  17. package/esm/plugins/llm-module-plugin.d.ts +38 -0
  18. package/esm/plugins/llm-module-plugin.js +82 -0
  19. package/esm/plugins/rag-plugin.d.ts +36 -0
  20. package/esm/plugins/rag-plugin.js +341 -0
  21. package/esm/plugins/text-mutation-plugin.d.ts +44 -0
  22. package/esm/plugins/text-mutation-plugin.js +191 -0
  23. package/esm/plugins/text-search-plugin.d.ts +41 -0
  24. package/esm/plugins/text-search-plugin.js +163 -0
  25. package/esm/preset.d.ts +55 -0
  26. package/esm/preset.js +74 -0
  27. package/esm/types.d.ts +173 -0
  28. package/esm/types.js +6 -0
  29. package/index.d.ts +39 -0
  30. package/index.js +56 -0
  31. package/package.json +76 -0
  32. package/plugins/llm-module-plugin.d.ts +38 -0
  33. package/plugins/llm-module-plugin.js +85 -0
  34. package/plugins/rag-plugin.d.ts +36 -0
  35. package/plugins/rag-plugin.js +344 -0
  36. package/plugins/text-mutation-plugin.d.ts +44 -0
  37. package/plugins/text-mutation-plugin.js +194 -0
  38. package/plugins/text-search-plugin.d.ts +41 -0
  39. package/plugins/text-search-plugin.js +166 -0
  40. package/preset.d.ts +55 -0
  41. package/preset.js +77 -0
  42. package/types.d.ts +173 -0
  43. package/types.js +7 -0
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ /**
3
+ * LlmTextMutationPlugin
4
+ *
5
+ * Adds `{columnName}Text: String` companion fields on create/update mutation
6
+ * inputs for every vector column. When the client provides a text string in
7
+ * the companion field, the plugin embeds it server-side and injects the
8
+ * resulting vector into the actual column.
9
+ *
10
+ * Example:
11
+ * mutation { createArticle(input: { embeddingText: "Machine learning concepts" }) }
12
+ *
13
+ * This is the mutation counterpart to LlmTextSearchPlugin (which handles
14
+ * filter/query-side text-to-vector). Together they let clients work entirely
15
+ * with text/prompts instead of raw float vectors.
16
+ *
17
+ * Runtime embedding uses the v4-style resolver wrapping approach (same as
18
+ * graphile-upload-plugin and graphile-bucket-provisioner-plugin). grafserv v5
19
+ * supports this through its backwards-compatibility layer.
20
+ *
21
+ * The companion fields are only added when the LLM plugin is loaded.
22
+ * If no embedder is configured, the fields are still registered for schema
23
+ * stability but return a clear error at execution time.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.createLlmTextMutationPlugin = createLlmTextMutationPlugin;
27
+ require("graphile-build");
28
+ require("graphile-build-pg");
29
+ /**
30
+ * Check if a codec is the pgvector `vector` type.
31
+ */
32
+ function isVectorCodec(codec) {
33
+ return codec?.name === 'vector';
34
+ }
35
+ /**
36
+ * Collect the text→vector field mapping for a codec's vector columns.
37
+ * Returns a map of textFieldName → vectorFieldName.
38
+ */
39
+ function getTextToVectorMapping(pgCodec, build) {
40
+ const mapping = {};
41
+ if (!pgCodec?.attributes)
42
+ return mapping;
43
+ for (const [attributeName, attribute] of Object.entries(pgCodec.attributes)) {
44
+ if (isVectorCodec(attribute.codec)) {
45
+ const fieldName = build.inflection.attribute({
46
+ codec: pgCodec,
47
+ attributeName,
48
+ });
49
+ mapping[`${fieldName}Text`] = fieldName;
50
+ }
51
+ }
52
+ return mapping;
53
+ }
54
+ /**
55
+ * Creates the LlmTextMutationPlugin.
56
+ *
57
+ * Hooks into GraphQLInputObjectType_fields for create/update input types
58
+ * and adds `{columnName}Text: String` for each vector column.
59
+ *
60
+ * Also wraps mutation resolvers via GraphQLObjectType_fields_field to
61
+ * intercept `*Text` companion field values, embed them, and inject the
62
+ * resulting vectors before the mutation executes.
63
+ */
64
+ function createLlmTextMutationPlugin() {
65
+ return {
66
+ name: 'LlmTextMutationPlugin',
67
+ version: '0.1.0',
68
+ description: 'Adds text companion fields on mutation inputs for vector columns — ' +
69
+ 'text is embedded server-side before storing',
70
+ after: [
71
+ 'LlmModulePlugin',
72
+ 'PgAttributesPlugin',
73
+ 'PgMutationCreatePlugin',
74
+ 'PgMutationUpdateDeletePlugin',
75
+ 'VectorCodecPlugin',
76
+ ],
77
+ schema: {
78
+ hooks: {
79
+ /**
80
+ * Add `{columnName}Text: String` fields to create/update input types
81
+ * for tables that have vector columns.
82
+ */
83
+ GraphQLInputObjectType_fields(fields, build, context) {
84
+ const { scope: { isPgPatch, isPgBaseInput, isMutationInput, pgCodec, }, } = context;
85
+ // Only intercept create/update input types for table rows
86
+ if (!pgCodec?.attributes || (!isPgPatch && !isPgBaseInput && !isMutationInput)) {
87
+ return fields;
88
+ }
89
+ const { graphql: { GraphQLString }, } = build;
90
+ // Find vector columns on this table
91
+ const vectorColumns = [];
92
+ for (const [attributeName, attribute] of Object.entries(pgCodec.attributes)) {
93
+ if (isVectorCodec(attribute.codec)) {
94
+ vectorColumns.push(attributeName);
95
+ }
96
+ }
97
+ if (vectorColumns.length === 0) {
98
+ return fields;
99
+ }
100
+ let newFields = fields;
101
+ for (const columnName of vectorColumns) {
102
+ // Convert snake_case column name to camelCase field name
103
+ const fieldName = build.inflection.attribute({
104
+ codec: pgCodec,
105
+ attributeName: columnName,
106
+ });
107
+ const textFieldName = `${fieldName}Text`;
108
+ newFields = build.extend(newFields, {
109
+ [textFieldName]: {
110
+ type: GraphQLString,
111
+ description: `Natural language text to embed server-side into the \`${fieldName}\` vector column. ` +
112
+ `Mutually exclusive with \`${fieldName}\` — provide one or the other. ` +
113
+ 'Requires the LLM plugin to be configured with an embedding provider.',
114
+ },
115
+ }, `LlmTextMutationPlugin adding ${textFieldName} companion field for vector column '${columnName}'`);
116
+ }
117
+ return newFields;
118
+ },
119
+ /**
120
+ * Wrap create/update mutation resolvers to intercept `*Text` companion
121
+ * field values, embed them using the configured embedder, and inject
122
+ * the resulting vector into the corresponding vector field.
123
+ *
124
+ * Uses the same v4-style resolver wrapping pattern as graphile-upload-plugin
125
+ * and graphile-bucket-provisioner-plugin. grafserv v5 supports this through
126
+ * its backwards-compatibility layer.
127
+ */
128
+ GraphQLObjectType_fields_field(field, build, context) {
129
+ const { scope: { isRootMutation, fieldName, pgCodec }, } = context;
130
+ // Only wrap root mutation fields on tables with attributes
131
+ if (!isRootMutation || !pgCodec || !pgCodec.attributes) {
132
+ return field;
133
+ }
134
+ // Only wrap create/update mutations
135
+ const isCreate = fieldName.startsWith('create');
136
+ const isUpdate = fieldName.startsWith('update');
137
+ if (!isCreate && !isUpdate) {
138
+ return field;
139
+ }
140
+ // Build the text→vector mapping for this codec
141
+ const textToVectorMap = getTextToVectorMapping(pgCodec, build);
142
+ if (Object.keys(textToVectorMap).length === 0) {
143
+ return field;
144
+ }
145
+ const embedder = build.llmEmbedder;
146
+ const defaultResolver = (obj) => obj[fieldName];
147
+ const { resolve: oldResolve = defaultResolver, ...rest } = field;
148
+ return {
149
+ ...rest,
150
+ async resolve(source, args, graphqlContext, info) {
151
+ // Walk through the input args and embed any *Text companion fields
152
+ async function embedTextFields(obj) {
153
+ if (!obj || typeof obj !== 'object')
154
+ return;
155
+ const pending = [];
156
+ for (const key of Object.keys(obj)) {
157
+ const value = obj[key];
158
+ // Check if this key is a *Text companion field
159
+ if (key in textToVectorMap && typeof value === 'string') {
160
+ const vectorFieldName = textToVectorMap[key];
161
+ pending.push((async () => {
162
+ if (!embedder) {
163
+ throw new Error(`EMBED_NOT_CONFIGURED: Cannot embed ${key} — no embedding provider configured. ` +
164
+ 'Set defaultEmbedder in GraphileLlmPreset options or EMBEDDER_PROVIDER env var.');
165
+ }
166
+ const startTime = Date.now();
167
+ const vector = await embedder(value);
168
+ const latencyMs = Date.now() - startTime;
169
+ console.log(`[graphile-llm] Mutation embed: field=${key}, dims=${vector.length}, latency=${latencyMs}ms`);
170
+ // Inject the vector into the corresponding field
171
+ obj[vectorFieldName] = vector;
172
+ // Remove the consumed *Text field
173
+ delete obj[key];
174
+ })());
175
+ continue;
176
+ }
177
+ // Recurse into nested objects (e.g. input.article.embeddingText)
178
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
179
+ pending.push(embedTextFields(value));
180
+ }
181
+ }
182
+ if (pending.length > 0) {
183
+ await Promise.all(pending);
184
+ }
185
+ }
186
+ await embedTextFields(args);
187
+ return oldResolve(source, args, graphqlContext, info);
188
+ },
189
+ };
190
+ },
191
+ },
192
+ },
193
+ };
194
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * LlmTextSearchPlugin
3
+ *
4
+ * Adds a `text: String` field to `VectorNearbyInput` when the LLM plugin
5
+ * is enabled. This allows clients to pass natural language text instead of
6
+ * raw float vectors for similarity search — the plugin converts text to
7
+ * vectors server-side using the configured embedder.
8
+ *
9
+ * This mirrors the graphile-postgis pattern where `WithinDistanceInput`
10
+ * accepts a compound input (point + distance) and the plugin handles
11
+ * the conversion to SQL internally.
12
+ *
13
+ * The `text` field is mutually exclusive with `vector`: clients provide
14
+ * one or the other. When `text` is provided, the plugin embeds it and
15
+ * injects the resulting vector into the normal pgvector pipeline.
16
+ *
17
+ * Runtime embedding for query filters uses the v4-style resolver wrapping
18
+ * approach (same as graphile-upload-plugin). When a connection query's
19
+ * `where` argument includes a VectorNearbyInput with `text`, the resolver
20
+ * wrapper embeds the text and replaces it with the resulting vector before
21
+ * the plan executes.
22
+ *
23
+ * If the embedder is not configured, the `text` field is still registered
24
+ * (so the schema is stable) but will return a clear error at execution time.
25
+ */
26
+ import type { GraphileConfig } from 'graphile-config';
27
+ declare global {
28
+ namespace GraphileConfig {
29
+ interface Plugins {
30
+ LlmTextSearchPlugin: true;
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Creates the LlmTextSearchPlugin.
36
+ *
37
+ * Hooks into VectorNearbyInput to add a `text` field alongside the
38
+ * existing `vector` field. When a user provides `text`, the plugin's
39
+ * resolver wrapper embeds it before passing to pgvector.
40
+ */
41
+ export declare function createLlmTextSearchPlugin(): GraphileConfig.Plugin;
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * LlmTextSearchPlugin
4
+ *
5
+ * Adds a `text: String` field to `VectorNearbyInput` when the LLM plugin
6
+ * is enabled. This allows clients to pass natural language text instead of
7
+ * raw float vectors for similarity search — the plugin converts text to
8
+ * vectors server-side using the configured embedder.
9
+ *
10
+ * This mirrors the graphile-postgis pattern where `WithinDistanceInput`
11
+ * accepts a compound input (point + distance) and the plugin handles
12
+ * the conversion to SQL internally.
13
+ *
14
+ * The `text` field is mutually exclusive with `vector`: clients provide
15
+ * one or the other. When `text` is provided, the plugin embeds it and
16
+ * injects the resulting vector into the normal pgvector pipeline.
17
+ *
18
+ * Runtime embedding for query filters uses the v4-style resolver wrapping
19
+ * approach (same as graphile-upload-plugin). When a connection query's
20
+ * `where` argument includes a VectorNearbyInput with `text`, the resolver
21
+ * wrapper embeds the text and replaces it with the resulting vector before
22
+ * the plan executes.
23
+ *
24
+ * If the embedder is not configured, the `text` field is still registered
25
+ * (so the schema is stable) but will return a clear error at execution time.
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.createLlmTextSearchPlugin = createLlmTextSearchPlugin;
29
+ /**
30
+ * Check if a codec has any pgvector `vector` columns.
31
+ */
32
+ function hasVectorColumns(pgCodec) {
33
+ if (!pgCodec?.attributes)
34
+ return false;
35
+ for (const attribute of Object.values(pgCodec.attributes)) {
36
+ if (attribute.codec?.name === 'vector')
37
+ return true;
38
+ }
39
+ return false;
40
+ }
41
+ /**
42
+ * Recursively walk a `where` argument object and embed any VectorNearbyInput
43
+ * values that have `text` instead of `vector`.
44
+ */
45
+ async function embedTextInWhere(obj, embedder) {
46
+ if (!obj || typeof obj !== 'object')
47
+ return;
48
+ const pending = [];
49
+ for (const key of Object.keys(obj)) {
50
+ const value = obj[key];
51
+ if (!value || typeof value !== 'object')
52
+ continue;
53
+ // Detect VectorNearbyInput shape: has `text` and no `vector`
54
+ if ('text' in value && typeof value.text === 'string' && !value.vector) {
55
+ pending.push((async () => {
56
+ const startTime = Date.now();
57
+ const vector = await embedder(value.text);
58
+ const latencyMs = Date.now() - startTime;
59
+ console.log(`[graphile-llm] Search embed: field=${key}, dims=${vector.length}, latency=${latencyMs}ms`);
60
+ // Replace text with vector
61
+ value.vector = vector;
62
+ delete value.text;
63
+ })());
64
+ continue;
65
+ }
66
+ // Recurse into nested filter objects (AND, OR, etc.)
67
+ if (!Array.isArray(value)) {
68
+ pending.push(embedTextInWhere(value, embedder));
69
+ }
70
+ else {
71
+ // Handle arrays (e.g. AND: [...], OR: [...])
72
+ for (const item of value) {
73
+ pending.push(embedTextInWhere(item, embedder));
74
+ }
75
+ }
76
+ }
77
+ if (pending.length > 0) {
78
+ await Promise.all(pending);
79
+ }
80
+ }
81
+ /**
82
+ * Creates the LlmTextSearchPlugin.
83
+ *
84
+ * Hooks into VectorNearbyInput to add a `text` field alongside the
85
+ * existing `vector` field. When a user provides `text`, the plugin's
86
+ * resolver wrapper embeds it before passing to pgvector.
87
+ */
88
+ function createLlmTextSearchPlugin() {
89
+ return {
90
+ name: 'LlmTextSearchPlugin',
91
+ version: '0.1.0',
92
+ description: 'Adds text-to-vector embedding support on VectorNearbyInput filter fields',
93
+ after: [
94
+ 'LlmModulePlugin',
95
+ 'UnifiedSearchPlugin',
96
+ 'VectorCodecPlugin',
97
+ ],
98
+ schema: {
99
+ hooks: {
100
+ /**
101
+ * Add the `text: String` field to VectorNearbyInput.
102
+ *
103
+ * We intercept VectorNearbyInput specifically and add a `text` field.
104
+ * The field is optional — clients provide either `text` or `vector`.
105
+ */
106
+ GraphQLInputObjectType_fields(fields, build, context) {
107
+ const { scope: { inputObjectTypeName }, } = context;
108
+ if (inputObjectTypeName !== 'VectorNearbyInput') {
109
+ return fields;
110
+ }
111
+ const { graphql: { GraphQLString }, } = build;
112
+ return build.extend(fields, {
113
+ text: {
114
+ type: GraphQLString,
115
+ description: 'Natural language text to embed server-side for similarity search. ' +
116
+ 'Mutually exclusive with `vector` — provide one or the other. ' +
117
+ 'Requires the LLM plugin to be configured with an embedding provider.',
118
+ },
119
+ }, 'LlmTextSearchPlugin adding text field to VectorNearbyInput');
120
+ },
121
+ /**
122
+ * Wrap connection query resolvers to intercept `where` arguments that
123
+ * contain VectorNearbyInput with `text`, embed the text, and replace
124
+ * it with the resulting vector before the plan executes.
125
+ *
126
+ * Uses the same v4-style resolver wrapping pattern as graphile-upload-plugin
127
+ * and graphile-bucket-provisioner-plugin.
128
+ */
129
+ GraphQLObjectType_fields_field(field, build, context) {
130
+ const { scope: { isRootQuery, pgCodec }, } = context;
131
+ // Only wrap root query fields on tables with vector columns
132
+ if (!isRootQuery || !pgCodec || !hasVectorColumns(pgCodec)) {
133
+ return field;
134
+ }
135
+ const embedder = build.llmEmbedder;
136
+ if (!embedder)
137
+ return field;
138
+ const defaultResolver = (obj) => obj[context.scope.fieldName];
139
+ const { resolve: oldResolve = defaultResolver, ...rest } = field;
140
+ return {
141
+ ...rest,
142
+ async resolve(source, args, graphqlContext, info) {
143
+ // If the query has a `where` argument, check for text fields
144
+ if (args?.where) {
145
+ await embedTextInWhere(args.where, embedder);
146
+ }
147
+ // Also handle `filter` for relay-style connections
148
+ if (args?.filter) {
149
+ await embedTextInWhere(args.filter, embedder);
150
+ }
151
+ return oldResolve(source, args, graphqlContext, info);
152
+ },
153
+ };
154
+ },
155
+ finalize(schema, build) {
156
+ const embedder = build.llmEmbedder;
157
+ if (!embedder) {
158
+ console.log('[graphile-llm] No embedder available — text field on VectorNearbyInput ' +
159
+ 'will return errors if used. Configure an embedding provider to enable.');
160
+ }
161
+ return schema;
162
+ },
163
+ },
164
+ },
165
+ };
166
+ }
package/preset.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * GraphileLlmPreset
3
+ *
4
+ * A preset that bundles all LLM plugins for PostGraphile v5.
5
+ * This is the recommended entry point — add it to your preset's `extends` array.
6
+ *
7
+ * When enabled, this preset:
8
+ * - Resolves an embedder from configuration (llm_module, env vars, or preset options)
9
+ * - Adds a `text: String` field to `VectorNearbyInput` for text-based vector search
10
+ * - Adds `{column}Text: String` companion fields on mutation inputs for vector columns
11
+ * - Logs token usage to console (metering integration deferred to billing system)
12
+ *
13
+ * This preset is standalone — it is NOT included in ConstructivePreset by default.
14
+ * Projects that want LLM features opt in by adding it to their preset.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { GraphileLlmPreset } from 'graphile-llm';
19
+ *
20
+ * const preset = {
21
+ * extends: [
22
+ * ConstructivePreset,
23
+ * GraphileLlmPreset(),
24
+ * ],
25
+ * };
26
+ * ```
27
+ *
28
+ * @example With explicit embedder configuration:
29
+ * ```typescript
30
+ * import { GraphileLlmPreset } from 'graphile-llm';
31
+ *
32
+ * const preset = {
33
+ * extends: [
34
+ * ConstructivePreset,
35
+ * GraphileLlmPreset({
36
+ * defaultEmbedder: {
37
+ * provider: 'ollama',
38
+ * model: 'nomic-embed-text',
39
+ * baseUrl: 'http://localhost:11434',
40
+ * },
41
+ * }),
42
+ * ],
43
+ * };
44
+ * ```
45
+ */
46
+ import type { GraphileConfig } from 'graphile-config';
47
+ import type { GraphileLlmOptions } from './types';
48
+ /**
49
+ * Creates a preset that includes all LLM plugins.
50
+ *
51
+ * @param options - Configuration options for the LLM plugin
52
+ * @returns A GraphileConfig.Preset to add to your extends array
53
+ */
54
+ export declare function GraphileLlmPreset(options?: GraphileLlmOptions): GraphileConfig.Preset;
55
+ export default GraphileLlmPreset;
package/preset.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * GraphileLlmPreset
4
+ *
5
+ * A preset that bundles all LLM plugins for PostGraphile v5.
6
+ * This is the recommended entry point — add it to your preset's `extends` array.
7
+ *
8
+ * When enabled, this preset:
9
+ * - Resolves an embedder from configuration (llm_module, env vars, or preset options)
10
+ * - Adds a `text: String` field to `VectorNearbyInput` for text-based vector search
11
+ * - Adds `{column}Text: String` companion fields on mutation inputs for vector columns
12
+ * - Logs token usage to console (metering integration deferred to billing system)
13
+ *
14
+ * This preset is standalone — it is NOT included in ConstructivePreset by default.
15
+ * Projects that want LLM features opt in by adding it to their preset.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { GraphileLlmPreset } from 'graphile-llm';
20
+ *
21
+ * const preset = {
22
+ * extends: [
23
+ * ConstructivePreset,
24
+ * GraphileLlmPreset(),
25
+ * ],
26
+ * };
27
+ * ```
28
+ *
29
+ * @example With explicit embedder configuration:
30
+ * ```typescript
31
+ * import { GraphileLlmPreset } from 'graphile-llm';
32
+ *
33
+ * const preset = {
34
+ * extends: [
35
+ * ConstructivePreset,
36
+ * GraphileLlmPreset({
37
+ * defaultEmbedder: {
38
+ * provider: 'ollama',
39
+ * model: 'nomic-embed-text',
40
+ * baseUrl: 'http://localhost:11434',
41
+ * },
42
+ * }),
43
+ * ],
44
+ * };
45
+ * ```
46
+ */
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.GraphileLlmPreset = GraphileLlmPreset;
49
+ const llm_module_plugin_1 = require("./plugins/llm-module-plugin");
50
+ const text_search_plugin_1 = require("./plugins/text-search-plugin");
51
+ const text_mutation_plugin_1 = require("./plugins/text-mutation-plugin");
52
+ const rag_plugin_1 = require("./plugins/rag-plugin");
53
+ /**
54
+ * Creates a preset that includes all LLM plugins.
55
+ *
56
+ * @param options - Configuration options for the LLM plugin
57
+ * @returns A GraphileConfig.Preset to add to your extends array
58
+ */
59
+ function GraphileLlmPreset(options = {}) {
60
+ const { enableTextSearch = true, enableTextMutations = true, enableRag = false, ragDefaults, } = options;
61
+ const plugins = [
62
+ (0, llm_module_plugin_1.createLlmModulePlugin)(options),
63
+ ];
64
+ if (enableTextSearch) {
65
+ plugins.push((0, text_search_plugin_1.createLlmTextSearchPlugin)());
66
+ }
67
+ if (enableTextMutations) {
68
+ plugins.push((0, text_mutation_plugin_1.createLlmTextMutationPlugin)());
69
+ }
70
+ if (enableRag) {
71
+ plugins.push((0, rag_plugin_1.createLlmRagPlugin)(ragDefaults));
72
+ }
73
+ return {
74
+ plugins,
75
+ };
76
+ }
77
+ exports.default = GraphileLlmPreset;