@@ -22,6 +22,13 @@ type ProviderToolSchemaParams<TSchemaType extends TSchema = TSchema, TResult = u
2222 model ?: ProviderRuntimeModel ;
2323 runtimeHandle ?: ProviderRuntimePluginHandle ;
2424 allowRuntimePluginLoad ?: boolean ;
25+ throwOnProviderToolSchemaError ?: boolean ;
26+ } ;
27+
28+ type ReadableProviderToolSchemaDiagnostic = {
29+ toolName : string ;
30+ toolIndex ?: number ;
31+ violations : string [ ] ;
2532} ;
2633
2734function buildProviderToolSchemaContext < TSchemaType extends TSchema = TSchema , TResult = unknown > (
@@ -49,15 +56,27 @@ export function normalizeProviderToolSchemas<
4956 TResult = unknown ,
5057> ( params : ProviderToolSchemaParams < TSchemaType , TResult > ) : AgentTool < TSchemaType , TResult > [ ] {
5158 const provider = params . provider . trim ( ) ;
52- const pluginNormalized = normalizeProviderToolSchemasWithPlugin ( {
53- provider,
54- config : params . config ,
55- workspaceDir : params . workspaceDir ,
56- env : params . env ,
57- runtimeHandle : params . runtimeHandle ,
58- allowRuntimePluginLoad : params . allowRuntimePluginLoad ,
59- context : buildProviderToolSchemaContext ( params , provider ) ,
60- } ) ;
59+ let pluginNormalized : unknown ;
60+ try {
61+ pluginNormalized = normalizeProviderToolSchemasWithPlugin ( {
62+ provider,
63+ config : params . config ,
64+ workspaceDir : params . workspaceDir ,
65+ env : params . env ,
66+ runtimeHandle : params . runtimeHandle ,
67+ allowRuntimePluginLoad : params . allowRuntimePluginLoad ,
68+ context : buildProviderToolSchemaContext ( params , provider ) ,
69+ } ) ;
70+ } catch ( error ) {
71+ if ( params . throwOnProviderToolSchemaError ) {
72+ throw error ;
73+ }
74+ log . warn (
75+ `provider tool schema normalization failed for ${ provider } ; keeping original tool schemas` ,
76+ { provider, toolCount : readToolCount ( params . tools ) , error : describeProviderHookError ( error ) } ,
77+ ) ;
78+ return params . tools ;
79+ }
6180 return Array . isArray ( pluginNormalized )
6281 ? ( pluginNormalized as AgentTool < TSchemaType , TResult > [ ] )
6382 : params . tools ;
@@ -68,31 +87,42 @@ export function normalizeProviderToolSchemas<
6887 */
6988export function logProviderToolSchemaDiagnostics ( params : ProviderToolSchemaParams ) : void {
7089 const provider = params . provider . trim ( ) ;
71- const diagnostics = inspectProviderToolSchemasWithPlugin ( {
72- provider,
73- config : params . config ,
74- workspaceDir : params . workspaceDir ,
75- env : params . env ,
76- runtimeHandle : params . runtimeHandle ,
77- allowRuntimePluginLoad : params . allowRuntimePluginLoad ,
78- context : buildProviderToolSchemaContext ( params , provider ) ,
79- } ) ;
90+ let diagnostics : unknown ;
91+ try {
92+ diagnostics = inspectProviderToolSchemasWithPlugin ( {
93+ provider,
94+ config : params . config ,
95+ workspaceDir : params . workspaceDir ,
96+ env : params . env ,
97+ runtimeHandle : params . runtimeHandle ,
98+ allowRuntimePluginLoad : params . allowRuntimePluginLoad ,
99+ context : buildProviderToolSchemaContext ( params , provider ) ,
100+ } ) ;
101+ } catch ( error ) {
102+ log . warn ( `provider tool schema diagnostics failed for ${ provider } ` , {
103+ provider,
104+ toolCount : readToolCount ( params . tools ) ,
105+ error : describeProviderHookError ( error ) ,
106+ } ) ;
107+ return ;
108+ }
80109 if ( ! Array . isArray ( diagnostics ) ) {
81110 return ;
82111 }
83- if ( diagnostics . length === 0 ) {
112+ const readableDiagnostics = readProviderToolSchemaDiagnostics ( diagnostics ) ;
113+ if ( readableDiagnostics . length === 0 ) {
84114 return ;
85115 }
86116
87- const summary = summarizeProviderToolSchemaDiagnostics ( diagnostics ) ;
117+ const summary = summarizeProviderToolSchemaDiagnostics ( readableDiagnostics ) ;
88118 log . warn (
89- `provider tool schema diagnostics: ${ diagnostics . length } ${ diagnostics . length === 1 ? "tool" : "tools" } for ${ params . provider } : ${ summary } ` ,
119+ `provider tool schema diagnostics: ${ readableDiagnostics . length } ${ readableDiagnostics . length === 1 ? "tool" : "tools" } for ${ provider } : ${ summary } ` ,
90120 {
91- provider : params . provider ,
92- toolCount : params . tools . length ,
93- diagnosticCount : diagnostics . length ,
94- tools : params . tools . map ( ( tool , index ) => ` ${ index } : ${ tool . name } ` ) ,
95- diagnostics : diagnostics . map ( ( diagnostic ) => ( {
121+ provider,
122+ toolCount : readToolCount ( params . tools ) ,
123+ diagnosticCount : readableDiagnostics . length ,
124+ tools : summarizeToolNames ( params . tools ) ,
125+ diagnostics : readableDiagnostics . map ( ( diagnostic ) => ( {
96126 index : diagnostic . toolIndex ,
97127 tool : diagnostic . toolName ,
98128 violations : diagnostic . violations . slice ( 0 , 12 ) ,
@@ -103,7 +133,7 @@ export function logProviderToolSchemaDiagnostics(params: ProviderToolSchemaParam
103133}
104134
105135function summarizeProviderToolSchemaDiagnostics (
106- diagnostics : readonly ProviderToolSchemaDiagnostic [ ] ,
136+ diagnostics : readonly ReadableProviderToolSchemaDiagnostic [ ] ,
107137) {
108138 const visible = diagnostics . slice ( 0 , 6 ) . map ( ( diagnostic ) => {
109139 const violationCount = diagnostic . violations . length ;
@@ -112,3 +142,104 @@ function summarizeProviderToolSchemaDiagnostics(
112142 const remaining = diagnostics . length - visible . length ;
113143 return remaining > 0 ? `${ visible . join ( ", " ) } , +${ remaining } more` : visible . join ( ", " ) ;
114144}
145+
146+ function describeProviderHookError ( error : unknown ) : string {
147+ if ( error instanceof Error && error . message ) {
148+ return error . message ;
149+ }
150+ return String ( error ) ;
151+ }
152+
153+ function readToolCount ( tools : readonly unknown [ ] ) : number {
154+ try {
155+ return tools . length ;
156+ } catch {
157+ return 0 ;
158+ }
159+ }
160+
161+ function summarizeToolNames ( tools : readonly AnyAgentTool [ ] ) : string [ ] {
162+ const count = readToolCount ( tools ) ;
163+ const names : string [ ] = [ ] ;
164+ for ( let index = 0 ; index < count ; index += 1 ) {
165+ try {
166+ const name = normalizeDiagnosticText ( tools [ index ] ?. name ) ?? "unknown" ;
167+ names . push ( `${ index } :${ name } ` ) ;
168+ } catch {
169+ names . push ( `${ index } :unknown` ) ;
170+ }
171+ }
172+ return names ;
173+ }
174+
175+ function readProviderToolSchemaDiagnostics (
176+ diagnostics : readonly ProviderToolSchemaDiagnostic [ ] ,
177+ ) : ReadableProviderToolSchemaDiagnostic [ ] {
178+ let count : number ;
179+ try {
180+ count = diagnostics . length ;
181+ } catch {
182+ return [ { toolName : "unknown" , violations : [ "diagnostics are unreadable" ] } ] ;
183+ }
184+ const readableDiagnostics : ReadableProviderToolSchemaDiagnostic [ ] = [ ] ;
185+ for ( let index = 0 ; index < count ; index += 1 ) {
186+ try {
187+ readableDiagnostics . push ( readProviderToolSchemaDiagnostic ( diagnostics [ index ] ) ) ;
188+ } catch {
189+ readableDiagnostics . push ( {
190+ toolName : "unknown" ,
191+ toolIndex : index ,
192+ violations : [ "diagnostic is unreadable" ] ,
193+ } ) ;
194+ }
195+ }
196+ return readableDiagnostics ;
197+ }
198+
199+ function readProviderToolSchemaDiagnostic (
200+ diagnostic : ProviderToolSchemaDiagnostic ,
201+ ) : ReadableProviderToolSchemaDiagnostic {
202+ const readableDiagnostic : ReadableProviderToolSchemaDiagnostic = {
203+ toolName : "unknown" ,
204+ violations : [ "diagnostic is unreadable" ] ,
205+ } ;
206+ try {
207+ readableDiagnostic . toolName = normalizeDiagnosticText ( diagnostic . toolName ) ?? "unknown" ;
208+ } catch {
209+ return readableDiagnostic ;
210+ }
211+ try {
212+ if ( typeof diagnostic . toolIndex === "number" && Number . isInteger ( diagnostic . toolIndex ) ) {
213+ readableDiagnostic . toolIndex = diagnostic . toolIndex ;
214+ }
215+ } catch {
216+ // Keep the diagnostic visible even if optional metadata is hostile.
217+ }
218+ try {
219+ if ( Array . isArray ( diagnostic . violations ) ) {
220+ readableDiagnostic . violations = normalizeViolationTexts ( diagnostic . violations ) ;
221+ }
222+ } catch {
223+ readableDiagnostic . violations = [ "diagnostic is unreadable" ] ;
224+ }
225+ return readableDiagnostic ;
226+ }
227+
228+ function normalizeViolationTexts ( violations : readonly unknown [ ] ) : string [ ] {
229+ const normalized : string [ ] = [ ] ;
230+ for ( const entry of violations ) {
231+ const violation = normalizeDiagnosticText ( entry ) ;
232+ if ( violation ) {
233+ normalized . push ( violation ) ;
234+ }
235+ }
236+ return normalized . length > 0 ? normalized : [ "diagnostic has no readable violations" ] ;
237+ }
238+
239+ function normalizeDiagnosticText ( value : unknown ) : string | undefined {
240+ if ( typeof value === "string" ) {
241+ const trimmed = value . trim ( ) ;
242+ return trimmed . length > 0 ? trimmed : undefined ;
243+ }
244+ return undefined ;
245+ }
0 commit comments