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
package/esm/chat.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Chat Completion — pluggable chat/completion provider for the Graphile LLM plugin
3
+ *
4
+ * Provides a provider-based architecture for LLM chat completions.
5
+ * Currently supports Ollama via @agentic-kit/ollama.
6
+ *
7
+ * Used by the RAG plugin to generate answers from retrieved context.
8
+ *
9
+ * Resolution order mirrors the embedder:
10
+ * 1. The `llm_module` api_modules configuration (per-database)
11
+ * 2. The preset's `defaultChatCompleter` option (fallback for dev/testing)
12
+ * 3. Environment variables (CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL)
13
+ */
14
+ import type { ChatConfig, ChatFunction, LlmModuleData } from './types';
15
+ /**
16
+ * Build a chat completion function from a config object.
17
+ *
18
+ * @returns A ChatFunction, or null if the provider is not recognized
19
+ */
20
+ export declare function buildChatCompleter(config: ChatConfig): ChatFunction | null;
21
+ /**
22
+ * Build a chat completer from an `llm_module` api_modules row.
23
+ *
24
+ * @param data - The llm_module data from services_public.api_modules
25
+ * @returns A ChatFunction, or null if the chat provider is not configured
26
+ */
27
+ export declare function buildChatCompleterFromModule(data: LlmModuleData): ChatFunction | null;
28
+ /**
29
+ * Resolve a chat completer from environment variables.
30
+ * This is a fallback for development when no llm_module or defaultChatCompleter is configured.
31
+ *
32
+ * Environment variables:
33
+ * CHAT_PROVIDER - Provider name ('ollama')
34
+ * CHAT_MODEL - Model identifier (e.g. 'llama3')
35
+ * CHAT_BASE_URL - Provider base URL
36
+ */
37
+ export declare function buildChatCompleterFromEnv(): ChatFunction | null;
package/esm/chat.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Chat Completion — pluggable chat/completion provider for the Graphile LLM plugin
3
+ *
4
+ * Provides a provider-based architecture for LLM chat completions.
5
+ * Currently supports Ollama via @agentic-kit/ollama.
6
+ *
7
+ * Used by the RAG plugin to generate answers from retrieved context.
8
+ *
9
+ * Resolution order mirrors the embedder:
10
+ * 1. The `llm_module` api_modules configuration (per-database)
11
+ * 2. The preset's `defaultChatCompleter` option (fallback for dev/testing)
12
+ * 3. Environment variables (CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL)
13
+ */
14
+ import OllamaClient from '@agentic-kit/ollama';
15
+ // ─── Built-in Providers ─────────────────────────────────────────────────────
16
+ /**
17
+ * Create an Ollama-based chat completion function.
18
+ *
19
+ * Uses OllamaClient.generate() with a messages array, which internally
20
+ * routes to the /api/chat endpoint.
21
+ */
22
+ function createOllamaChatCompleter(baseUrl = 'http://localhost:11434', model = 'llama3') {
23
+ const client = new OllamaClient(baseUrl);
24
+ return async (messages, options) => {
25
+ // Build the input for OllamaClient.generate() in chat mode
26
+ const input = {
27
+ model,
28
+ messages: messages.filter((m) => m.role !== 'system'),
29
+ };
30
+ // Extract system message if present
31
+ const systemMsg = messages.find((m) => m.role === 'system');
32
+ if (systemMsg) {
33
+ input.system = systemMsg.content;
34
+ }
35
+ if (options?.temperature !== undefined) {
36
+ input.temperature = options.temperature;
37
+ }
38
+ const startTime = Date.now();
39
+ const response = await client.generate(input);
40
+ const latencyMs = Date.now() - startTime;
41
+ // Token count logging (metering deferred to billing system)
42
+ console.log(`[graphile-llm] Chat completion: model=${model}, latency=${latencyMs}ms, ` +
43
+ `messages=${messages.length}`);
44
+ return response;
45
+ };
46
+ }
47
+ // ─── Chat Completer Construction ────────────────────────────────────────────
48
+ /**
49
+ * Build a chat completion function from a config object.
50
+ *
51
+ * @returns A ChatFunction, or null if the provider is not recognized
52
+ */
53
+ export function buildChatCompleter(config) {
54
+ switch (config.provider) {
55
+ case 'ollama':
56
+ return createOllamaChatCompleter(config.baseUrl, config.model);
57
+ // Future: 'openai', 'anthropic', 'custom'
58
+ default:
59
+ return null;
60
+ }
61
+ }
62
+ // ─── Resolution from LLM Module ─────────────────────────────────────────────
63
+ /**
64
+ * Build a chat completer from an `llm_module` api_modules row.
65
+ *
66
+ * @param data - The llm_module data from services_public.api_modules
67
+ * @returns A ChatFunction, or null if the chat provider is not configured
68
+ */
69
+ export function buildChatCompleterFromModule(data) {
70
+ if (!data.chat_provider)
71
+ return null;
72
+ return buildChatCompleter({
73
+ provider: data.chat_provider,
74
+ model: data.chat_model,
75
+ baseUrl: data.chat_base_url,
76
+ apiKey: data.api_key_ref,
77
+ });
78
+ }
79
+ /**
80
+ * Resolve a chat completer from environment variables.
81
+ * This is a fallback for development when no llm_module or defaultChatCompleter is configured.
82
+ *
83
+ * Environment variables:
84
+ * CHAT_PROVIDER - Provider name ('ollama')
85
+ * CHAT_MODEL - Model identifier (e.g. 'llama3')
86
+ * CHAT_BASE_URL - Provider base URL
87
+ */
88
+ export function buildChatCompleterFromEnv() {
89
+ const provider = process.env.CHAT_PROVIDER;
90
+ if (!provider)
91
+ return null;
92
+ return buildChatCompleter({
93
+ provider,
94
+ model: process.env.CHAT_MODEL,
95
+ baseUrl: process.env.CHAT_BASE_URL,
96
+ });
97
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Embedder — pluggable text-to-vector embedding for the Graphile LLM plugin
3
+ *
4
+ * Provides a provider-based architecture for converting text into vector
5
+ * embeddings. Currently supports Ollama via @agentic-kit/ollama.
6
+ *
7
+ * The embedder is resolved at request time from:
8
+ * 1. The `llm_module` api_modules configuration (per-database)
9
+ * 2. The preset's `defaultEmbedder` option (fallback for dev/testing)
10
+ * 3. Environment variables (EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL)
11
+ */
12
+ import type { EmbedderConfig, EmbedderFunction, LlmModuleData } from './types';
13
+ /**
14
+ * Build an embedder function from a config object.
15
+ *
16
+ * @returns An EmbedderFunction, or null if the provider is not recognized
17
+ */
18
+ export declare function buildEmbedder(config: EmbedderConfig): EmbedderFunction | null;
19
+ /**
20
+ * Build an embedder from an `llm_module` api_modules row.
21
+ *
22
+ * @param data - The llm_module data from services_public.api_modules
23
+ * @returns An EmbedderFunction, or null if the provider is not supported
24
+ */
25
+ export declare function buildEmbedderFromModule(data: LlmModuleData): EmbedderFunction | null;
26
+ /**
27
+ * Resolve an embedder from environment variables.
28
+ * This is a fallback for development when no llm_module or defaultEmbedder is configured.
29
+ *
30
+ * Environment variables:
31
+ * EMBEDDER_PROVIDER - Provider name ('ollama')
32
+ * EMBEDDER_MODEL - Model identifier
33
+ * EMBEDDER_BASE_URL - Provider base URL
34
+ */
35
+ export declare function buildEmbedderFromEnv(): EmbedderFunction | null;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Embedder — pluggable text-to-vector embedding for the Graphile LLM plugin
3
+ *
4
+ * Provides a provider-based architecture for converting text into vector
5
+ * embeddings. Currently supports Ollama via @agentic-kit/ollama.
6
+ *
7
+ * The embedder is resolved at request time from:
8
+ * 1. The `llm_module` api_modules configuration (per-database)
9
+ * 2. The preset's `defaultEmbedder` option (fallback for dev/testing)
10
+ * 3. Environment variables (EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL)
11
+ */
12
+ import OllamaClient from '@agentic-kit/ollama';
13
+ // ─── Built-in Providers ─────────────────────────────────────────────────────
14
+ /**
15
+ * Create an Ollama-based embedder function.
16
+ */
17
+ function createOllamaEmbedder(baseUrl = 'http://localhost:11434', model = 'nomic-embed-text') {
18
+ const client = new OllamaClient(baseUrl);
19
+ return async (text) => {
20
+ return client.generateEmbedding(text, model);
21
+ };
22
+ }
23
+ // ─── Embedder Construction ──────────────────────────────────────────────────
24
+ /**
25
+ * Build an embedder function from a config object.
26
+ *
27
+ * @returns An EmbedderFunction, or null if the provider is not recognized
28
+ */
29
+ export function buildEmbedder(config) {
30
+ switch (config.provider) {
31
+ case 'ollama':
32
+ return createOllamaEmbedder(config.baseUrl, config.model);
33
+ // Future: 'openai', 'anthropic', 'custom'
34
+ default:
35
+ return null;
36
+ }
37
+ }
38
+ // ─── Resolution from LLM Module ─────────────────────────────────────────────
39
+ /**
40
+ * Build an embedder from an `llm_module` api_modules row.
41
+ *
42
+ * @param data - The llm_module data from services_public.api_modules
43
+ * @returns An EmbedderFunction, or null if the provider is not supported
44
+ */
45
+ export function buildEmbedderFromModule(data) {
46
+ return buildEmbedder({
47
+ provider: data.embedding_provider,
48
+ model: data.embedding_model,
49
+ baseUrl: data.embedding_base_url,
50
+ apiKey: data.api_key_ref,
51
+ });
52
+ }
53
+ /**
54
+ * Resolve an embedder from environment variables.
55
+ * This is a fallback for development when no llm_module or defaultEmbedder is configured.
56
+ *
57
+ * Environment variables:
58
+ * EMBEDDER_PROVIDER - Provider name ('ollama')
59
+ * EMBEDDER_MODEL - Model identifier
60
+ * EMBEDDER_BASE_URL - Provider base URL
61
+ */
62
+ export function buildEmbedderFromEnv() {
63
+ const provider = process.env.EMBEDDER_PROVIDER;
64
+ if (!provider)
65
+ return null;
66
+ return buildEmbedder({
67
+ provider,
68
+ model: process.env.EMBEDDER_MODEL,
69
+ baseUrl: process.env.EMBEDDER_BASE_URL,
70
+ });
71
+ }
package/esm/index.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * graphile-llm — LLM Integration Plugin for PostGraphile v5
3
+ *
4
+ * Server-side text-to-vector embedding, text companion fields for pgvector
5
+ * columns, and RAG (Retrieval-Augmented Generation) query support.
6
+ *
7
+ * Moves the embedding logic from the client (CLI --auto-embed) into the
8
+ * Graphile server layer so clients work with text/prompts instead of raw
9
+ * float vectors.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { GraphileLlmPreset } from 'graphile-llm';
14
+ *
15
+ * const preset = {
16
+ * extends: [
17
+ * GraphileLlmPreset({
18
+ * defaultEmbedder: {
19
+ * provider: 'ollama',
20
+ * model: 'nomic-embed-text',
21
+ * },
22
+ * defaultChatCompleter: {
23
+ * provider: 'ollama',
24
+ * model: 'llama3',
25
+ * },
26
+ * enableRag: true,
27
+ * }),
28
+ * ],
29
+ * };
30
+ * ```
31
+ */
32
+ export { GraphileLlmPreset } from './preset';
33
+ export { createLlmModulePlugin } from './plugins/llm-module-plugin';
34
+ export { createLlmTextSearchPlugin } from './plugins/text-search-plugin';
35
+ export { createLlmTextMutationPlugin } from './plugins/text-mutation-plugin';
36
+ export { createLlmRagPlugin } from './plugins/rag-plugin';
37
+ export { buildEmbedder, buildEmbedderFromModule, buildEmbedderFromEnv, } from './embedder';
38
+ export { buildChatCompleter, buildChatCompleterFromModule, buildChatCompleterFromEnv, } from './chat';
39
+ export type { EmbedderFunction, EmbedderConfig, ChatFunction, ChatConfig, ChatMessage, ChatOptions, LlmModuleData, GraphileLlmOptions, RagDefaults, ChunkTableInfo, } from './types';
package/esm/index.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * graphile-llm — LLM Integration Plugin for PostGraphile v5
3
+ *
4
+ * Server-side text-to-vector embedding, text companion fields for pgvector
5
+ * columns, and RAG (Retrieval-Augmented Generation) query support.
6
+ *
7
+ * Moves the embedding logic from the client (CLI --auto-embed) into the
8
+ * Graphile server layer so clients work with text/prompts instead of raw
9
+ * float vectors.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { GraphileLlmPreset } from 'graphile-llm';
14
+ *
15
+ * const preset = {
16
+ * extends: [
17
+ * GraphileLlmPreset({
18
+ * defaultEmbedder: {
19
+ * provider: 'ollama',
20
+ * model: 'nomic-embed-text',
21
+ * },
22
+ * defaultChatCompleter: {
23
+ * provider: 'ollama',
24
+ * model: 'llama3',
25
+ * },
26
+ * enableRag: true,
27
+ * }),
28
+ * ],
29
+ * };
30
+ * ```
31
+ */
32
+ // Preset (recommended entry point)
33
+ export { GraphileLlmPreset } from './preset';
34
+ // Individual plugins
35
+ export { createLlmModulePlugin } from './plugins/llm-module-plugin';
36
+ export { createLlmTextSearchPlugin } from './plugins/text-search-plugin';
37
+ export { createLlmTextMutationPlugin } from './plugins/text-mutation-plugin';
38
+ export { createLlmRagPlugin } from './plugins/rag-plugin';
39
+ // Embedder utilities
40
+ export { buildEmbedder, buildEmbedderFromModule, buildEmbedderFromEnv, } from './embedder';
41
+ // Chat completion utilities
42
+ export { buildChatCompleter, buildChatCompleterFromModule, buildChatCompleterFromEnv, } from './chat';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * LlmModulePlugin
3
+ *
4
+ * Detects and loads the `llm_module` configuration from `services_public.api_modules`.
5
+ * Makes the resolved embedder available to other plugins via the build context.
6
+ *
7
+ * This plugin is the foundation that enables per-database LLM configuration.
8
+ * When an API has an `llm_module` configured, the embedder is resolved and
9
+ * stored on the build object for other plugins (text search, text mutations)
10
+ * to consume.
11
+ *
12
+ * Resolution order for the embedder:
13
+ * 1. `llm_module` from api_modules (per-database, loaded at schema build time)
14
+ * 2. `defaultEmbedder` from preset options (dev/testing fallback)
15
+ * 3. Environment variables (EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL)
16
+ * 4. null — LLM features are disabled
17
+ */
18
+ import type { GraphileConfig } from 'graphile-config';
19
+ import type { EmbedderFunction, ChatFunction, GraphileLlmOptions } from '../types';
20
+ declare global {
21
+ namespace GraphileBuild {
22
+ interface Build {
23
+ /** The resolved embedder function, or null if LLM is not configured */
24
+ llmEmbedder: EmbedderFunction | null;
25
+ /** The resolved chat completion function, or null if not configured */
26
+ llmChatCompleter: ChatFunction | null;
27
+ }
28
+ }
29
+ namespace GraphileConfig {
30
+ interface Plugins {
31
+ LlmModulePlugin: true;
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * Creates the LlmModulePlugin with the given options.
37
+ */
38
+ export declare function createLlmModulePlugin(options?: GraphileLlmOptions): GraphileConfig.Plugin;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * LlmModulePlugin
3
+ *
4
+ * Detects and loads the `llm_module` configuration from `services_public.api_modules`.
5
+ * Makes the resolved embedder available to other plugins via the build context.
6
+ *
7
+ * This plugin is the foundation that enables per-database LLM configuration.
8
+ * When an API has an `llm_module` configured, the embedder is resolved and
9
+ * stored on the build object for other plugins (text search, text mutations)
10
+ * to consume.
11
+ *
12
+ * Resolution order for the embedder:
13
+ * 1. `llm_module` from api_modules (per-database, loaded at schema build time)
14
+ * 2. `defaultEmbedder` from preset options (dev/testing fallback)
15
+ * 3. Environment variables (EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL)
16
+ * 4. null — LLM features are disabled
17
+ */
18
+ import { buildEmbedder, buildEmbedderFromEnv } from '../embedder';
19
+ import { buildChatCompleter, buildChatCompleterFromEnv } from '../chat';
20
+ /**
21
+ * Creates the LlmModulePlugin with the given options.
22
+ */
23
+ export function createLlmModulePlugin(options = {}) {
24
+ const { defaultEmbedder, defaultChatCompleter } = options;
25
+ return {
26
+ name: 'LlmModulePlugin',
27
+ version: '0.1.0',
28
+ description: 'Resolves LLM embedder and chat completer configuration and makes them available to other plugins',
29
+ schema: {
30
+ hooks: {
31
+ build(build) {
32
+ // Resolve the embedder from available sources:
33
+ // 1. Preset default embedder option
34
+ // 2. Environment variables
35
+ // 3. null (disabled)
36
+ //
37
+ // Note: Per-database llm_module resolution happens at request time,
38
+ // not schema build time. The defaultEmbedder and env vars provide
39
+ // the schema-build-time embedder so that text fields are registered
40
+ // in the GraphQL schema. At execution time, the actual embedder
41
+ // used may differ per-database based on the llm_module config.
42
+ let embedder = null;
43
+ if (defaultEmbedder) {
44
+ embedder = buildEmbedder(defaultEmbedder);
45
+ }
46
+ if (!embedder) {
47
+ embedder = buildEmbedderFromEnv();
48
+ }
49
+ if (embedder) {
50
+ console.log('[graphile-llm] Embedder configured — LLM text fields will be enabled');
51
+ }
52
+ else {
53
+ console.log('[graphile-llm] No embedder configured. Set defaultEmbedder in preset options ' +
54
+ 'or EMBEDDER_PROVIDER env var to enable text-to-vector fields.');
55
+ }
56
+ // Resolve the chat completer from available sources:
57
+ // 1. Preset default chat completer option
58
+ // 2. Environment variables
59
+ // 3. null (disabled — RAG queries will error)
60
+ let chat = null;
61
+ if (defaultChatCompleter) {
62
+ chat = buildChatCompleter(defaultChatCompleter);
63
+ }
64
+ if (!chat) {
65
+ chat = buildChatCompleterFromEnv();
66
+ }
67
+ if (chat) {
68
+ console.log('[graphile-llm] Chat completer configured — RAG queries will be enabled');
69
+ }
70
+ else {
71
+ console.log('[graphile-llm] No chat completer configured. Set defaultChatCompleter in preset ' +
72
+ 'options or CHAT_PROVIDER env var to enable RAG queries.');
73
+ }
74
+ return build.extend(build, {
75
+ llmEmbedder: embedder,
76
+ llmChatCompleter: chat,
77
+ }, 'LlmModulePlugin adding llmEmbedder and llmChatCompleter to build');
78
+ },
79
+ },
80
+ },
81
+ };
82
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * LlmRagPlugin
3
+ *
4
+ * Adds RAG (Retrieval-Augmented Generation) query support to PostGraphile v5.
5
+ *
6
+ * When enabled, this plugin:
7
+ * 1. Discovers tables with @hasChunks smart tag during schema build
8
+ * 2. Adds a `ragQuery` root query field that orchestrates:
9
+ * embed prompt → pgvector search chunks → assemble context → call chat LLM → return answer
10
+ * 3. Adds an `embedText` root query field for standalone text-to-vector conversion
11
+ *
12
+ * Uses the extendSchema + grafast lambda pattern (same as bucket-provisioner
13
+ * and presigned-url plugins) for async operations at execution time.
14
+ *
15
+ * RAG is a consumer of graphile-search's pgvector adapter — it uses the existing
16
+ * chunk-aware tables but orchestrates the full LLM synthesis pipeline.
17
+ *
18
+ * Resolution order for embedder and chat completer:
19
+ * 1. build.llmEmbedder / build.llmChatCompleter (from LlmModulePlugin)
20
+ * 2. Falls back to error if not configured
21
+ */
22
+ import type { GraphileConfig } from 'graphile-config';
23
+ import type { RagDefaults } from '../types';
24
+ declare global {
25
+ namespace GraphileConfig {
26
+ interface Plugins {
27
+ LlmRagPlugin: true;
28
+ }
29
+ }
30
+ }
31
+ /**
32
+ * Creates the LlmRagPlugin.
33
+ *
34
+ * @param ragDefaults - Default configuration for RAG queries
35
+ */
36
+ export declare function createLlmRagPlugin(ragDefaults?: RagDefaults): GraphileConfig.Plugin;