@@ -3,16 +3,95 @@ import { AIMessage, HumanMessage, SystemMessage } from '@langchain/core/messages
33import { initChatModel } from 'langchain/chat_models/universal' ;
44
55import {
6+ AIProvider ,
7+ ChatResponse ,
68 LDAIConfig ,
7- LDAIConfigTracker ,
9+ LDAIMetrics ,
810 LDMessage ,
911 LDTokenUsage ,
1012} from '@launchdarkly/server-sdk-ai' ;
1113
1214/**
13- * LangChain provider utilities and helper functions.
15+ * LangChain implementation of AIProvider.
16+ * This provider integrates LangChain models with LaunchDarkly's tracking capabilities.
1417 */
15- export class LangChainProvider {
18+ export class LangChainProvider extends AIProvider {
19+ private _llm : BaseChatModel ;
20+
21+ constructor ( llm : BaseChatModel ) {
22+ super ( ) ;
23+ this . _llm = llm ;
24+ }
25+
26+ // =============================================================================
27+ // MAIN FACTORY METHOD
28+ // =============================================================================
29+
30+ /**
31+ * Static factory method to create a LangChain AIProvider from an AI configuration.
32+ */
33+ static async create ( aiConfig : LDAIConfig ) : Promise < LangChainProvider > {
34+ const llm = await LangChainProvider . createLangChainModel ( aiConfig ) ;
35+ return new LangChainProvider ( llm ) ;
36+ }
37+
38+ // =============================================================================
39+ // INSTANCE METHODS (AIProvider Implementation)
40+ // =============================================================================
41+
42+ /**
43+ * Invoke the LangChain model with an array of messages.
44+ */
45+ async invokeModel ( messages : LDMessage [ ] ) : Promise < ChatResponse > {
46+ // Convert LDMessage[] to LangChain messages
47+ const langchainMessages = LangChainProvider . convertMessagesToLangChain ( messages ) ;
48+
49+ // Get the LangChain response
50+ const response : AIMessage = await this . _llm . invoke ( langchainMessages ) ;
51+
52+ // Handle different content types from LangChain
53+ let content : string ;
54+ if ( typeof response . content === 'string' ) {
55+ content = response . content ;
56+ } else if ( Array . isArray ( response . content ) ) {
57+ // Handle complex content (e.g., with images)
58+ content = response . content
59+ . map ( ( item : any ) => {
60+ if ( typeof item === 'string' ) return item ;
61+ if ( item . type === 'text' ) return item . text ;
62+ return '' ;
63+ } )
64+ . join ( '' ) ;
65+ } else {
66+ content = String ( response . content ) ;
67+ }
68+
69+ // Create the assistant message
70+ const assistantMessage : LDMessage = {
71+ role : 'assistant' ,
72+ content,
73+ } ;
74+
75+ // Extract metrics including token usage and success status
76+ const metrics = LangChainProvider . createAIMetrics ( response ) ;
77+
78+ return {
79+ message : assistantMessage ,
80+ metrics,
81+ } ;
82+ }
83+
84+ /**
85+ * Get the underlying LangChain model instance.
86+ */
87+ getChatModel ( ) : BaseChatModel {
88+ return this . _llm ;
89+ }
90+
91+ // =============================================================================
92+ // STATIC UTILITY METHODS
93+ // =============================================================================
94+
1695 /**
1796 * Map LaunchDarkly provider names to LangChain provider names.
1897 * This method enables seamless integration between LaunchDarkly's standardized
@@ -29,21 +108,35 @@ export class LangChainProvider {
29108 }
30109
31110 /**
32- * Create token usage information from a LangChain provider response.
33- * This method extracts token usage information from LangChain responses
34- * and returns a LaunchDarkly TokenUsage object.
111+ * Create AI metrics information from a LangChain provider response.
112+ * This method extracts token usage information and success status from LangChain responses
113+ * and returns a LaunchDarkly AIMetrics object.
114+ *
115+ * @example
116+ * ```typescript
117+ * // Use with tracker.trackMetricsOf for automatic tracking
118+ * const response = await tracker.trackMetricsOf(
119+ * (result: AIMessage) => LangChainProvider.createAIMetrics(result),
120+ * () => llm.invoke(messages)
121+ * );
122+ * ```
35123 */
36- static createTokenUsage ( langChainResponse : AIMessage ) : LDTokenUsage | undefined {
37- if ( ! langChainResponse ?. response_metadata ?. tokenUsage ) {
38- return undefined ;
124+ static createAIMetrics ( langChainResponse : AIMessage ) : LDAIMetrics {
125+ // Extract token usage if available
126+ let usage : LDTokenUsage | undefined ;
127+ if ( langChainResponse ?. response_metadata ?. tokenUsage ) {
128+ const { tokenUsage } = langChainResponse . response_metadata ;
129+ usage = {
130+ total : tokenUsage . totalTokens || 0 ,
131+ input : tokenUsage . promptTokens || 0 ,
132+ output : tokenUsage . completionTokens || 0 ,
133+ } ;
39134 }
40135
41- const { tokenUsage } = langChainResponse . response_metadata ;
42-
136+ // LangChain responses that complete successfully are considered successful
43137 return {
44- total : tokenUsage . totalTokens || 0 ,
45- input : tokenUsage . promptTokens || 0 ,
46- output : tokenUsage . completionTokens || 0 ,
138+ success : true ,
139+ usage,
47140 } ;
48141 }
49142
@@ -69,38 +162,6 @@ export class LangChainProvider {
69162 } ) ;
70163 }
71164
72- /**
73- * Track metrics for a LangChain callable execution.
74- * This helper method enables developers to work directly with LangChain callables
75- * while ensuring consistent tracking behavior.
76- */
77- static async trackMetricsOf (
78- tracker : LDAIConfigTracker ,
79- callable : ( ) => Promise < AIMessage > ,
80- ) : Promise < AIMessage > {
81- return tracker . trackDurationOf ( async ( ) => {
82- try {
83- const result = await callable ( ) ;
84-
85- // Extract and track token usage if available
86- const tokenUsage = this . createTokenUsage ( result ) ;
87- if ( tokenUsage ) {
88- tracker . trackTokens ( {
89- total : tokenUsage . total ,
90- input : tokenUsage . input ,
91- output : tokenUsage . output ,
92- } ) ;
93- }
94-
95- tracker . trackSuccess ( ) ;
96- return result ;
97- } catch ( error ) {
98- tracker . trackError ( ) ;
99- throw error ;
100- }
101- } ) ;
102- }
103-
104165 /**
105166 * Create a LangChain model from an AI configuration.
106167 * This public helper method enables developers to initialize their own LangChain models
@@ -116,7 +177,7 @@ export class LangChainProvider {
116177
117178 // Use LangChain's universal initChatModel to support multiple providers
118179 return initChatModel ( modelName , {
119- modelProvider : this . mapProvider ( provider ) ,
180+ modelProvider : LangChainProvider . mapProvider ( provider ) ,
120181 ...parameters ,
121182 } ) ;
122183 }
0 commit comments