@@ -117,6 +117,115 @@ describe("createAgentSession tool defaults", () => {
117117 expect ( session . getActiveToolNames ( ) ) . toEqual ( [ "custom_lookup" ] ) ;
118118 } ) ;
119119
120+ it ( "drops unreadable SDK custom tool descriptors before session setup" , async ( ) => {
121+ const healthyTool : ToolDefinition = {
122+ name : "healthy_lookup" ,
123+ label : "Healthy Lookup" ,
124+ description : "Looks up a test value." ,
125+ promptSnippet : "Lookup test values" ,
126+ promptGuidelines : [ "Use healthy_lookup for test values." ] ,
127+ parameters : Type . Object ( { } ) ,
128+ execute : async ( ) => ( {
129+ content : [ { type : "text" , text : "ok" } ] ,
130+ details : { } ,
131+ } ) ,
132+ } ;
133+ const unreadableNameTool = {
134+ get name ( ) : string {
135+ throw new Error ( "boom" ) ;
136+ } ,
137+ label : "Broken" ,
138+ description : "Breaks when read." ,
139+ parameters : Type . Object ( { } ) ,
140+ execute : async ( ) => ( {
141+ content : [ { type : "text" , text : "bad" } ] ,
142+ details : { } ,
143+ } ) ,
144+ } as unknown as ToolDefinition ;
145+ const unreadableGuidelinesTool = {
146+ name : "bad_guidelines" ,
147+ label : "Broken Guidelines" ,
148+ description : "Breaks when prompt metadata is read." ,
149+ get promptGuidelines ( ) : string [ ] {
150+ throw new Error ( "boom" ) ;
151+ } ,
152+ parameters : Type . Object ( { } ) ,
153+ execute : async ( ) => ( {
154+ content : [ { type : "text" , text : "bad" } ] ,
155+ details : { } ,
156+ } ) ,
157+ } as unknown as ToolDefinition ;
158+ const unreadableParametersTool = {
159+ name : "bad_parameters" ,
160+ label : "Broken Parameters" ,
161+ description : "Breaks when schema is read." ,
162+ get parameters ( ) : ToolDefinition [ "parameters" ] {
163+ throw new Error ( "boom" ) ;
164+ } ,
165+ execute : async ( ) => ( {
166+ content : [ { type : "text" , text : "bad" } ] ,
167+ details : { } ,
168+ } ) ,
169+ } as unknown as ToolDefinition ;
170+
171+ const { session } = await createAgentSession ( {
172+ model : testModel ,
173+ noTools : "builtin" ,
174+ customTools : [
175+ unreadableNameTool ,
176+ unreadableGuidelinesTool ,
177+ healthyTool ,
178+ unreadableParametersTool ,
179+ ] ,
180+ resourceLoader : createEmptyResourceLoader ( ) ,
181+ sessionManager : SessionManager . inMemory ( ) ,
182+ settingsManager : SettingsManager . inMemory ( ) ,
183+ modelRegistry : ModelRegistry . inMemory ( AuthStorage . inMemory ( ) ) ,
184+ } ) ;
185+
186+ expect ( session . getActiveToolNames ( ) ) . toEqual ( [ "healthy_lookup" ] ) ;
187+ expect ( session . getAllTools ( ) . map ( ( tool ) => tool . name ) ) . toEqual ( [ "healthy_lookup" ] ) ;
188+ } ) ;
189+
190+ it ( "preserves the original custom tool receiver after snapshotting" , async ( ) => {
191+ const statefulTool = {
192+ name : "stateful_lookup" ,
193+ label : "Stateful Lookup" ,
194+ description : "Uses state from the tool object." ,
195+ parameters : Type . Object ( { } ) ,
196+ calls : 0 ,
197+ async execute ( ) {
198+ this . calls += 1 ;
199+ return {
200+ content : [ { type : "text" as const , text : String ( this . calls ) } ] ,
201+ details : { } ,
202+ } ;
203+ } ,
204+ } as ToolDefinition & { calls : number } ;
205+
206+ const { session } = await createAgentSession ( {
207+ model : testModel ,
208+ noTools : "builtin" ,
209+ customTools : [ statefulTool ] ,
210+ resourceLoader : createEmptyResourceLoader ( ) ,
211+ sessionManager : SessionManager . inMemory ( ) ,
212+ settingsManager : SettingsManager . inMemory ( ) ,
213+ modelRegistry : ModelRegistry . inMemory ( AuthStorage . inMemory ( ) ) ,
214+ } ) ;
215+
216+ const definition = session . getToolDefinition ( "stateful_lookup" ) ;
217+ const result = await definition ?. execute (
218+ "call-1" ,
219+ { } ,
220+ undefined ,
221+ undefined ,
222+ undefined as unknown as Parameters < ToolDefinition [ "execute" ] > [ 4 ] ,
223+ ) ;
224+
225+ expect ( result ?. content ) . toEqual ( [ { type : "text" , text : "1" } ] ) ;
226+ expect ( statefulTool . calls ) . toBe ( 1 ) ;
227+ } ) ;
228+
120229 it ( "preserves an exact base system prompt when active tools change" , async ( ) => {
121230 const customTool : ToolDefinition = {
122231 name : "custom_lookup" ,
0 commit comments