@nextsparkjs/plugin-langchain 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 (67) hide show
  1. package/.env.example +41 -0
  2. package/api/observability/metrics/route.ts +110 -0
  3. package/api/observability/traces/[traceId]/route.ts +398 -0
  4. package/api/observability/traces/route.ts +205 -0
  5. package/api/sessions/route.ts +332 -0
  6. package/components/observability/CollapsibleJson.tsx +71 -0
  7. package/components/observability/CompactTimeline.tsx +75 -0
  8. package/components/observability/ConversationFlow.tsx +271 -0
  9. package/components/observability/DisabledMessage.tsx +21 -0
  10. package/components/observability/FiltersPanel.tsx +82 -0
  11. package/components/observability/ObservabilityDashboard.tsx +230 -0
  12. package/components/observability/SpansList.tsx +210 -0
  13. package/components/observability/TraceDetail.tsx +335 -0
  14. package/components/observability/TraceStatusBadge.tsx +39 -0
  15. package/components/observability/TracesTable.tsx +97 -0
  16. package/components/observability/index.ts +7 -0
  17. package/docs/01-getting-started/01-overview.md +196 -0
  18. package/docs/01-getting-started/02-installation.md +368 -0
  19. package/docs/01-getting-started/03-configuration.md +794 -0
  20. package/docs/02-core-concepts/01-architecture.md +566 -0
  21. package/docs/02-core-concepts/02-agents.md +597 -0
  22. package/docs/02-core-concepts/03-tools.md +689 -0
  23. package/docs/03-orchestration/01-graph-orchestrator.md +809 -0
  24. package/docs/03-orchestration/02-legacy-react.md +650 -0
  25. package/docs/04-advanced/01-observability.md +645 -0
  26. package/docs/04-advanced/02-token-tracking.md +469 -0
  27. package/docs/04-advanced/03-streaming.md +476 -0
  28. package/docs/04-advanced/04-guardrails.md +597 -0
  29. package/docs/05-reference/01-api-reference.md +1403 -0
  30. package/docs/05-reference/02-customization.md +646 -0
  31. package/docs/05-reference/03-examples.md +881 -0
  32. package/docs/index.md +85 -0
  33. package/hooks/observability/useMetrics.ts +31 -0
  34. package/hooks/observability/useTraceDetail.ts +48 -0
  35. package/hooks/observability/useTraces.ts +59 -0
  36. package/lib/agent-factory.ts +354 -0
  37. package/lib/agent-helpers.ts +201 -0
  38. package/lib/db-memory-store.ts +417 -0
  39. package/lib/graph/index.ts +58 -0
  40. package/lib/graph/nodes/combiner.ts +399 -0
  41. package/lib/graph/nodes/router.ts +440 -0
  42. package/lib/graph/orchestrator-graph.ts +386 -0
  43. package/lib/graph/prompts/combiner.md +131 -0
  44. package/lib/graph/prompts/router.md +193 -0
  45. package/lib/graph/types.ts +365 -0
  46. package/lib/guardrails.ts +230 -0
  47. package/lib/index.ts +44 -0
  48. package/lib/logger.ts +70 -0
  49. package/lib/memory-store.ts +168 -0
  50. package/lib/message-serializer.ts +110 -0
  51. package/lib/prompt-renderer.ts +94 -0
  52. package/lib/providers.ts +226 -0
  53. package/lib/streaming.ts +232 -0
  54. package/lib/token-tracker.ts +298 -0
  55. package/lib/tools-builder.ts +192 -0
  56. package/lib/tracer-callbacks.ts +342 -0
  57. package/lib/tracer.ts +350 -0
  58. package/migrations/001_langchain_memory.sql +83 -0
  59. package/migrations/002_token_usage.sql +127 -0
  60. package/migrations/003_observability.sql +257 -0
  61. package/package.json +28 -0
  62. package/plugin.config.ts +170 -0
  63. package/presets/lib/langchain.config.ts.preset +142 -0
  64. package/presets/templates/sector7/ai-observability/[traceId]/page.tsx +91 -0
  65. package/presets/templates/sector7/ai-observability/page.tsx +54 -0
  66. package/types/langchain.types.ts +274 -0
  67. package/types/observability.types.ts +270 -0
