@@ -3,7 +3,10 @@ import {
3
3
UsageMetadata ,
4
4
type BaseMessage ,
5
5
} from "@langchain/core/messages" ;
6
- import { BaseLanguageModelInput } from "@langchain/core/language_models/base" ;
6
+ import {
7
+ BaseLanguageModelInput ,
8
+ StructuredOutputMethodOptions ,
9
+ } from "@langchain/core/language_models/base" ;
7
10
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager" ;
8
11
import {
9
12
type BaseChatModelParams ,
@@ -21,9 +24,20 @@ import type {
21
24
Message as OllamaMessage ,
22
25
Tool as OllamaTool ,
23
26
} from "ollama" ;
24
- import { Runnable } from "@langchain/core/runnables" ;
27
+ import {
28
+ Runnable ,
29
+ RunnablePassthrough ,
30
+ RunnableSequence ,
31
+ } from "@langchain/core/runnables" ;
25
32
import { convertToOpenAITool } from "@langchain/core/utils/function_calling" ;
26
33
import { concat } from "@langchain/core/utils/stream" ;
34
+ import {
35
+ JsonOutputParser ,
36
+ StructuredOutputParser ,
37
+ } from "@langchain/core/output_parsers" ;
38
+ import { isZodSchema } from "@langchain/core/utils/types" ;
39
+ import { z } from "zod" ;
40
+ import { zodToJsonSchema } from "zod-to-json-schema" ;
27
41
import {
28
42
convertOllamaMessagesToLangChain ,
29
43
convertToOllamaMessages ,
@@ -36,6 +50,8 @@ export interface ChatOllamaCallOptions extends BaseChatModelCallOptions {
36
50
*/
37
51
stop ?: string [ ] ;
38
52
tools ?: BindToolsInput [ ] ;
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ format ?: string | Record < string , any > ;
39
55
}
40
56
41
57
export interface PullModelOptions {
@@ -82,7 +98,8 @@ export interface ChatOllamaInput
82
98
*/
83
99
checkOrPullModel ?: boolean ;
84
100
streaming ?: boolean ;
85
- format ?: string ;
101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
102
+ format ?: string | Record < string , any > ;
86
103
}
87
104
88
105
/**
@@ -453,7 +470,8 @@ export class ChatOllama
453
470
454
471
streaming ?: boolean ;
455
472
456
- format ?: string ;
473
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
474
+ format ?: string | Record < string , any > ;
457
475
458
476
keepAlive ?: string | number ;
459
477
@@ -575,7 +593,7 @@ export class ChatOllama
575
593
576
594
return {
577
595
model : this . model ,
578
- format : this . format ,
596
+ format : options ?. format ?? this . format ,
579
597
keep_alive : this . keepAlive ,
580
598
options : {
581
599
numa : this . numa ,
@@ -763,4 +781,109 @@ export class ChatOllama
763
781
} ) ,
764
782
} ) ;
765
783
}
784
+
785
+ withStructuredOutput <
786
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
787
+ RunOutput extends Record < string , any > = Record < string , any >
788
+ > (
789
+ outputSchema :
790
+ | z . ZodType < RunOutput >
791
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
792
+ | Record < string , any > ,
793
+ config ?: StructuredOutputMethodOptions < false >
794
+ ) : Runnable < BaseLanguageModelInput , RunOutput > ;
795
+
796
+ withStructuredOutput <
797
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
798
+ RunOutput extends Record < string , any > = Record < string , any >
799
+ > (
800
+ outputSchema :
801
+ | z . ZodType < RunOutput >
802
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
803
+ | Record < string , any > ,
804
+ config ?: StructuredOutputMethodOptions < true >
805
+ ) : Runnable < BaseLanguageModelInput , { raw : BaseMessage ; parsed : RunOutput } > ;
806
+
807
+ withStructuredOutput <
808
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
809
+ RunOutput extends Record < string , any > = Record < string , any >
810
+ > (
811
+ outputSchema :
812
+ | z . ZodType < RunOutput >
813
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
814
+ | Record < string , any > ,
815
+ config ?: StructuredOutputMethodOptions < boolean >
816
+ ) :
817
+ | Runnable < BaseLanguageModelInput , RunOutput >
818
+ | Runnable <
819
+ BaseLanguageModelInput ,
820
+ {
821
+ raw : BaseMessage ;
822
+ parsed : RunOutput ;
823
+ }
824
+ > ;
825
+
826
+ withStructuredOutput <
827
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
828
+ RunOutput extends Record < string , any > = Record < string , any >
829
+ > (
830
+ outputSchema :
831
+ | z . ZodType < RunOutput >
832
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
833
+ | Record < string , any > ,
834
+ config ?: StructuredOutputMethodOptions < boolean >
835
+ ) :
836
+ | Runnable < BaseLanguageModelInput , RunOutput >
837
+ | Runnable <
838
+ BaseLanguageModelInput ,
839
+ {
840
+ raw : BaseMessage ;
841
+ parsed : RunOutput ;
842
+ }
843
+ > {
844
+ // TODO: Make this method the default in a minor bump
845
+ if ( config ?. method === "jsonSchema" ) {
846
+ const outputSchemaIsZod = isZodSchema ( outputSchema ) ;
847
+ const jsonSchema = outputSchemaIsZod
848
+ ? zodToJsonSchema ( outputSchema )
849
+ : outputSchema ;
850
+ const llm = this . bind ( {
851
+ format : jsonSchema ,
852
+ } ) ;
853
+ const outputParser = outputSchemaIsZod
854
+ ? StructuredOutputParser . fromZodSchema ( outputSchema )
855
+ : new JsonOutputParser < RunOutput > ( ) ;
856
+
857
+ if ( ! config ?. includeRaw ) {
858
+ return llm . pipe ( outputParser ) as Runnable <
859
+ BaseLanguageModelInput ,
860
+ RunOutput
861
+ > ;
862
+ }
863
+
864
+ const parserAssign = RunnablePassthrough . assign ( {
865
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
866
+ parsed : ( input : any , config ) => outputParser . invoke ( input . raw , config ) ,
867
+ } ) ;
868
+ const parserNone = RunnablePassthrough . assign ( {
869
+ parsed : ( ) => null ,
870
+ } ) ;
871
+ const parsedWithFallback = parserAssign . withFallbacks ( {
872
+ fallbacks : [ parserNone ] ,
873
+ } ) ;
874
+ return RunnableSequence . from <
875
+ BaseLanguageModelInput ,
876
+ { raw : BaseMessage ; parsed : RunOutput }
877
+ > ( [
878
+ {
879
+ raw : llm ,
880
+ } ,
881
+ parsedWithFallback ,
882
+ ] ) ;
883
+ } else {
884
+ // TODO: Fix this type in core
885
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
886
+ return super . withStructuredOutput < RunOutput > ( outputSchema , config as any ) ;
887
+ }
888
+ }
766
889
}
0 commit comments