@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.
- package/.env.example +41 -0
- package/api/observability/metrics/route.ts +110 -0
- package/api/observability/traces/[traceId]/route.ts +398 -0
- package/api/observability/traces/route.ts +205 -0
- package/api/sessions/route.ts +332 -0
- package/components/observability/CollapsibleJson.tsx +71 -0
- package/components/observability/CompactTimeline.tsx +75 -0
- package/components/observability/ConversationFlow.tsx +271 -0
- package/components/observability/DisabledMessage.tsx +21 -0
- package/components/observability/FiltersPanel.tsx +82 -0
- package/components/observability/ObservabilityDashboard.tsx +230 -0
- package/components/observability/SpansList.tsx +210 -0
- package/components/observability/TraceDetail.tsx +335 -0
- package/components/observability/TraceStatusBadge.tsx +39 -0
- package/components/observability/TracesTable.tsx +97 -0
- package/components/observability/index.ts +7 -0
- package/docs/01-getting-started/01-overview.md +196 -0
- package/docs/01-getting-started/02-installation.md +368 -0
- package/docs/01-getting-started/03-configuration.md +794 -0
- package/docs/02-core-concepts/01-architecture.md +566 -0
- package/docs/02-core-concepts/02-agents.md +597 -0
- package/docs/02-core-concepts/03-tools.md +689 -0
- package/docs/03-orchestration/01-graph-orchestrator.md +809 -0
- package/docs/03-orchestration/02-legacy-react.md +650 -0
- package/docs/04-advanced/01-observability.md +645 -0
- package/docs/04-advanced/02-token-tracking.md +469 -0
- package/docs/04-advanced/03-streaming.md +476 -0
- package/docs/04-advanced/04-guardrails.md +597 -0
- package/docs/05-reference/01-api-reference.md +1403 -0
- package/docs/05-reference/02-customization.md +646 -0
- package/docs/05-reference/03-examples.md +881 -0
- package/docs/index.md +85 -0
- package/hooks/observability/useMetrics.ts +31 -0
- package/hooks/observability/useTraceDetail.ts +48 -0
- package/hooks/observability/useTraces.ts +59 -0
- package/lib/agent-factory.ts +354 -0
- package/lib/agent-helpers.ts +201 -0
- package/lib/db-memory-store.ts +417 -0
- package/lib/graph/index.ts +58 -0
- package/lib/graph/nodes/combiner.ts +399 -0
- package/lib/graph/nodes/router.ts +440 -0
- package/lib/graph/orchestrator-graph.ts +386 -0
- package/lib/graph/prompts/combiner.md +131 -0
- package/lib/graph/prompts/router.md +193 -0
- package/lib/graph/types.ts +365 -0
- package/lib/guardrails.ts +230 -0
- package/lib/index.ts +44 -0
- package/lib/logger.ts +70 -0
- package/lib/memory-store.ts +168 -0
- package/lib/message-serializer.ts +110 -0
- package/lib/prompt-renderer.ts +94 -0
- package/lib/providers.ts +226 -0
- package/lib/streaming.ts +232 -0
- package/lib/token-tracker.ts +298 -0
- package/lib/tools-builder.ts +192 -0
- package/lib/tracer-callbacks.ts +342 -0
- package/lib/tracer.ts +350 -0
- package/migrations/001_langchain_memory.sql +83 -0
- package/migrations/002_token_usage.sql +127 -0
- package/migrations/003_observability.sql +257 -0
- package/package.json +28 -0
- package/plugin.config.ts +170 -0
- package/presets/lib/langchain.config.ts.preset +142 -0
- package/presets/templates/sector7/ai-observability/[traceId]/page.tsx +91 -0
- package/presets/templates/sector7/ai-observability/page.tsx +54 -0
- package/types/langchain.types.ts +274 -0
- 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
|
+
}
|
package/plugin.config.ts
ADDED
|
@@ -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
|