@@ -0,0 +1,257 @@
1
+ -- Migration: 003_observability.sql
2
+ -- Description: LangChain observability (traces, spans, metrics tracking)
3
+ -- Date: 2025-12-22
4
+
5
+ -- ============================================
6
+ -- TABLE: Traces (Main trace records)
7
+ -- ============================================
8
+ DROP TABLE IF EXISTS public."langchain_traces" CASCADE;
9
+
10
+ CREATE TABLE IF NOT EXISTS public."langchain_traces" (
11
+ -- Primary key
12
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
13
+
14
+ -- Unique trace identifier
15
+ "traceId" TEXT NOT NULL UNIQUE,
16
+
17
+ -- Relational fields (multi-tenancy)
18
+ "userId" TEXT NOT NULL REFERENCES "users"(id) ON DELETE CASCADE,
19
+ "teamId" TEXT NOT NULL REFERENCES "teams"(id) ON DELETE CASCADE,
20
+ "sessionId" TEXT,
21
+
22
+ -- Agent information
23
+ "agentName" TEXT NOT NULL,
24
+ "agentType" TEXT,
25
+ "parentId" TEXT,
26
+
27
+ -- Input/Output (truncatable content)
28
+ input TEXT,
29
+ output TEXT,
30
+
31
+ -- Status and error tracking
32
+ status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running', 'success', 'error')),
33
+ error TEXT,
34
+ "errorType" TEXT,
35
+ "errorStack" TEXT,
36
+
37
+ -- Timing information
38
+ "startedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
39
+ "endedAt" TIMESTAMPTZ,
40
+ "durationMs" INTEGER,
41
+
42
+ -- Token usage and cost
43
+ "inputTokens" INTEGER DEFAULT 0,
44
+ "outputTokens" INTEGER DEFAULT 0,
45
+ "totalTokens" INTEGER DEFAULT 0,
46
+ "totalCost" DECIMAL(12, 6) DEFAULT 0,
47
+
48
+ -- Call counts
49
+ "llmCalls" INTEGER DEFAULT 0,
50
+ "toolCalls" INTEGER DEFAULT 0,
51
+
52
+ -- Additional metadata
53
+ metadata JSONB DEFAULT '{}'::jsonb,
54
+ tags TEXT[],
55
+
56
+ -- System fields
57
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
58
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
59
+ );
60
+
61
+ -- ============================================
62
+ -- COMMENTS: Traces Table
63
+ -- ============================================
64
+ COMMENT ON TABLE public."langchain_traces" IS 'LangChain agent invocation traces for observability';
65
+ COMMENT ON COLUMN public."langchain_traces".id IS 'Unique row identifier';
66
+ COMMENT ON COLUMN public."langchain_traces"."traceId" IS 'Unique trace identifier (gen by tracer)';
67
+ COMMENT ON COLUMN public."langchain_traces"."userId" IS 'User who triggered the agent invocation';
68
+ COMMENT ON COLUMN public."langchain_traces"."teamId" IS 'Team context for multi-tenancy';
69
+ COMMENT ON COLUMN public."langchain_traces"."sessionId" IS 'Optional session identifier';
70
+ COMMENT ON COLUMN public."langchain_traces"."agentName" IS 'Name of the agent that was invoked';
71
+ COMMENT ON COLUMN public."langchain_traces"."agentType" IS 'Type/category of agent';
72
+ COMMENT ON COLUMN public."langchain_traces"."parentId" IS 'Parent trace ID for nested agent calls';
73
+ COMMENT ON COLUMN public."langchain_traces".input IS 'Agent input (truncated if too long)';
74
+ COMMENT ON COLUMN public."langchain_traces".output IS 'Agent output (truncated if too long)';
75
+ COMMENT ON COLUMN public."langchain_traces".status IS 'Trace status: running, success, error';
76
+ COMMENT ON COLUMN public."langchain_traces".error IS 'Error message if failed';
77
+ COMMENT ON COLUMN public."langchain_traces"."errorType" IS 'Error type/category';
78
+ COMMENT ON COLUMN public."langchain_traces"."errorStack" IS 'Error stack trace';
79
+ COMMENT ON COLUMN public."langchain_traces"."startedAt" IS 'Trace start timestamp';
80
+ COMMENT ON COLUMN public."langchain_traces"."endedAt" IS 'Trace end timestamp';
81
+ COMMENT ON COLUMN public."langchain_traces"."durationMs" IS 'Total duration in milliseconds';
82
+ COMMENT ON COLUMN public."langchain_traces"."inputTokens" IS 'Total input tokens across all LLM calls';
83
+ COMMENT ON COLUMN public."langchain_traces"."outputTokens" IS 'Total output tokens across all LLM calls';
84
+ COMMENT ON COLUMN public."langchain_traces"."totalTokens" IS 'Total tokens (input + output)';
85
+ COMMENT ON COLUMN public."langchain_traces"."totalCost" IS 'Total cost in USD';
86
+ COMMENT ON COLUMN public."langchain_traces"."llmCalls" IS 'Number of LLM calls in trace';
87
+ COMMENT ON COLUMN public."langchain_traces"."toolCalls" IS 'Number of tool calls in trace';
88
+ COMMENT ON COLUMN public."langchain_traces".metadata IS 'Additional trace metadata';
89
+ COMMENT ON COLUMN public."langchain_traces".tags IS 'Tags for filtering and categorization';
90
+ COMMENT ON COLUMN public."langchain_traces"."createdAt" IS 'Record creation timestamp';
91
+ COMMENT ON COLUMN public."langchain_traces"."updatedAt" IS 'Record last update timestamp';
92
+
93
+ -- ============================================
94
+ -- INDEXES: Traces Table
95
+ -- ============================================
96
+ CREATE INDEX IF NOT EXISTS idx_traces_trace_id ON public."langchain_traces"("traceId");
97
+ CREATE INDEX IF NOT EXISTS idx_traces_user_id ON public."langchain_traces"("userId");
98
+ CREATE INDEX IF NOT EXISTS idx_traces_team_id ON public."langchain_traces"("teamId");
99
+ CREATE INDEX IF NOT EXISTS idx_traces_team_time ON public."langchain_traces"("teamId", "startedAt" DESC);
100
+ CREATE INDEX IF NOT EXISTS idx_traces_status ON public."langchain_traces"(status) WHERE status != 'success';
101
+ CREATE INDEX IF NOT EXISTS idx_traces_agent ON public."langchain_traces"("agentName", "startedAt" DESC);
102
+ CREATE INDEX IF NOT EXISTS idx_traces_parent_id ON public."langchain_traces"("parentId") WHERE "parentId" IS NOT NULL;
103
+ CREATE INDEX IF NOT EXISTS idx_traces_session ON public."langchain_traces"("sessionId") WHERE "sessionId" IS NOT NULL;
104
+ CREATE INDEX IF NOT EXISTS idx_traces_created_at ON public."langchain_traces"("createdAt" DESC);
105
+ CREATE INDEX IF NOT EXISTS idx_traces_user_created_at ON public."langchain_traces"("userId", "createdAt" DESC);
106
+
107
+ -- ============================================
108
+ -- TRIGGER: Traces updatedAt
109
+ -- ============================================
110
+ DROP TRIGGER IF EXISTS langchain_traces_set_updated_at ON public."langchain_traces";
111
+ CREATE TRIGGER langchain_traces_set_updated_at
112
+ BEFORE UPDATE ON public."langchain_traces"
113
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
114
+
115
+ -- ============================================
116
+ -- TABLE: Spans (Individual operations)
117
+ -- ============================================
118
+ CREATE TABLE IF NOT EXISTS public."langchain_spans" (
119
+ -- Primary key
120
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
121
+
122
+ -- Unique span identifier
123
+ "spanId" TEXT NOT NULL UNIQUE,
124
+
125
+ -- Relational fields
126
+ "traceId" TEXT NOT NULL REFERENCES public."langchain_traces"("traceId") ON DELETE CASCADE,
127
+ "parentSpanId" TEXT,
128
+
129
+ -- Span information
130
+ name TEXT NOT NULL,
131
+ type TEXT NOT NULL CHECK (type IN ('llm', 'tool', 'chain', 'retriever')),
132
+
133
+ -- LLM-specific fields
134
+ provider TEXT,
135
+ model TEXT,
136
+ "inputTokens" INTEGER,
137
+ "outputTokens" INTEGER,
138
+
139
+ -- Tool-specific fields
140
+ "toolName" TEXT,
141
+ "toolInput" JSONB,
142
+ "toolOutput" JSONB,
143
+
144
+ -- Generic input/output
145
+ input JSONB,
146
+ output JSONB,
147
+
148
+ -- Status and error tracking
149
+ status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running', 'success', 'error')),
150
+ error TEXT,
151
+
152
+ -- Timing information
153
+ "startedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
154
+ "endedAt" TIMESTAMPTZ,
155
+ "durationMs" INTEGER,
156
+
157
+ -- Hierarchy depth
158
+ depth INTEGER DEFAULT 0,
159
+
160
+ -- System fields
161
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
162
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
163
+ );
164
+
165
+ -- ============================================
166
+ -- COMMENTS: Spans Table
167
+ -- ============================================
168
+ COMMENT ON TABLE public."langchain_spans" IS 'Individual operations (spans) within LangChain traces';
169
+ COMMENT ON COLUMN public."langchain_spans".id IS 'Unique row identifier';
170
+ COMMENT ON COLUMN public."langchain_spans"."spanId" IS 'Unique span identifier';
171
+ COMMENT ON COLUMN public."langchain_spans"."traceId" IS 'Parent trace identifier';
172
+ COMMENT ON COLUMN public."langchain_spans"."parentSpanId" IS 'Parent span ID for nested operations';
173
+ COMMENT ON COLUMN public."langchain_spans".name IS 'Span name/description';
174
+ COMMENT ON COLUMN public."langchain_spans".type IS 'Span type: llm, tool, chain, retriever';
175
+ COMMENT ON COLUMN public."langchain_spans".provider IS 'LLM provider (openai, anthropic, etc)';
176
+ COMMENT ON COLUMN public."langchain_spans".model IS 'LLM model name';
177
+ COMMENT ON COLUMN public."langchain_spans"."inputTokens" IS 'Input tokens (LLM spans)';
178
+ COMMENT ON COLUMN public."langchain_spans"."outputTokens" IS 'Output tokens (LLM spans)';
179
+ COMMENT ON COLUMN public."langchain_spans"."toolName" IS 'Tool name (tool spans)';
180
+ COMMENT ON COLUMN public."langchain_spans"."toolInput" IS 'Tool input data (tool spans)';
181
+ COMMENT ON COLUMN public."langchain_spans"."toolOutput" IS 'Tool output data (tool spans)';
182
+ COMMENT ON COLUMN public."langchain_spans".input IS 'Generic span input';
183
+ COMMENT ON COLUMN public."langchain_spans".output IS 'Generic span output';
184
+ COMMENT ON COLUMN public."langchain_spans".status IS 'Span status: running, success, error';
185
+ COMMENT ON COLUMN public."langchain_spans".error IS 'Error message if failed';
186
+ COMMENT ON COLUMN public."langchain_spans"."startedAt" IS 'Span start timestamp';
187
+ COMMENT ON COLUMN public."langchain_spans"."endedAt" IS 'Span end timestamp';
188
+ COMMENT ON COLUMN public."langchain_spans"."durationMs" IS 'Span duration in milliseconds';
189
+ COMMENT ON COLUMN public."langchain_spans".depth IS 'Nesting depth in span tree';
190
+ COMMENT ON COLUMN public."langchain_spans"."createdAt" IS 'Record creation timestamp';
191
+ COMMENT ON COLUMN public."langchain_spans"."updatedAt" IS 'Record last update timestamp';
192
+
193
+ -- ============================================
194
+ -- INDEXES: Spans Table
195
+ -- ============================================
196
+ CREATE INDEX IF NOT EXISTS idx_spans_span_id ON public."langchain_spans"("spanId");
197
+ CREATE INDEX IF NOT EXISTS idx_spans_trace_id ON public."langchain_spans"("traceId");
198
+ CREATE INDEX IF NOT EXISTS idx_spans_trace_time ON public."langchain_spans"("traceId", "startedAt");
199
+ CREATE INDEX IF NOT EXISTS idx_spans_parent_id ON public."langchain_spans"("parentSpanId") WHERE "parentSpanId" IS NOT NULL;
200
+ CREATE INDEX IF NOT EXISTS idx_spans_type ON public."langchain_spans"(type);
201
+ CREATE INDEX IF NOT EXISTS idx_spans_provider_model ON public."langchain_spans"(provider, model) WHERE type = 'llm';
202
+ CREATE INDEX IF NOT EXISTS idx_spans_tool_name ON public."langchain_spans"("toolName") WHERE type = 'tool';
203
+ CREATE INDEX IF NOT EXISTS idx_spans_created_at ON public."langchain_spans"("createdAt" DESC);
204
+
205
+ -- ============================================
206
+ -- TRIGGER: Spans updatedAt
207
+ -- ============================================
208
+ DROP TRIGGER IF EXISTS langchain_spans_set_updated_at ON public."langchain_spans";
209
+ CREATE TRIGGER langchain_spans_set_updated_at
210
+ BEFORE UPDATE ON public."langchain_spans"
211
+ FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
212
+
213
+ -- ============================================
214
+ -- RLS: Traces Table (Superadmin sees all)
215
+ -- ============================================
216
+ ALTER TABLE public."langchain_traces" ENABLE ROW LEVEL SECURITY;
217
+
218
+ DROP POLICY IF EXISTS "langchain_traces_owner_access" ON public."langchain_traces";
219
+ DROP POLICY IF EXISTS "langchain_traces_superadmin_access" ON public."langchain_traces";
220
+
221
+ -- Users can view their own traces
222
+ CREATE POLICY "langchain_traces_owner_access"
223
+ ON public."langchain_traces"
224
+ FOR ALL TO authenticated
225
+ USING ("userId" = public.get_auth_user_id());
226
+
227
+ -- Superadmins can view all traces
228
+ CREATE POLICY "langchain_traces_superadmin_access"
229
+ ON public."langchain_traces"
230
+ FOR ALL TO authenticated
231
+ USING (public.is_superadmin());
232
+
233
+ -- ============================================
234
+ -- RLS: Spans Table (Inherit from traces)
235
+ -- ============================================
236
+ ALTER TABLE public."langchain_spans" ENABLE ROW LEVEL SECURITY;
237
+
238
+ DROP POLICY IF EXISTS "langchain_spans_owner_access" ON public."langchain_spans";
239
+ DROP POLICY IF EXISTS "langchain_spans_superadmin_access" ON public."langchain_spans";
240
+
241
+ -- Users can view spans from their own traces
242
+ CREATE POLICY "langchain_spans_owner_access"
243
+ ON public."langchain_spans"
244
+ FOR ALL TO authenticated
245
+ USING (
246
+ EXISTS (
247
+ SELECT 1 FROM public."langchain_traces" t
248
+ WHERE t."traceId" = "langchain_spans"."traceId"
249
+ AND t."userId" = public.get_auth_user_id()
250
+ )
251
+ );
252
+
253
+ -- Superadmins can view all spans
254
+ CREATE POLICY "langchain_spans_superadmin_access"
255
+ ON public."langchain_spans"
256
+ FOR ALL TO authenticated
257
+ USING (public.is_superadmin());
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@nextsparkjs/plugin-langchain",
3
+ "version": "0.1.0-beta.1",
4
+ "private": false,
5
+ "main": "./plugin.config.ts",
6
+ "requiredPlugins": [],
7
+ "dependencies": {
8
+ "@anthropic-ai/sdk": "^0.36.0",
9
+ "@langchain/anthropic": "^0.3.0",
10
+ "@langchain/community": "^0.3.0",
11
+ "@langchain/core": "^0.3.0",
12
+ "@langchain/langgraph": "^0.2.0",
13
+ "@langchain/ollama": "^0.1.0",
14
+ "@langchain/openai": "^0.3.0",
15
+ "handlebars": "^4.7.8",
16
+ "langchain": "^0.3.0"
17
+ },
18
+ "peerDependencies": {
19
+ "@nextsparkjs/core": "workspace:*",
20
+ "@tanstack/react-query": "^5.0.0",
21
+ "lucide-react": "^0.539.0",
22
+ "next": "^15.0.0",
23
+ "next-intl": "^4.0.0",
24
+ "react": "^19.0.0",
25
+ "react-dom": "^19.0.0",
26
+ "zod": "^4.0.0"
27
+ }
28
+ }
@@ -0,0 +1,170 @@
1
+ import type { PluginConfig } from '@nextsparkjs/core/types/plugin'
2
+ import type { LLMProvider } from './types/langchain.types'
3
+
4
+ /**
5
+ * LangChain Plugin Configuration
6
+ *
7
+ * Environment variables:
8
+ * - LANGCHAIN_PLUGIN_ENABLED: Enable/disable the plugin
9
+ * - LANGCHAIN_PLUGIN_DEBUG: Enable debug console logging
10
+ *
11
+ * File logging:
12
+ * - LOG_ENABLED: Enable file logging (core environment variable)
13
+ *
14
+ * Ollama (local):
15
+ * - LANGCHAIN_OLLAMA_BASE_URL: Ollama server URL (default: http://localhost:11434)
16
+ * - LANGCHAIN_OLLAMA_MODEL: Ollama model (default: llama3.2:3b)
17
+ *
18
+ * OpenAI-compatible (LM Studio, LocalAI, etc.):
19
+ * - LANGCHAIN_OPENAI_BASE_URL: Server URL (e.g., http://localhost:1234/v1)
20
+ * - LANGCHAIN_OPENAI_MODEL: Model name
21
+ * - OPENAI_API_KEY: API key (use "lm-studio" for local servers)
22
+ */
23
+ export const config = {
24
+ enabled: process.env.LANGCHAIN_PLUGIN_ENABLED === 'true',
25
+ debug: process.env.LANGCHAIN_PLUGIN_DEBUG === 'true',
26
+
27
+ /** Default provider when not specified per-agent */
28
+ defaultProvider: (process.env.LANGCHAIN_DEFAULT_PROVIDER || 'ollama') as LLMProvider,
29
+
30
+ /** Default temperature for all providers */
31
+ defaultTemperature: 0.1,
32
+
33
+ /** Provider-specific configurations */
34
+ providers: {
35
+ openai: {
36
+ apiKey: process.env.OPENAI_API_KEY,
37
+ baseUrl: process.env.LANGCHAIN_OPENAI_BASE_URL,
38
+ model: process.env.LANGCHAIN_OPENAI_MODEL || 'gpt-4o-mini',
39
+ temperature: 0.1,
40
+ },
41
+ anthropic: {
42
+ apiKey: process.env.ANTHROPIC_API_KEY,
43
+ model: process.env.LANGCHAIN_ANTHROPIC_MODEL || 'claude-3-5-sonnet-20241022',
44
+ temperature: 0.1,
45
+ },
46
+ ollama: {
47
+ baseUrl: process.env.LANGCHAIN_OLLAMA_BASE_URL || 'http://localhost:11434',
48
+ model: process.env.LANGCHAIN_OLLAMA_MODEL || 'llama3.2:3b',
49
+ temperature: 0.1,
50
+ },
51
+ },
52
+ }
53
+
54
+ /**
55
+ * Validate that required configuration exists for a provider
56
+ * @throws Error if required configuration is missing
57
+ */
58
+ export function validateProviderConfig(provider: LLMProvider): void {
59
+ switch (provider) {
60
+ case 'openai':
61
+ if (!config.providers.openai.apiKey) {
62
+ throw new Error(
63
+ 'OPENAI_API_KEY environment variable is required when using OpenAI provider. ' +
64
+ 'Get your API key at https://platform.openai.com/api-keys'
65
+ )
66
+ }
67
+ break
68
+ case 'anthropic':
69
+ if (!config.providers.anthropic.apiKey) {
70
+ throw new Error(
71
+ 'ANTHROPIC_API_KEY environment variable is required when using Anthropic provider. ' +
72
+ 'Get your API key at https://console.anthropic.com/settings/keys'
73
+ )
74
+ }
75
+ break
76
+ case 'ollama':
77
+ // Ollama doesn't require API key (local)
78
+ break
79
+ default:
80
+ throw new Error(`Unsupported provider: ${provider}. Supported: openai, anthropic, ollama`)
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Check if a provider is available (has required credentials)
86
+ */
87
+ export function isProviderAvailable(provider: LLMProvider): boolean {
88
+ switch (provider) {
89
+ case 'openai':
90
+ return !!config.providers.openai.apiKey
91
+ case 'anthropic':
92
+ return !!config.providers.anthropic.apiKey
93
+ case 'ollama':
94
+ return true // Ollama is always "available" (local)
95
+ default:
96
+ return false
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Get list of available providers (those with valid configuration)
102
+ */
103
+ export function getAvailableProviders(): LLMProvider[] {
104
+ return (['openai', 'anthropic', 'ollama'] as LLMProvider[]).filter(isProviderAvailable)
105
+ }
106
+
107
+ /**
108
+ * LangChain Plugin Config
109
+ *
110
+ * Provides AI agent capabilities with:
111
+ * - Multiple LLM providers (OpenAI, Anthropic, Ollama)
112
+ * - Tool system for extending agent capabilities
113
+ * - Session-based memory for conversation continuity
114
+ * - Per-agent model configuration for themes
115
+ *
116
+ * ## Usage in Themes
117
+ *
118
+ * Import directly from the lib files (NOT from plugin.config.ts to avoid circular deps):
119
+ *
120
+ * ```typescript
121
+ * import { createAgent } from '@/plugins/langchain/lib/agent-factory'
122
+ * import { buildTools, type ToolDefinition } from '@/plugins/langchain/lib/tools-builder'
123
+ * import { memoryStore } from '@/plugins/langchain/lib/memory-store'
124
+ * import { getModel } from '@/plugins/langchain/lib/providers'
125
+ *
126
+ * // Use default provider (from env or plugin config)
127
+ * const agent = await createAgent({
128
+ * sessionId: 'unique-session-id',
129
+ * systemPrompt: 'You are a helpful assistant...',
130
+ * tools: myTools,
131
+ * })
132
+ *
133
+ * // Use specific provider and model
134
+ * const agent = await createAgent({
135
+ * sessionId: 'unique-session-id',
136
+ * systemPrompt: 'You are a helpful assistant...',
137
+ * tools: myTools,
138
+ * modelConfig: {
139
+ * provider: 'openai',
140
+ * model: 'gpt-4o',
141
+ * temperature: 0.3,
142
+ * },
143
+ * })
144
+ *
145
+ * const response = await agent.chat('Hello!')
146
+ * ```
147
+ */
148
+ export const langchainPluginConfig: PluginConfig = {
149
+ name: 'langchain',
150
+ displayName: 'LangChain Agent Framework',
151
+ version: '2.0.0',
152
+ description: 'Create AI agents with tools, memory, and customizable behavior. Supports OpenAI, Anthropic, and Ollama.',
153
+ enabled: config.enabled,
154
+ dependencies: [],
155
+
156
+ hooks: {
157
+ onLoad: async () => {
158
+ if (config.debug) {
159
+ console.log('[LangChain Plugin] Loaded')
160
+ console.log('[LangChain Plugin] Default Provider:', config.defaultProvider)
161
+ console.log('[LangChain Plugin] OpenAI configured:', !!config.providers.openai.apiKey)
162
+ console.log('[LangChain Plugin] Anthropic configured:', !!config.providers.anthropic.apiKey)
163
+ console.log('[LangChain Plugin] Ollama URL:', config.providers.ollama.baseUrl)
164
+ console.log('[LangChain Plugin] Ollama Model:', config.providers.ollama.model)
165
+ }
166
+ }
167
+ }
168
+ }
169
+
170
+ export default langchainPluginConfig
@@ -0,0 +1,142 @@
1
+ /**
2
+ * ============================================================================
3
+ * LANGCHAIN CONFIGURATION PRESET
4
+ * ============================================================================
5
+ *
6
+ * This is a preset template for LangChain plugin configuration.
7
+ * Copy this file to your theme's lib/langchain/langchain.config.ts
8
+ *
9
+ * Path: contents/themes/{your-theme}/lib/langchain/langchain.config.ts
10
+ *
11
+ * ============================================================================
12
+ */
13
+
14
+ import type { ObservabilityConfig } from '@/contents/plugins/langchain/types/observability.types'
15
+ import type {
16
+ ThemeLangChainConfig,
17
+ AgentDefinition,
18
+ AgentContext,
19
+ } from '@/contents/plugins/langchain/types/langchain.types'
20
+ import { createAgentHelpers } from '@/contents/plugins/langchain/lib/agent-helpers'
21
+
22
+ // TODO: Import your tool factories
23
+ // import { createTaskTools } from './tools/tasks'
24
+ // import { createCustomerTools } from './tools/customers'
25
+
26
+ // ============================================================================
27
+ // OBSERVABILITY CONFIGURATION
28
+ // ============================================================================
29
+
30
+ export interface LangChainObservabilityConfig {
31
+ /** Observability configuration */
32
+ observability: ObservabilityConfig
33
+ }
34
+
35
+ export const observabilityConfig: LangChainObservabilityConfig = {
36
+ observability: {
37
+ /** Enable observability tracing */
38
+ enabled: true,
39
+
40
+ /** Data retention settings */
41
+ retention: {
42
+ /** Days to keep trace data */
43
+ traces: 30,
44
+ },
45
+
46
+ /** Sampling configuration */
47
+ sampling: {
48
+ /** Sample rate (0.0-1.0) - 1.0 = 100% */
49
+ rate: 1.0,
50
+ /** Always trace errors regardless of sample rate */
51
+ alwaysTraceErrors: true,
52
+ },
53
+
54
+ /** PII and content processing */
55
+ pii: {
56
+ /** Mask inputs for PII (email, phone, card, SSN patterns) */
57
+ maskInputs: false,
58
+ /** Mask outputs for PII */
59
+ maskOutputs: false,
60
+ /** Truncate content at this length (characters) */
61
+ truncateAt: 10000,
62
+ },
63
+ },
64
+ }
65
+
66
+ // ============================================================================
67
+ // AGENT DEFINITIONS
68
+ // ============================================================================
69
+
70
+ /**
71
+ * Define your agents here.
72
+ *
73
+ * Each agent has:
74
+ * - provider: LLM provider (ollama, openai, anthropic)
75
+ * - model: Model name (optional for ollama - uses LANGCHAIN_OLLAMA_MODEL env)
76
+ * - temperature: Creativity level (0-1)
77
+ * - createTools: Factory function that returns tools for this agent
78
+ * - systemPrompt: Name of the .md file in lib/langchain/agents/ folder
79
+ * - description: What this agent does (documentation)
80
+ * - sessionConfig: (optional) Memory customization (TTL, maxMessages)
81
+ * - enrichContext: (optional) Fetch runtime data for prompt templates
82
+ */
83
+ export const AGENTS: Record<string, AgentDefinition> = {
84
+ // Example: Single unified agent
85
+ 'single-agent': {
86
+ provider: 'ollama',
87
+ // model: uses LANGCHAIN_OLLAMA_MODEL from .env
88
+ temperature: 0.3,
89
+ description: 'Unified agent with access to all entity tools',
90
+ systemPrompt: 'single-agent', // loads from lib/langchain/agents/single-agent.md
91
+ createTools: (context: AgentContext) => [
92
+ // TODO: Add your tools here
93
+ // ...createTaskTools(context),
94
+ ],
95
+ },
96
+
97
+ // Example: Orchestrator for multi-agent routing
98
+ // 'orchestrator': {
99
+ // provider: 'anthropic',
100
+ // model: 'claude-3-haiku-20240307',
101
+ // temperature: 0.1,
102
+ // description: 'Routes to specialized agents',
103
+ // systemPrompt: 'orchestrator',
104
+ // createTools: () => createOrchestratorTools(),
105
+ // },
106
+ }
107
+
108
+ // ============================================================================
109
+ // THEME CONFIG (for plugin compatibility)
110
+ // ============================================================================
111
+
112
+ export const langchainConfig: ThemeLangChainConfig = {
113
+ defaultProvider: 'ollama',
114
+ defaultTemperature: 0.3,
115
+ agents: AGENTS,
116
+ }
117
+
118
+ // ============================================================================
119
+ // HELPERS (from plugin factory)
120
+ // ============================================================================
121
+
122
+ /**
123
+ * Helper functions created from the plugin's factory.
124
+ * These provide convenient access to agent configuration.
125
+ */
126
+ const helpers = createAgentHelpers(AGENTS, {
127
+ provider: langchainConfig.defaultProvider,
128
+ model: langchainConfig.defaultModel,
129
+ temperature: langchainConfig.defaultTemperature,
130
+ })
131
+
132
+ // Re-export individual helpers for convenience
133
+ export const {
134
+ getAgentConfig,
135
+ getAgentModelConfig,
136
+ getAgentTools,
137
+ getAgentPromptName,
138
+ getAgentSessionConfig,
139
+ getAgentEnrichContext,
140
+ hasAgent,
141
+ getAgentNames,
142
+ } = helpers